Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 28 additions & 23 deletions openssh/openssh_installer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,22 @@
#########################################################################
# OpenSSH Hardened Configuration Installer
#
# Installs OpenSSH and applies a maximally hardened configuration.
# Designed for modern systems where password authentication over SSH
# is considered obsolete and insecure.
# Ed25519-only · No password auth · Post-quantum hardened
#
# Philosophy:
# SSH keys are the only acceptable authentication method for remote
# access. Passwords belong exclusively in sudo as a second layer,
# never as SSH authentication.
#
# Recommendation: store your SSH private keys in Bitwarden (SSH Agent
# feature) or another password manager. This gives you:
# - Encrypted key storage
# - Cross-device key sync
# - Audit log of key usage
# - Easy revocation
# feature) or another password manager.
#
# External access: PKI auth only, FUTURE crypto policy (Fedora/RHEL)
# Internal access: PKI auth only, sudo for privilege escalation
#
# OpenSSH official website: https://www.openssh.com/
# Crypto policy:
# This script does not require or enforce Fedora/RHEL FUTURE crypto
# policy. It independently applies strong, post-quantum-aware settings
# that align with FUTURE in spirit — Ed25519, curve25519, AES-256,
# SHA-2 — while adding ML-KEM (Kyber) key exchange to mitigate
# store-now-decrypt-later attacks. No FUTURE policy activation needed.
#########################################################################

set -euo pipefail
Expand Down Expand Up @@ -71,7 +67,7 @@ print_header() {
echo
echo -e "${BOLD}OpenSSH Hardened Configuration Installer${NC}"
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "Ed25519-only · No password auth · FUTURE crypto policy compatible"
echo -e "Ed25519-only · No password auth · Post-quantum hardened"
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo
}
Expand Down Expand Up @@ -139,7 +135,7 @@ configure_ssh() {
cat > "$tmp_config" << 'EOF'
# =============================================================================
# Hardened OpenSSH Server Configuration
# Ed25519-only · No password auth · FUTURE crypto policy compatible
# Ed25519-only · No password auth · Post-quantum hardened
#
# CVE mitigations:
# CVE-2023-51767 — Ed25519 only (no RSA)
Expand All @@ -158,8 +154,12 @@ configure_ssh() {
# Use passwords only for sudo (local privilege escalation), never for
# SSH authentication itself.
#
# External access: PKI auth only, FUTURE crypto policy (Fedora/RHEL)
# Internal access: PKI auth only, sudo as the second layer
# Crypto policy:
# This script does not require or enforce Fedora/RHEL FUTURE crypto
# policy. It independently applies strong, post-quantum-aware settings
# that align with FUTURE in spirit — Ed25519, curve25519, AES-256,
# SHA-2 — while adding ML-KEM (Kyber) key exchange to mitigate
# store-now-decrypt-later attacks. No FUTURE policy activation needed.
# =============================================================================

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -221,11 +221,16 @@ ClientAliveCountMax 2
TCPKeepAlive no

# -----------------------------------------------------------------------------
# Cryptographic Algorithms — FUTURE policy compatible
# Ed25519 + curve25519 + AES-256 + SHA-256+ only
# Cryptographic Algorithms — Post-quantum hardened
#
# Goal: mitigate store-now-decrypt-later (SNDL) attacks by adding a
# post-quantum key exchange (ML-KEM / FIPS 203) alongside classical
# curve25519. This does not require FUTURE crypto policy to be active.
#
# Ed25519 + ML-KEM + curve25519 + AES-256 + SHA-2 only
# No RSA, no ECDSA, no SHA-1, no AES-128
# -----------------------------------------------------------------------------
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
Comment on lines +233 to 234

Copilot AI Mar 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding KexAlgorithms to include mlkem768x25519-sha256 will make sshd -t fail on systems where the distro-provided OpenSSH does not yet support ML-KEM (this repo installs from distribution repositories). Consider detecting KEX support (e.g., via ssh -Q kex / sshd -T equivalents) and conditionally including ML-KEM with a safe fallback list, or failing early with a clear message about the minimum required OpenSSH version.

Copilot uses AI. Check for mistakes.
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com
HostKeyAlgorithms ssh-ed25519
Expand Down Expand Up @@ -317,15 +322,16 @@ test_configuration() {

show_summary() {
local ssh_version
ssh_version=$(sshd -V 2>&1 | grep -o 'OpenSSH_[^ ]*' || echo "unknown")
ssh_version=$(ssh -V 2>&1 | awk '{print $1}' | tr -d ',')

Comment on lines 323 to 326

Copilot AI Mar 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show_summary() uses ssh -V to derive the version. This script only installs openssh-server, and on some distros the SSH client binary may not be present, causing the install flow to abort (due to set -e) right at the end. Prefer reading the version from sshd -V (or guard with command -v ssh and fall back) so the summary cannot break an otherwise successful install.

Copilot uses AI. Check for mistakes.
echo
echo -e "${BOLD}Summary${NC}"
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${GREEN}✓${NC} $ssh_version installed"
echo -e "${GREEN}✓${NC} Ed25519-only host key"
echo -e "${GREEN}✓${NC} Password authentication disabled"
echo -e "${GREEN}✓${NC} FUTURE crypto policy compatible"
echo -e "${GREEN}✓${NC} Post-quantum KEX (ML-KEM / mlkem768x25519)"
echo -e "${GREEN}✓${NC} Aligned with FUTURE crypto policy (not required)"
echo -e "${GREEN}✓${NC} All forwarding disabled"
echo -e "${GREEN}✓${NC} CVE mitigations applied"
systemctl is-active --quiet "$SSH_SERVICE" \
Expand All @@ -345,7 +351,6 @@ show_summary() {
echo -e "1. Add your public key: ${BLUE}ssh-copy-id user@host${NC}"
echo -e "2. Test login: ${BLUE}ssh user@${ip_hint}${NC}"
echo -e "3. Store key in: ${BLUE}Bitwarden SSH Agent${NC}"
echo -e "4. On Fedora/RHEL: ${BLUE}sudo update-crypto-policies --set FUTURE${NC}"
echo
echo -e "${YELLOW}Emergency password access:${NC}"
echo -e "Uncomment ${BLUE}PasswordAuthentication yes${NC} in $CONFIG_FILE"
Expand Down Expand Up @@ -422,7 +427,7 @@ verify() {
local issues=0

command -v sshd &>/dev/null \
&& log_success "sshd found: $(sshd -V 2>&1 | grep -o 'OpenSSH_[^ ]*')" \
&& log_success "sshd found: $ssh_version=$(ssh -V 2>&1 | awk '{print $1}' | tr -d ',')" \
|| { log_error "sshd not found"; ((issues++)); }
Comment on lines 429 to 431

Copilot AI Mar 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

verify() references $ssh_version inside the log string, but that variable is never set in this function. With set -u, this will cause an immediate unbound variable error and make verify unusable. Compute the version into a local variable first (or reuse sshd -V) and then log it without referencing an unset variable.

Copilot uses AI. Check for mistakes.

[ -f "$CONFIG_FILE" ] && sshd -t 2>/dev/null \
Expand Down
Loading