#!/bin/sh # =========================================================================== # Broker-only sshd entrypoint for the OSM taxiway bastion. # =========================================================================== # Minimal, security-focused: key-only SSH for one non-root user whose every # session is forced through bastion-broker (client command validated whole-line # against the allowlist, then exec'd shell-free). No shell, no forwarding, no # root login. Host keys persist under the mounted /etc/ssh/keys. # =========================================================================== set -eu SSH_USER=agent KEYS_DIR=/etc/ssh/keys USERS_D=/etc/bastion/users.d ALLOW=/etc/bastion/allowed-commands.list # 1) Persistent host identity (bind-mounted dir → survives rebuilds). mkdir -p "$KEYS_DIR" for t in rsa ecdsa ed25519; do f="$KEYS_DIR/ssh_host_${t}_key" [ -f "$f" ] || ssh-keygen -t "$t" -f "$f" -N "" -q done chmod 600 "$KEYS_DIR"/ssh_host_* 2>/dev/null || true # 2) authorized_keys from the mounted users.d/*.pub (one client identity per file). home=$(getent passwd "$SSH_USER" | cut -d: -f6) mkdir -p "$home/.ssh" : > "$home/.ssh/authorized_keys" if [ -d "$USERS_D" ]; then cat "$USERS_D"/*.pub >> "$home/.ssh/authorized_keys" 2>/dev/null || true fi chown -R "$SSH_USER:$SSH_USER" "$home/.ssh" chmod 700 "$home/.ssh" chmod 600 "$home/.ssh/authorized_keys" # The broker reads this live every request; make sure it exists (empty ⇒ deny all). [ -f "$ALLOW" ] || { mkdir -p /etc/bastion; : > "$ALLOW"; } # 3) ForceCommand wrapper → hand the client's requested command to the broker. cat > /usr/local/bin/force-command <<'EOF' #!/bin/sh exec /usr/local/bin/bastion-broker "${SSH_ORIGINAL_COMMAND:-}" EOF chmod 0755 /usr/local/bin/force-command # 4) sshd config — key-only, single user, forced through the broker, no forwarding. cat > /etc/ssh/sshd_config <