# =========================================================================== # docker-bastion — hardened sshd config # # Every authenticated session is routed through /etc/bastion/force-command, # which is generated at container start. In FORCE_COMMAND mode it runs the # fixed command; in broker mode it hands SSH_ORIGINAL_COMMAND to # bastion-broker, which runs it only if it matches the regex allowlist. # (The bastion user's shell is /bin/sh, not nologin — sshd invokes the # ForceCommand as `shell -c ""`, so nologin would break it. Security # comes from ForceCommand + this config, not from the login shell.) # =========================================================================== Port 22 AddressFamily any ListenAddress 0.0.0.0 ListenAddress :: # Host keys live in /etc/ssh/keys/ so they can survive image rebuilds via # a named volume. start-container generates them on first boot if missing. HostKey /etc/ssh/keys/ssh_host_ed25519_key HostKey /etc/ssh/keys/ssh_host_rsa_key # Privilege separation directory (Alpine default is /var/empty). StrictModes yes # Auth — public keys only, no passwords, no interactive prompts. # (UsePAM is omitted: Alpine's openssh-server is built without PAM support # and rejects the directive entirely. Without PAM compiled in, the no-PAM # behavior is already the default — nothing to disable.) PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no PubkeyAuthentication yes # Two key sources sshd consults on every auth attempt: # 1. The boot-time merged file at /home/%u/.ssh/authorized_keys — # populated from $AUTHORIZED_KEYS_HOST / $AUTHORIZED_KEYS_REPO file # mounts. Static after container start. # 2. AuthorizedKeysCommand /usr/local/bin/bastion-list-keys — # enumerates *.pub files in $AUTHORIZED_KEYS_DIR (default # /etc/bastion/users.d). Runs on every login, so adding or removing # a pubkey file takes effect immediately without a container restart. AuthorizedKeysFile /home/%u/.ssh/authorized_keys AuthorizedKeysCommand /usr/local/bin/bastion-list-keys AuthorizedKeysCommandUser agent # Surface reduction — no forwarding, no tunnels, no user env / rc files. AllowAgentForwarding no AllowTcpForwarding no X11Forwarding no GatewayPorts no PermitTunnel no PermitUserEnvironment no PermitUserRC no # Logging. LogLevel VERBOSE SyslogFacility AUTH # Belt + suspenders: applies even if per-key command="" is missing. ForceCommand /etc/bastion/force-command