Ssh_hardening
Chapter 32: SSH Hardening and Key Management - Deep Dive
Section titled “Chapter 32: SSH Hardening and Key Management - Deep Dive”Mastering SSH Security for Production Environments
Section titled “Mastering SSH Security for Production Environments”32.1 Understanding SSH Protocol
Section titled “32.1 Understanding SSH Protocol”SSH Protocol Architecture
Section titled “SSH Protocol Architecture” SSH Protocol Layers+------------------------------------------------------------------+| || SSH Application Layer || +-------------------------------------------------------------+ || | sftp, scp, ssh-add, ssh-keygen, ssh-agent | || +-------------------------------------------------------------+ || | || v || SSH Connection Protocol || +-------------------------------------------------------------+ || | - Channel management | || | - Session multiplexing | || | - X11 forwarding | || | - Agent forwarding | || | - TCP forwarding | || +-------------------------------------------------------------+ || | || v || SSH Authentication Protocol || +-------------------------------------------------------------+ || | - publickey (RSA, ECDSA, Ed25519) | || | - password | || | - keyboard-interactive | || | - hostbased | || +-------------------------------------------------------------+ || | || v || SSH Transport Layer Protocol || +-------------------------------------------------------------+ || | - Server authentication | || | - Key exchange (DH, ECDH) | || | - Encryption (AES, ChaCha20) | || | - MAC (HMAC, Poly1305) | || | - Compression (zlib) | || +-------------------------------------------------------------+ || | || v || TCP/IP Layer || |+------------------------------------------------------------------+SSH Protocol Versions
Section titled “SSH Protocol Versions” SSH Protocol Comparison+------------------------------------------------------------------+| || SSH Version 1 || +----------------------------------------------------------+ || | - Deprecated due to security vulnerabilities | || | - Single encryption tunnel | || | - Vulnerable to man-in-the-middle attacks | || | - No integrity checking for channels | || | - Still exists on some legacy systems | || +----------------------------------------------------------+ || || SSH Version 2 || +----------------------------------------------------------+ || | - Current standard (RFC 4251-4256) | || | - Multiple encryption channels | || | - Strong key exchange algorithms | || | - Better integrity checking (MAC) | || | - Modular design | || | - Extension support | || +----------------------------------------------------------+ || || Key Differences: || +----------------------------------------------------------+ || | Feature | SSHv1 | SSHv2 | || | ---------------|------------|----------------------------| || | Encryption | Single | Multiple channels | || | Key Exchange | Fixed | Modular (diffie-hellman) | || | Integrity | Weak | HMAC | || | Security | Weak | Strong | || +----------------------------------------------------------+ || |+------------------------------------------------------------------+32.2 SSH Hardening Strategies
Section titled “32.2 SSH Hardening Strategies”Comprehensive sshd_config
Section titled “Comprehensive sshd_config”# /etc/ssh/sshd_config - Production Hardened Configuration
# =============================================================================# SSH PROTOCOL SETTINGS# =============================================================================
# Use only SSH Protocol 2 (mandatory for security)Protocol 2
# Listen on specific interfaces (reduce attack surface)ListenAddress 0.0.0.0ListenAddress ::
# =============================================================================# AUTHENTICATION SETTINGS# =============================================================================
# Disable root login (critical security measure)PermitRootLogin no
# Disable empty passwordsPermitEmptyPasswords no
# Disable password authentication (use keys only)PasswordAuthentication noPermitUserEnvironment noChallengeResponseAuthentication no
# Maximum authentication attemptsMaxAuthTries 3MaxSessions 10
# Login grace timeLoginGraceTime 30
# Strict modes - check file permissionsStrictModes yes
# Allow specific users/groups (whitelist approach)AllowUsers admin deployuser automation# AllowGroups sudo developers
# =============================================================================# KEY/BANNER SETTINGS# =============================================================================
# Login bannerBanner /etc/ssh/banner
# Public key authenticationPubkeyAuthentication yes
# AuthorizedKeysFile locationAuthorizedKeysFile .ssh/authorized_keys
# =============================================================================# SESSION SETTINGS# =============================================================================
# Client alive settings (detect disconnected clients)ClientAliveInterval 300ClientAliveCountMax 2
# Session timeout# Idle timeout (set in client)# Add to client config: ServerAliveInterval 300
# =============================================================================# FORWARDING SETTINGS# =============================================================================
# Disable all forwarding (if not needed)# Disable X11 forwarding (security risk)X11Forwarding no
# Disable agent forwardingAllowAgentForwarding no
# Disable TCP forwardingAllowTcpForwarding no
# Disable tunnel forwarding# PermitTunnel no
# =============================================================================# ENCRYPTION AND HASHING# =============================================================================
# Ciphers (order matters - put strongest first)Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# MAC (Message Authentication Codes)MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
# Key exchange algorithmsKexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256
# =============================================================================# HOSTKEY SETTINGS# =============================================================================
# HostKeys for protocol 2HostKey /etc/ssh/ssh_host_rsa_keyHostKey /etc/ssh/ssh_host_ecdsa_keyHostKey /etc/ssh/ssh_host_ed25519_key
# Use privileged port (security)# HostKey /etc/ssh/ssh_host_key (SSHv1 - disable)
# =============================================================================# SUBSYSTEMS# =============================================================================
Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO
# =============================================================================# ACCESS CONTROL# =============================================================================
# Deny certain users# DenyUsers baduser
# Kerberos optionsKerberosAuthentication noKerberosOrLocalPasswd yesKerberosTicketCleanup yes
# GSSAPI optionsGSSAPIAuthentication noGSSAPICleanupCredentials yes
# =============================================================================# LOGGING# =============================================================================
# Log levelLogLevel VERBOSE
# =============================================================================# ENVIRONMENT# =============================================================================
# Accept environment variables from client (disable for security)AcceptEnv LANG LC_*
# =============================================================================# PAM SETTINGS# =============================================================================
UsePAM yes
# =============================================================================# OTHER SETTINGS# =============================================================================
# Print last login infoPrintLastLog yes
# Print MOTDPrintMotd no
# Handle deprecated options# IgnoreRhosts yes# RhostsRSAAuthentication no# HostbasedAuthentication no
# Allow shared connections# ControlMaster auto# ControlPath /tmp/ssh_mux_%h_%p# ControlPersist 4hSSH Banner
Section titled “SSH Banner”+------------------------------------------------------------------+| || AUTHORIZED ACCESS ONLY || || If you are not authorized to access or use this system, || disconnect immediately. || || All connections are logged and monitored. || Unauthorized access is prohibited and will be prosecuted. || || By using this system, you consent to these terms. || |+------------------------------------------------------------------+32.3 SSH Key Management
Section titled “32.3 SSH Key Management”Understanding SSH Key Types
Section titled “Understanding SSH Key Types” SSH Key Types Comparison+------------------------------------------------------------------+| || RSA (Rivest-Shamir-Adleman) || +----------------------------------------------------------+ || | Key Sizes: 1024, 2048, 3072, 4096 bits | || | Compatibility: Excellent (all SSH clients) | || | Security: Good (2048+ bits recommended) | || | Performance: Slower than Ed25519 | || | Use Case: Legacy systems, compatibility | || +----------------------------------------------------------+ || || ECDSA (Elliptic Curve DSA) || +----------------------------------------------------------+ || | Key Sizes: 256, 384, 521 bits | || | Compatibility: Good (modern clients) | || | Security: Good (depends on curve) | || | Performance: Faster than RSA | || | Use Case: Balanced performance/security | || | Concerns: NIST curves (potential backdoor concerns) | || +----------------------------------------------------------+ || || Ed25519 (Edwards-curve DSA) || +----------------------------------------------------------+ || | Key Size: 256 bits (fixed) | || | Compatibility: Very Good (modern clients) | || | Security: Excellent (modern, well-reviewed) | || | Performance: Fastest | || | Key Size: Smallest (37 bytes public, 64 bytes priv) | || | Use Case: RECOMMENDED for new deployments | || +----------------------------------------------------------+ || || Ed448 (Edwards-curve DSA) || +----------------------------------------------------------+ || | Key Size: 448 bits (fixed) | || | Compatibility: Limited (newer) | || | Security: Highest (largest key) | || | Performance: Very fast | || | Use Case: Maximum security requirements | || +----------------------------------------------------------+ || |+------------------------------------------------------------------+Key Generation Best Practices
Section titled “Key Generation Best Practices”# =============================================================================# ED25519 KEY (RECOMMENDED)# =============================================================================
# Generate Ed25519 key with commentssh-keygen -t ed25519 -C "work@company.com - Production"
# Ed25519 with custom filenamessh-keygen -t ed25519 -f ~/.ssh/id_ed25519_production -C "production-server"
# Ed25519 with passphrase (REQUIRED for production)ssh-keygen -t ed25519 -C "production" -a 100# -a rounds: Key derivation function iterations (more = slower but secure)
# =============================================================================# RSA KEY (FOR LEGACY COMPATIBILITY)# =============================================================================
# RSA 4096-bit keyssh-keygen -t rsa -b 4096 -C "legacy@company.com"
# RSA with more KDF rounds (slower but secure)ssh-keygen -t rsa -b 4096 -a 100 -C "production"
# =============================================================================# ED448 KEY (MAXIMUM SECURITY)# =============================================================================
ssh-keygen -t ed448 -C "maximum-security"
# =============================================================================# VIEW KEY DETAILS# =============================================================================
# View public keycat ~/.ssh/id_ed25519.pub
# View key fingerprintssh-keygen -lf ~/.ssh/id_ed25519.pub
# View key fingerprint (MD5 - useful for comparing)ssh-keygen -lf ~/.ssh/id_ed25519.pub -E md5
# View key commentsssh-keygen -y -f ~/.ssh/id_ed25519
# =============================================================================# KEY MANAGEMENT# =============================================================================
# Change passphrasessh-keygen -p -f ~/.ssh/id_ed25519
# Change commentssh-keygen -c -f ~/.ssh/id_ed25519 -C "new-comment"
# Generate public key from private keyssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pubDeploying SSH Keys
Section titled “Deploying SSH Keys”# =============================================================================# METHOD 1: ssh-copy-id (Simplest)# =============================================================================
# Standard copyssh-copy-id user@server
# Copy specific keyssh-copy-id -i ~/.ssh/id_ed25519_production.pub user@server
# =============================================================================# METHOD 2: Manual Copy# =============================================================================
# Create .ssh directory and set permissionsssh user@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
# Copy public keycat ~/.ssh/id_ed25519.pub | ssh user@server "cat >> ~/.ssh/authorized_keys"
# Set correct permissionsssh user@server "chmod 600 ~/.ssh/authorized_keys && chmod 700 ~/.ssh"
# =============================================================================# METHOD 3: Using Ansible# =============================================================================
ansible all -m authorized_key -a "user=deploy key={{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
# =============================================================================# METHOD 4: SSH Key Deployment (Restricted)# =============================================================================
# Create restricted authorized_keys# Force specific options per key
# Command restriction (user can only run specific commands)command="/usr/local/bin/deploy.sh",no-pty,no-agent-forwarding,no-X11-forwarding ssh-rsa AAAA... user@host
# From specific IP onlyfrom="192.168.1.100" ssh-rsa AAAA... user@host
# Multiple restrictionsfrom="192.168.1.0/24",command="/usr/bin/git-shell" ssh-rsa AAAA... git@host32.4 SSH Agent Management
Section titled “32.4 SSH Agent Management”SSH Agent Security
Section titled “SSH Agent Security” SSH Agent Architecture+------------------------------------------------------------------+| || SSH Agent: In-memory key manager for SSH authentication || || +----------------------------------------------------------+ || | ssh-agent (runs as background process) | || | +------------------------------------------------------+ | || | | - Holds decrypted private keys in memory | | || | | - Communicates with SSH client via socket | | || | | - Keys never written to disk in decrypted form | | || | +------------------------------------------------------+ | || +----------------------------------------------------------+ || || Security Concerns: || +----------------------------------------------------------+ || | 1. Keys in memory can be extracted (cold boot attack) | || | 2. Agent forwarding exposes keys to remote servers | || | 3. Agent can be hijacked if socket is compromised | || | 4. Lock agent when leaving workstation | || +----------------------------------------------------------+ || |+------------------------------------------------------------------+Agent Commands
Section titled “Agent Commands”# =============================================================================# START SSH AGENT# =============================================================================
# Start agent and set environmenteval "$(ssh-agent -s)"
# Or start agent in backgroundssh-agent -s > /tmp/ssh-agent-envsource /tmp/ssh-agent-env
# Check if agent is runningecho $SSH_AUTH_SOCK
# =============================================================================# ADD KEYS TO AGENT# =============================================================================
# Add key with default settingsssh-add
# Add specific keyssh-add ~/.ssh/id_ed25519_production
# Add key with time limit (5 hours)ssh-add -t 18000 ~/.ssh/id_ed25519
# Add with confirmation (macOS)ssh-add -K ~/.ssh/id_ed25519
# =============================================================================# LIST KEYS# =============================================================================
# List all keys in agentssh-add -l
# List with fingerprintsssh-add -l -E md5ssh-add -l -E sha256
# List all (including those not in agent but with keys available)ssh-add -L
# =============================================================================# REMOVE KEYS# =============================================================================
# Remove specific keyssh-add -d ~/.ssh/id_ed25519
# Remove all keysssh-add -D
# Remove keys with timeoutssh-add -t 300 -d ~/.ssh/id_ed25519
# =============================================================================# LOCK/UNLOCK AGENT# =============================================================================
# Lock agent with passwordssh-add -x
# Unlock agentssh-add -X
# =============================================================================# AGENT FORWARDING# =============================================================================
# In SSH config (client)Host remote-server HostName server.example.com ForwardAgent yes
# On command linessh -A user@server
# CAUTION: Agent forwarding allows remote server to use your keys# Only use with trusted servers32.5 SSH Client Configuration
Section titled “32.5 SSH Client Configuration”Client Config Best Practices
Section titled “Client Config Best Practices”# ~/.ssh/config - Production SSH Client Configuration
# =============================================================================# GLOBAL DEFAULTS# =============================================================================
Host * # Security defaults PasswordAuthentication no PubkeyAuthentication yes IdentitiesOnly yes
# Connection settings ServerAliveInterval 60 ServerAliveCountMax 3 TCPKeepAlive yes
# Forwarding ForwardAgent no ForwardX11 no ForwardX11Trusted no
# Security HashKnownHosts yes VerifyHostKeyDNS yes StrictHostKeyChecking ask
# Performance Compression yes ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600
# Logging LogLevel ERROR
# =============================================================================# PRODUCTION SERVERS# =============================================================================
Host prod-* User admin Port 22 IdentityFile ~/.ssh/id_ed25519_production ServerAliveInterval 30 ServerAliveCountMax 5
Host prod-web-1 HostName 192.168.1.10 Host prod-web-*
Host prod-web-2 HostName 192.168.1.11 Host prod-web-*
Host prod-db-1 HostName 192.168.1.20 User dbadmin
# =============================================================================# DEVELOPMENT SERVERS# =============================================================================
Host dev-* User developer Port 22 IdentityFile ~/.ssh/id_ed25519_dev StrictHostKeyChecking no
Host dev-server HostName dev.example.com
# =============================================================================# JUMP HOST / BASTION# =============================================================================
Host bastion HostName bastion.example.com User admin Port 22 IdentityFile ~/.ssh/id_ed25519_bastion ForwardAgent yes
Host internal-server HostName 192.168.1.100 User admin ProxyJump bastion
# Alternative using ProxyCommandHost internal-server-alt HostName 192.168.1.100 User admin ProxyCommand ssh -W %h:%p bastion
# =============================================================================# GITHUB / GIT SERVICES# =============================================================================
Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github IdentitiesOnly yes
Host gitlab.com HostName gitlab.com User git IdentityFile ~/.ssh/id_ed25519_gitlab IdentitiesOnly yes
# =============================================================================# SPECIAL CONNECTIONS# =============================================================================
# High latency connectionsHost overseas-server HostName server.example.com Compression yes Cipher aes256-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com
# =============================================================================# CREATE SOCKET DIRECTORY# =============================================================================
# Run this once:mkdir -p ~/.ssh/socketschmod 700 ~/.ssh/sockets32.6 Fail2Ban Configuration
Section titled “32.6 Fail2Ban Configuration”Fail2Ban Architecture
Section titled “Fail2Ban Architecture” Fail2Ban Architecture+------------------------------------------------------------------+| || +---------------+ || | Log Files | || | (/var/log/) | || +---------------+ || | || v || +---------------+ || | Fail2Ban | || | Server | || +---------------+ || | || +------+------+-------+------+ || | | | | | || v v v v v || +------+------+-------+------+------+ || |Filter|Filter|Filter |Filter |Filter | (Regex patterns) || |sshd |nginx |apache |postfix|mysql | || +------+------+-------+------+------+ || | | | | | || v v v v v || +------+------+-------+------+------+ || |Action|Action|Action |Action |Action | (Ban/Unban actions) || |iptabl|firew |abuse |notify |cloud | || +------+------+-------+------+------+ || |+------------------------------------------------------------------+Comprehensive Fail2Ban Configuration
Section titled “Comprehensive Fail2Ban Configuration”# /etc/fail2ban/jail.local - Production Configuration
[DEFAULT]# Global settingsbantime = 1hfindtime = 10mmaxretry = 5destemail = admin@example.comsender = fail2ban@example.comaction = %(action_mwl)s
# Override action defaultsbanaction = iptables-multiportbanaction_allports = iptables-allports
# =============================================================================# SSH JAIL# =============================================================================
[sshd]enabled = trueport = sshfilter = sshdlogpath = /var/log/auth.logmaxretry = 3bantime = 24hfindtime = 1h
# Using recidive jail for repeat offenders[sshd-ddos]enabled = trueport = sshfilter = sshd-ddoslogpath = /var/log/auth.logmaxretry = 20bantime = 1wfindtime = 1d
# =============================================================================# WEB SERVER JAILS# =============================================================================
[nginx-http-auth]enabled = trueport = http,httpsfilter = nginx-http-authlogpath = /var/log/nginx/error.logmaxretry = 5bantime = 1h
[nginx-noscript]enabled = trueport = http,httpsfilter = nginx-noscriptlogpath = /var/log/nginx/access.logmaxretry = 6bantime = 1h
[nginx-badrequests]enabled = trueport = http,httpsfilter = nginx-badrequestslogpath = /var/log/nginx/access.logmaxretry = 3bantime = 1h
[apache-auth]enabled = trueport = http,httpsfilter = apache-authlogpath = /var/log/apache2/error.logmaxretry = 5
[apache-badbots]enabled = trueport = http,httpsfilter = apache-badbotslogpath = /var/log/apache2/access.logmaxretry = 2
[apache-noscript]enabled = trueport = http,httpsfilter = apache-noscriptlogpath = /var/log/apache2/access.logmaxretry = 6
# =============================================================================# DATABASE JAILS# =============================================================================
[mysqld]enabled = trueport = 3306filter = mysqld-authlogpath = /var/log/mysql/error.logmaxretry = 5bantime = 1h
[postgresql]enabled = trueport = 5432filter = postgresqllogpath = /var/log/postgresql/postgresql.logmaxretry = 5
# =============================================================================# MAIL SERVER JAILS# =============================================================================
[postfix]enabled = trueport = smtp,submission,imapsfilter = postfixlogpath = /var/log/mail.logmaxretry = 5bantime = 1h
[dovecot]enabled = trueport = pop3,pop3s,imap,imapsfilter = dovecotlogpath = /var/log/mail.logmaxretry = 5
# =============================================================================# FTP JAILS# =============================================================================
[vsftpd]enabled = trueport = ftp,ftp-data,ftps,ftps-datafilter = vsftpdlogpath = /var/log/vsftpd.logmaxretry = 5bantime = 1h
# =============================================================================# CUSTOM FILTERS# =============================================================================
# Example: Protect API endpoints[nginx-api]enabled = trueport = http,httpsfilter = nginx-apilogpath = /var/log/nginx/api-access.logmaxretry = 10bantime = 30mfindtime = 1m
# Create /etc/fail2ban/filter.d/nginx-api.conf#[Definition]#failregex = ^<HOST> .* "POST /api/.*" HTTP/1.1" (401|403|500|502|503|504)#ignoreregex =Fail2Ban Management Commands
Section titled “Fail2Ban Management Commands”# =============================================================================# MONITORING# =============================================================================
# Check statussudo fail2ban-client statussudo fail2ban-client status sshd
# View banned IPssudo iptables -L -nsudo fail2ban-client get sshd banned
# View logstail -f /var/log/fail2ban/fail2ban.log
# =============================================================================# BANNING/UNBANNING# =============================================================================
# Ban IP manuallysudo fail2ban-client set sshd banip 192.168.1.100
# Unban IPsudo fail2ban-client set sshd unbanip 192.168.1.100
# Unban allsudo fail2ban-client unban --all
# =============================================================================# TESTING FILTERS# =============================================================================
# Test regex against logfail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# Test with custom logecho "Failed password for invalid user admin from 192.168.1.100" | \ fail2ban-regex /dev/stdin /etc/fail2ban/filter.d/sshd.conf32.7 Exam Tips
Section titled “32.7 Exam Tips”- SSH Protocol: Always use SSHv2 (Protocol 2)
- Key Types: Ed25519 is recommended (fastest, most secure)
- Passphrases: Always use passphrases for production keys
- Root Login: Always disable PermitRootLogin in production
- Password Auth: Disable PasswordAuthentication in production
- Port: Change default port 22 (security through obscurity)
- Fail2Ban: Configure for SSH and web services
- Key Deployment: Use authorized_keys with restrictions
- Agent Forwarding: Use carefully, only with trusted servers
- Client Config: Use ~/.ssh/config for organization
Summary
Section titled “Summary”In this chapter, you learned:
- ✅ SSH protocol architecture (transport, authentication, connection)
- ✅ Comprehensive sshd_config hardening
- ✅ SSH key types (RSA, ECDSA, Ed25519, Ed448)
- ✅ SSH key generation and deployment
- ✅ SSH agent management and security
- ✅ SSH client configuration best practices
- ✅ Fail2Ban architecture and configuration
- ✅ SSH security best practices for production
Next Chapter
Section titled “Next Chapter”Chapter 33: Intrusion Detection and Fail2Ban
Last Updated: February 2026