Ssh_hardening
Chapter 71: SSH Security and Hardening
Section titled “Chapter 71: SSH Security and Hardening”Overview
Section titled “Overview”SSH (Secure Shell) is the primary method for remote Linux administration. Securing SSH is critical for system security. This chapter covers SSH key-based authentication, hardening configurations, jump hosts, and protection against common attacks.
71.1 SSH Key-Based Authentication
Section titled “71.1 SSH Key-Based Authentication”Generating SSH Keys
Section titled “Generating SSH Keys”# Generate ED25519 key (recommended)ssh-keygen -t ed25519 -C "user@hostname"
# Generate RSA key (4096 bit, for compatibility)ssh-keygen -t rsa -b 4096 -C "user@hostname"
# Generate with commentssh-keygen -t ed25519 -C "admin@workstation"
# Different key filenamessh-keygen -t ed25519 -f ~/.ssh/id_ed25519_work
# Add passphrase (highly recommended)# Enter passphrase when promptedCopying Keys to Server
Section titled “Copying Keys to Server”# Method 1: ssh-copy-id (easiest)ssh-copy-id user@serverssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Method 2: Manual# Copy public key to servercat ~/.ssh/id_ed25519.pub# Then add to ~/.ssh/authorized_keys on server
# Method 3: Direct pipecat ~/.ssh/id_ed25519.pub | ssh user@server 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'SSH Agent
Section titled “SSH Agent”# Start SSH agenteval "$(ssh-agent -s)"
# Add key to agentssh-add ~/.ssh/id_ed25519
# List keys in agentssh-add -l
# Add with timeout (security)ssh-add -t 1h ~/.ssh/id_ed25519 # 1 hour timeout
# Add all keysssh-add
# Remove all keysssh-add -D71.2 SSH Configuration
Section titled “71.2 SSH Configuration”Client Configuration
Section titled “Client Configuration”Host server1 HostName server1.example.com User admin Port 22 IdentityFile ~/.ssh/id_ed25519
Host server2 HostName 192.168.1.100 User root Port 2222
Host * # Apply to all hosts AddKeysToAgent yes IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 ServerAliveCountMax 3 StrictHostKeyChecking ask UserKnownHostsFile ~/.ssh/known_hosts
# Jump host configurationHost internal HostName internal.example.com ProxyJump jump.example.com
# Using ProxyJump (modern)Host db-server HostName 192.168.1.50 User dbadmin ProxyJump admin@jump-serverServer Configuration Hardening
Section titled “Server Configuration Hardening”# Disable root loginPermitRootLogin no
# Disable password authenticationPasswordAuthentication noPermitEmptyPasswords no
# Use only strong ciphersCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
# Key exchangeKexAlgorithms curve25519-sha256,ecdh-sha2-nistp256
# MAC selectionMACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Disable unused authentication methodsHostbasedAuthentication noPubkeyAuthentication yesKerberosAuthentication noGSSAPIAuthentication no
# Session settingsClientAliveInterval 300ClientAliveCountMax 2LoginGraceTime 30MaxAuthTries 3MaxSessions 10
# BannerBanner /etc/ssh/banner
# Allow specific users/groupsAllowUsers admin deploy automationAllowGroups sshusers
# Disable protocol 1Protocol 2
# X11 forwardingX11Forwarding no
# Agent forwarding (use with caution)AllowAgentForwarding nosshd_config Best Practices
Section titled “sshd_config Best Practices”# Always use Protocol 2Protocol 2
# Set strong key bitsHostKey /etc/ssh/ssh_host_rsa_keyHostKey /etc/ssh/ssh_host_ed25519_keyHostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# LoggingLogLevel VERBOSE
# SubsystemSubsystem sftp /usr/lib/ssh/ssh-sftp-server
# Chroot directory for SFTP# (see SFTP section)71.3 Protecting Against Brute Force
Section titled “71.3 Protecting Against Brute Force”fail2ban Installation and Configuration
Section titled “fail2ban Installation and Configuration”# Install fail2bansudo pacman -S fail2ban
# Create local configurationsudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# /etc/fail2ban/jail.local[DEFAULT]bantime = 1hfindtime = 10mmaxretry = 5destemail = admin@example.comsender = fail2ban@example.comaction = %(action_mwl)s
[sshd]enabled = trueport = sshfilter = sshdlogpath = /var/log/auth.logmaxretry = 3bantime = 24hfirewalld for SSH Protection
Section titled “firewalld for SSH Protection”# Rate limiting with firewalldsudo firewall-cmd --permanent --add-service=sshsudo firewall-cmd --permanent --add-rich-rule='rule service name="ssh" accept limit value="3/m"'sudo firewall-cmd --reload
# Allow only specific IPssudo firewall-cmd --permanent --remove-service=sshsudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'iptables Rate Limiting
Section titled “iptables Rate Limiting”# Rate limit SSH connectionsiptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --setiptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
# Allow SSH from specific IP onlyiptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPTiptables -A INPUT -p tcp --dport 22 -j DROP71.4 SSH Certificates
Section titled “71.4 SSH Certificates”Setting Up SSH CA
Section titled “Setting Up SSH CA”# On CA server (your laptop), generate CA keyssh-keygen -t ed25519 -C "ca@home"
# Configure SSH to use CA# ~/.ssh/configHost * TrustedUserCAKeys ~/.ssh/ca.pub
# On servers, add CA to authorized_keys# /etc/ssh/sshd_configTrustedUserCAKeys /etc/ssh/ca.pub
# Sign user keyssh-keygen -s ~/.ssh/ca -I "user@workstation" -n deploy,automation -V +52w ~/.ssh/id_ed25519.pub
# User can now SSH to any server with that principal# No need to copy keys to each server71.5 Jump Hosts and Bastion
Section titled “71.5 Jump Hosts and Bastion”Setting Up Jump Host
Section titled “Setting Up Jump Host”# Architecture:# Client -> Jump Host (Bastion) -> Internal Network
# sshd_config on jump host# Allow only key-based authPasswordAuthentication no
# SSH config for jump hostHost internal-server HostName 10.0.1.50 User admin ProxyJump admin@jump.example.com
# Or using ProxyCommand (older method)Host internal-server HostName 10.0.1.50 User admin ProxyCommand ssh -W %h:%p admin@jump.example.comAWS SSM Session Manager Alternative
Section titled “AWS SSM Session Manager Alternative”# Install Session Manager plugin# For Linux:curl -Lo /tmp/session-manager-plugin.rpm https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpmsudo rpm -i /tmp/session-manager-plugin.rpm
# Connect to instance (without SSH)aws ssm start-session --target i-1234567890abcdef0
# SSH through Session Managerssh -i key.pem admin@i-1234567890abcdef071.6 Port Forwarding and Tunneling
Section titled “71.6 Port Forwarding and Tunneling”Local Port Forwarding
Section titled “Local Port Forwarding”# Access internal service through SSH tunnel# Local:8080 -> SSH Server -> Remote:80
ssh -L 8080:localhost:80 user@serverssh -L 8080:internal-web:80 user@jump-server
# Example: Access internal databasessh -L 5432:localhost:5432 user@db-server# Now connect to localhost:5432 to reach db-server:5432Dynamic Port Forwarding (SOCKS Proxy)
Section titled “Dynamic Port Forwarding (SOCKS Proxy)”# Create SOCKS proxy on local port 1080ssh -D 1080 user@server
# Configure browser to use SOCKS5 proxy localhost:1080# All traffic through SSH tunnelRemote Port Forwarding
Section titled “Remote Port Forwarding”# Allow external access to internal service# Remote:8080 -> SSH -> Local:80
ssh -R 8080:localhost:80 user@public-server
# Expose local web server to internetssh -R 80:localhost:80 -R 443:localhost:443 user@public-server71.7 SFTP Configuration
Section titled “71.7 SFTP Configuration”Secure SFTP Setup
Section titled “Secure SFTP Setup”# /etc/ssh/sshd_config with SFTP onlySubsystem sftp internal-sftp
Match Group sftponly ChrootDirectory /home/%u AllowTcpForwarding no X11Forwarding no ForceCommand internal-sftp
# Create SFTP-only usersudo groupadd sftponlysudo useradd -m -g sftponly -s /usr/bin/sftp-server sftpusersudo passwd sftpuser
# Set directory permissionssudo chown root:root /home/sftpusersudo chmod 755 /home/sftpusersudo mkdir /home/sftpuser/uploadssudo chown sftpuser:sftponly /home/sftpuser/uploads71.8 SSH Troubleshooting
Section titled “71.8 SSH Troubleshooting”Common Issues
Section titled “Common Issues”# Connection refused# Check service: sudo systemctl status sshd# Check firewall: sudo firewall-cmd --list-all
# Permission denied (publickey)# Check key in authorized_keys# Check permissions:chmod 700 ~/.sshchmod 600 ~/.ssh/authorized_keyschmod 600 ~/.ssh/id_rsa
# Too many authentication failures# Add to config: MaxAuthTries 50 or use IdentitiesOnly yes
# Host key changed# Remove old key: ssh-keygen -R hostname# Or edit ~/.ssh/known_hosts
# Key not accepted# Check SELinux: restorecon -Rv ~/.ssh# Check home directory permissionsDebug Connection
Section titled “Debug Connection”# Verbose outputssh -v user@serverssh -vv user@server # More verbosessh -vvv user@server # Most verbose
# Test authenticationssh -v -o PreferredAuthentications=publickey user@server71.9 SSH Security Best Practices
Section titled “71.9 SSH Security Best Practices”Checklist
Section titled “Checklist”# 1. Use key-based authentication (disable passwords)PasswordAuthentication no
# 2. Disable root loginPermitRootLogin no
# 3. Change default portPort 2222
# 4. Use strong ciphersCiphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
# 5. Implement fail2ban
# 6. Use firewall to limit access# Only allow specific IPs
# 7. Keep SSH updatedsudo pacman -Syu openssh
# 8. Use SSH certificates for large deployments
# 9. Monitor auth logstail -f /var/log/auth.log | grep sshd
# 10. Use jump hosts for internal access
# 11. Rotate keys regularly# Generate new keys annually
# 12. Use two-factor authentication# Google Authenticator or DuoTwo-Factor Authentication
Section titled “Two-Factor Authentication”# Install google-authenticatorsudo pacman -S google-authenticator
# Configure usergoogle-authenticator
# Add to sshd# /etc/pam.d/sshdauth required pam_google_authenticator.so
# /etc/ssh/sshd_configChallengeResponseAuthentication yesAuthenticationMethods password,keyboard-interactive71.10 Practical SSH Scripts
Section titled “71.10 Practical SSH Scripts”SSH Connection Script
Section titled “SSH Connection Script”#!/bin/bash# Add key to agent if not alreadyif ! ssh-add -l > /dev/null 2>&1; then ssh-addfi
# Connect to serverserver=$1shift
ssh -o "ServerAliveInterval=60" \ -o "ServerAliveCountMax=3" \ "$server" "$@"SSH Key Management Script
Section titled “SSH Key Management Script”#!/bin/bashKEY_DIR="$HOME/.ssh"DAYS_OLD=90
rotate_keys() { local key_type=$1 local key_name="id_${key_type}"
# Backup old key if [ -f "$KEY_DIR/$key_name" ]; then mv "$KEY_DIR/$key_name" "$KEY_DIR/${key_name}.old" mv "$KEY_DIR/${key_name}.pub" "$KEY_DIR/${key_name}.pub.old" fi
# Generate new key ssh-keygen -t "$key_type" -f "$KEY_DIR/$key_name" -C "$USER@$(hostname)"
echo "New key generated. Deploy to servers:" cat "$KEY_DIR/${key_name}.pub"}
case "$1" in rotate) rotate_keys ed25519 ;; list) ls -la "$KEY_DIR"/id_* ;; deploy) server=$2 cat "$KEY_DIR/id_ed25519.pub" | ssh "$server" 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys' ;; *) echo "Usage: $0 {rotate|list|deploy <server>}" ;;esacSummary
Section titled “Summary”In this chapter, you learned:
- ✅ SSH key-based authentication
- ✅ Generating ED25519/RSA keys
- ✅ SSH agent and key management
- ✅ Client and server hardening
- ✅ fail2ban for brute force protection
- ✅ Firewalld/iptables rate limiting
- ✅ SSH certificates for scale
- ✅ Jump hosts and bastion servers
- ✅ Port forwarding and tunneling
- ✅ SFTP configuration
- ✅ Two-factor authentication
- ✅ Security best practices checklist
Next Chapter
Section titled “Next Chapter”Chapter 17: High Availability and Load Balancing
Last Updated: February 2026