Split host setup into explicit entity actions

This commit is contained in:
deytenit committed 2026-11-08 12:39:49 +03:00
1 parent a297e7c71e
commit ba9ef92051
51 files changed
+1023 -275

No files matched your search

+143
View File
@@ -0,0 +1,143 @@
"""Apply the image's public-key SSH policy to adam after a verified key login."""
import ipaddress
import json
import os
import pwd
import re
from pathlib import Path
from engine.descriptor import Meta
METADATA = Meta(summary="Require SSH public-key authentication for adam from an independent administrator or verified adam key session.")
CONFIG = "/etc/ssh/sshd_config"
POLICY = """
# APEX operator SSH policy
Match User adam
AuthenticationMethods publickey
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
X11Forwarding no
"""
def _ancestors():
ancestors = {}
pid = os.getppid()
ticks = os.sysconf("SC_CLK_TCK")
while pid > 1:
# comm can contain spaces and parentheses; the remaining fields start at state.
fields = Path(f"/proc/{pid}/stat").read_text().rsplit(")", 1)[1].split()
ancestors[pid] = int(fields[19]) * 1_000_000 // ticks
pid = int(fields[1])
return ancestors
def _connection(ctx):
if pwd.getpwuid(os.getuid()).pw_name != "adam":
raise RuntimeError("Run config/hardening inside an SSH public-key session as adam.")
ancestors = _ancestors()
sockets = ctx.sys.sudo(["ss", "-Hntp", "state", "established"], capture=True).stdout
connections = set()
for line in sockets.splitlines():
fields = line.split(None, 4)
if len(fields) == 5 and any(int(pid) in ancestors for pid in
re.findall(r'"sshd(?:-session)?",pid=(\d+),', fields[4])):
connections.add((fields[2], fields[3]))
if len(connections) != 1:
raise RuntimeError("Cannot identify a unique established SSH socket for this process.")
local, peer = connections.pop()
peer, peer_port = peer.rsplit(":", 1)
local, local_port = local.rsplit(":", 1)
def address(value):
ip = ipaddress.ip_address(value.strip("[]"))
return str(getattr(ip, "ipv4_mapped", None) or ip)
peer, local = address(peer), address(local)
record = rf"^Accepted publickey for adam from {re.escape(peer)} port {int(peer_port)} ssh2:"
result = ctx.sys.sudo(["journalctl", "-b", "_UID=0", "_EXE=/usr/sbin/sshd",
"_EXE=/usr/lib/openssh/sshd-session", "_EXE=/usr/lib/openssh/sshd-auth",
"--no-pager", "-o", "json", "--grep", record], capture=True, check=False)
if not result.returncode:
for line in result.stdout.splitlines():
entry = json.loads(line)
pid = int(entry["_PID"])
if (pid in ancestors and int(entry["__MONOTONIC_TIMESTAMP"]) >= ancestors[pid]
and re.match(record, entry["MESSAGE"])):
ctx.sys.run(["sudo", "-n", "true"])
return f"user=adam,host={peer},addr={peer},laddr={local},lport={int(local_port)}"
raise RuntimeError("Cannot verify public-key login for this SSH process in the root sshd journal.")
def _operator_access(ctx):
account = pwd.getpwnam("adam")
if account.pw_uid < 1000 or account.pw_dir != "/home/adam":
raise RuntimeError("Configure a regular adam operator account first.")
if pwd.getpwuid(os.getuid()).pw_name == "adam":
return _connection(ctx)
loginuid = int(Path("/proc/self/loginuid").read_text())
if loginuid in (account.pw_uid, 4294967295) or loginuid < 0:
raise RuntimeError("Use an independent administrator login or an SSH public-key session as adam.")
if os.getuid() not in (0, loginuid):
raise RuntimeError("Run from the independent administrator's own login.")
ctx.sys.sudo(["true"])
home = Path(account.pw_dir)
authorized = home / ".ssh" / "authorized_keys"
# Inspect as adam so private .ssh directories remain usable from another administrator.
command = ["runuser", "-u", "adam", "--"]
for path in (home, authorized.parent, authorized):
metadata = ctx.sys.sudo([*command, "env", "LC_ALL=C", "stat", "-c", "%u %a %F", "--", str(path)],
capture=True).stdout.strip().split(" ", 2)
owner, mode, kind = metadata
expected = "regular file" if path == authorized else "directory"
if int(owner) not in (0, account.pw_uid) or int(mode, 8) & 0o022 or kind != expected:
raise RuntimeError(f"Unsafe operator SSH path: {path}")
keys = ctx.sys.sudo([*command, "cat", "--", str(authorized)], capture=True).stdout
for key in keys.splitlines():
if key.startswith(("ssh-", "ecdsa-", "sk-")) and ctx.sys.run(
["ssh-keygen", "-lf", "-"], input=key + "\n", capture=True, check=False,
).returncode == 0:
break
else:
raise RuntimeError("Install a valid unrestricted operator public key before applying SSH hardening.")
ctx.sys.sudo([*command, "sudo", "-n", "true"])
connection = "user=adam,host=localhost,addr=127.0.0.1"
paths = _effective(ctx.sys, connection).get("authorizedkeysfile", "").split()
if not {".ssh/authorized_keys", "%h/.ssh/authorized_keys", str(authorized)}.intersection(paths):
raise RuntimeError("sshd does not use the operator's verified authorized_keys file.")
return connection
def _effective(system, connection):
result = system.sudo(["/usr/sbin/sshd", "-T", "-C", connection], capture=True)
return dict(line.split(" ", 1) for line in result.stdout.splitlines() if " " in line)
def run(ctx, args):
connection = _operator_access(ctx)
system = ctx.sys
system.sudo(["/usr/sbin/sshd", "-t"])
effective = _effective(system, connection)
if effective.get("authenticationmethods") not in ("any", "publickey"):
raise RuntimeError("Preserve the existing SSH authentication chain; reconcile it explicitly.")
required = {"authenticationmethods": "publickey", "pubkeyauthentication": "yes",
"passwordauthentication": "no", "kbdinteractiveauthentication": "no",
"permitemptypasswords": "no", "x11forwarding": "no"}
if all(effective.get(key) == value for key, value in required.items()):
return
if Path(CONFIG).is_symlink():
raise RuntimeError(f"Refusing redirected SSH configuration: {CONFIG}")
original = system.sudo(["cat", CONFIG], capture=True).stdout
if "# APEX operator SSH policy" in original:
raise RuntimeError("The managed SSH policy is ineffective; reconcile earlier directives.")
ctx.host.write_file(CONFIG, original + "\n" + POLICY, sudo=True)
try:
system.sudo(["/usr/sbin/sshd", "-t"])
effective = _effective(system, connection)
if any(effective.get(key) != value for key, value in required.items()):
raise RuntimeError("The effective SSH policy differs; inspect existing Match blocks.")
system.reload("ssh")
except BaseException:
ctx.host.write_file(CONFIG, original, backup=False, sudo=True)
system.sudo(["/usr/sbin/sshd", "-t"])
system.reload("ssh")
raise