Enforcing Passphrase-Protected SSH Keys: Secure Alternatives to Passwordless Authentication


2 views

While disabling password-based SSH authentication is a security best practice, allowing passwordless SSH keys creates another vulnerability vector. The ideal configuration requires:

  • Enforcing passphrase protection on all private keys
  • Preventing unauthorized key generation
  • Implementing centralized key management

Option 1: ForceCommand Wrapper Script

Create a script to verify key passphrase protection:

#!/bin/bash
if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
    # Check for agent forwarding
    if [[ -z "$SSH_AUTH_SOCK" ]]; then
        echo "ERROR: No SSH agent detected - passphrase required"
        exit 1
    fi
    
    # Verify loaded keys have passphrases
    ssh-add -l | grep -v "The agent has no identities" > /dev/null || {
        echo "ERROR: No passphrase-protected keys loaded in agent"
        exit 1
    }
    
    exec $SHELL -c "$SSH_ORIGINAL_COMMAND"
else
    exec $SHELL
fi

Then configure in sshd_config:

Match Group developers
    ForceCommand /usr/local/bin/check_passphrase.sh

For enterprise environments, implement SSH certificate authentication:

# Generate CA key (secured offline)
ssh-keygen -t ed25519 -f ssh_ca

# Sign user keys with expiration
ssh-keygen -s ssh_ca -I user@company -n developer -V +52w user_key.pub

# Configure sshd_config
TrustedUserCAKeys /etc/ssh/ca.pub
RevokedKeys /etc/ssh/revoked_keys

Combine these technical controls with policy:

  1. Set restrictive permissions on .ssh directories:
  2. chmod 700 ~/.ssh
    chmod 600 ~/.ssh/authorized_keys
  3. Implement filesystem monitoring:
  4. # Audit rule for new SSH key generation
    -a always,exit -F arch=b64 -S creat -F dir=/home -F uid!=0 -F name=id_*.pub -k ssh_key_gen

For high-security environments, consider:

  • Yubikey PIV integration
  • Smart card authentication
  • Temporary certificate issuance

Example Yubikey configuration:

# Configure PAM module
auth required pam_u2f.so authfile=/etc/u2f_mappings cue

When disabling password-based SSH authentication, many administrators face a dilemma: allowing passwordless SSH keys creates a significant security risk, while completely restricting SSH key usage hampers productivity. The ideal solution lies in enforcing passphrase-protected SSH keys without falling back to weaker authentication methods.

The OpenSSH server provides configuration options to control key authentication. While there's no direct "require passphrase" setting, we can implement workarounds:

# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey

To ensure users generate keys with passphrases, implement organizational policies for key creation:

# Force passphrase during generation
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519

The -a flag increases KDF rounds, making brute-force attacks more difficult.

For enterprises, consider these robust alternatives:

SSH Certificate Authority

Implement an SSH CA to sign user keys with expiration dates:

# CA signs user key (valid for 30 days)
ssh-keygen -s ca_key -I user_identity -n username -V +30d user_key.pub

Commercial SSH Management Tools

  • Teleport (open source & commercial)
  • Hashicorp Boundary
  • Smallstep SSH certificates

This bash script checks for passphrase-protected keys in authorized_keys:

#!/bin/bash
for key in $(cut -d' ' -f2 ~/.ssh/authorized_keys | sort -u); do
    if grep -q "ENCRYPTED" <(ssh-keygen -P "" -y -f <(echo "ssh-rsa $key")); then
        echo "VALID: Key $key has passphrase protection"
    else
        echo "INVALID: Key $key lacks passphrase - removing"
        sed -i "/$key/d" ~/.ssh/authorized_keys
    fi
done

Implement regular audits of SSH keys in your environment:

# Find passwordless private keys
find /home -name "id_*" ! -name "*.pub" -exec ssh-keygen -y -P "" -f {} \; 2>&1 | grep "incorrect passphrase"

For maximum security, combine SSH keys with second factors:

# Google Authenticator PAM setup
auth required pam_google_authenticator.so
auth required pam_sss.so use_first_pass