Secure SSH with Key-Based Authentication
Table of Contents
1. [Introduction to SSH and Key-Based Authentication](#introduction) 2. [Understanding SSH Key Types](#ssh-key-types) 3. [SSH Key Generation](#key-generation) 4. [SSH Key Management](#key-management) 5. [Server Configuration](#server-configuration) 6. [Client Configuration](#client-configuration) 7. [Advanced Security Configurations](#advanced-security) 8. [Troubleshooting](#troubleshooting) 9. [Best Practices](#best-practices) 10. [Monitoring and Auditing](#monitoring)Introduction to SSH and Key-Based Authentication {#introduction}
SSH (Secure Shell) is a cryptographic network protocol that provides secure communication over an unsecured network. Key-based authentication is a more secure alternative to password-based authentication, utilizing public-key cryptography to verify user identity.
Why Use Key-Based Authentication
Key-based authentication offers several advantages over traditional password authentication:
| Advantage | Description | |-----------|-------------| | Enhanced Security | Eliminates brute-force password attacks | | Convenience | No need to remember complex passwords | | Automation | Enables secure automated processes | | Non-repudiation | Provides strong identity verification | | Scalability | Easier management of multiple server access |
How SSH Key Authentication Works
The process involves asymmetric cryptography with a key pair:
1. Key Pair Generation: A public and private key pair is created 2. Public Key Distribution: The public key is placed on the server 3. Authentication Process: The client proves possession of the private key 4. Access Granted: Server verifies the signature and grants access
Understanding SSH Key Types {#ssh-key-types}
SSH supports multiple key algorithms, each with different security characteristics and performance implications.
Supported Key Types
| Algorithm | Key Size | Security Level | Performance | Recommended Use | |-----------|----------|----------------|-------------|-----------------| | RSA | 2048-4096 bits | Good-Excellent | Moderate | General purpose | | ECDSA | 256-521 bits | Good-Excellent | Fast | Modern systems | | Ed25519 | 256 bits | Excellent | Very Fast | Preferred choice | | DSA | 1024 bits | Deprecated | Fast | Legacy systems only |
Algorithm Comparison
RSA (Rivest-Shamir-Adleman) - Most widely supported - Requires larger key sizes for equivalent security - Computationally intensive for large keys
ECDSA (Elliptic Curve Digital Signature Algorithm) - Smaller key sizes with equivalent security - Faster than RSA - Some implementation concerns with certain curves
Ed25519 (Edwards-curve Digital Signature Algorithm) - Based on Curve25519 - Excellent security properties - Fast performance - Resistant to side-channel attacks
SSH Key Generation {#key-generation}
Basic Key Generation
The ssh-keygen command is used to generate SSH key pairs.
#### Generate RSA Key Pair
`bash
ssh-keygen -t rsa -b 4096 -C "user@example.com"
`
Command Breakdown:
- -t rsa: Specifies RSA algorithm
- -b 4096: Sets key length to 4096 bits
- -C "user@example.com": Adds a comment for identification
#### Generate Ed25519 Key Pair (Recommended)
`bash
ssh-keygen -t ed25519 -C "user@example.com"
`
Command Breakdown:
- -t ed25519: Specifies Ed25519 algorithm
- Ed25519 has a fixed key length of 256 bits
#### Generate ECDSA Key Pair
`bash
ssh-keygen -t ecdsa -b 521 -C "user@example.com"
`
Command Breakdown:
- -t ecdsa: Specifies ECDSA algorithm
- -b 521: Sets curve size to 521 bits
Advanced Key Generation Options
#### Specify Key File Location
`bash
ssh-keygen -t ed25519 -f ~/.ssh/custom_key -C "custom key"
`
Notes:
- -f ~/.ssh/custom_key: Specifies custom file path
- Creates custom_key (private) and custom_key.pub (public)
#### Generate Key with Passphrase
`bash
ssh-keygen -t ed25519 -N "strong_passphrase" -f ~/.ssh/secure_key
`
Notes:
- -N "strong_passphrase": Sets passphrase non-interactively
- Passphrase encrypts the private key file
#### Generate Key with Custom Parameters
`bash
ssh-keygen -t rsa -b 4096 -f ~/.ssh/server_key -N "" -C "server-$(date +%Y%m%d)"
`
Command Breakdown:
- -N "": No passphrase (empty string)
- -C "server-$(date +%Y%m%d)": Dynamic comment with date
Key Generation Process Flow
`
1. Algorithm Selection
↓
2. Key Size Determination
↓
3. File Location Specification
↓
4. Passphrase Configuration
↓
5. Key Pair Creation
↓
6. File Permissions Setting
`
SSH Key Management {#key-management}
File Structure and Permissions
SSH keys must have correct permissions for security:
| File Type | Permissions | Owner | Description | |-----------|-------------|-------|-------------| | Private Key | 600 | User only | Read/write for owner only | | Public Key | 644 | User | Read for all, write for owner | | .ssh Directory | 700 | User only | Full access for owner only | | authorized_keys | 600 | User only | Read/write for owner only |
#### Set Correct Permissions
`bash
Set directory permissions
chmod 700 ~/.sshSet private key permissions
chmod 600 ~/.ssh/id_ed25519Set public key permissions
chmod 644 ~/.ssh/id_ed25519.pubSet authorized_keys permissions
chmod 600 ~/.ssh/authorized_keys`Key Distribution Methods
#### Method 1: Using ssh-copy-id (Recommended)
`bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server.example.com
`
Command Breakdown:
- -i ~/.ssh/id_ed25519.pub: Specifies public key file
- user@server.example.com: Target user and server
#### Method 2: Manual Copy
`bash
cat ~/.ssh/id_ed25519.pub | ssh user@server.example.com "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
`
Process Explanation: 1. Reads local public key 2. Creates remote .ssh directory if needed 3. Appends public key to authorized_keys
#### Method 3: Direct File Transfer
`bash
scp ~/.ssh/id_ed25519.pub user@server.example.com:~/temp_key.pub
ssh user@server.example.com "cat ~/temp_key.pub >> ~/.ssh/authorized_keys && rm ~/temp_key.pub"
`
Multiple Key Management
#### Generate Keys for Different Purposes
`bash
Personal key
ssh-keygen -t ed25519 -f ~/.ssh/personal_ed25519 -C "personal@example.com"Work key
ssh-keygen -t ed25519 -f ~/.ssh/work_ed25519 -C "work@company.com"Server administration key
ssh-keygen -t ed25519 -f ~/.ssh/admin_ed25519 -C "admin@servers.com"`#### SSH Config for Multiple Keys
Create ~/.ssh/config:
`
Personal servers
Host personal-server HostName personal.example.com User personaluser IdentityFile ~/.ssh/personal_ed25519 IdentitiesOnly yesWork servers
Host work-server HostName work.company.com User workuser IdentityFile ~/.ssh/work_ed25519 IdentitiesOnly yesAdministrative access
Host admin-* User admin IdentityFile ~/.ssh/admin_ed25519 IdentitiesOnly yes`Server Configuration {#server-configuration}
SSH Daemon Configuration
The SSH daemon configuration file is typically located at /etc/ssh/sshd_config.
#### Essential Security Settings
`bash
Backup original configuration
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backupEdit configuration
sudo nano /etc/ssh/sshd_config`#### Key-Based Authentication Settings
`
Enable public key authentication
PubkeyAuthentication yesSpecify authorized keys file
AuthorizedKeysFile .ssh/authorized_keysDisable password authentication (after key setup)
PasswordAuthentication noDisable challenge-response authentication
ChallengeResponseAuthentication noDisable empty passwords
PermitEmptyPasswords noDisable root login (recommended)
PermitRootLogin noOr allow root login with keys only
PermitRootLogin prohibit-password`#### Additional Security Configurations
`
Change default port (security through obscurity)
Port 2222Limit user access
AllowUsers user1 user2 adminOr limit by group
AllowGroups ssh-users adminSet login grace time
LoginGraceTime 60Limit authentication attempts
MaxAuthTries 3Set maximum sessions
MaxSessions 2Disable X11 forwarding if not needed
X11Forwarding noDisable agent forwarding if not needed
AllowAgentForwarding noDisable TCP forwarding if not needed
AllowTcpForwarding no`Validate and Restart SSH Service
#### Test Configuration Syntax
`bash
sudo sshd -t
`
Notes: - Tests configuration file syntax - Reports any errors before applying changes
#### Restart SSH Service
`bash
SystemD systems
sudo systemctl restart sshdSysV systems
sudo service ssh restartCheck service status
sudo systemctl status sshd`Advanced Server Configurations
#### Key-Based Authentication with Restrictions
Add restrictions to authorized_keys entries:
`
Restrict by source IP
from="192.168.1.100" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... user@clientRestrict to specific command
command="/usr/local/bin/backup.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... backup@clientDisable port forwarding
no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... user@clientMultiple restrictions
from="192.168.1.0/24",command="/bin/ls",no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... restricted@client`#### Certificate-Based Authentication
Generate SSH Certificate Authority:
`bash
Generate CA key
ssh-keygen -t ed25519 -f ssh_ca -C "SSH Certificate Authority"Sign user key
ssh-keygen -s ssh_ca -I user_cert -n username -V +1w ~/.ssh/id_ed25519.pub`Configure server to trust CA:
`
In /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ssh_ca.pub`Client Configuration {#client-configuration}
SSH Client Configuration File
The client configuration file ~/.ssh/config allows customization of SSH behavior.
#### Basic Configuration Structure
`
Host hostname
Option value
Option value
Host pattern*
Option value
`
#### Common Configuration Options
| Option | Description | Example | |--------|-------------|---------| | HostName | Real hostname or IP | HostName 192.168.1.100 | | User | Username for connection | User admin | | Port | SSH port number | Port 2222 | | IdentityFile | Path to private key | IdentityFile ~/.ssh/custom_key | | IdentitiesOnly | Use only specified keys | IdentitiesOnly yes | | ServerAliveInterval | Keep-alive interval | ServerAliveInterval 60 | | ServerAliveCountMax | Max keep-alive attempts | ServerAliveCountMax 3 |
#### Example Client Configuration
`
Default settings for all hosts
Host * ServerAliveInterval 60 ServerAliveCountMax 3 HashKnownHosts yes VisualHostKey yesProduction servers
Host prod-* User admin Port 2222 IdentityFile ~/.ssh/production_key IdentitiesOnly yes StrictHostKeyChecking yesDevelopment environment
Host dev-server HostName dev.company.com User developer Port 22 IdentityFile ~/.ssh/dev_key LocalForward 3000 localhost:3000 LocalForward 5432 localhost:5432Jump host configuration
Host internal-server HostName 10.0.1.100 User admin ProxyJump bastion.company.com IdentityFile ~/.ssh/internal_keyBastion host
Host bastion HostName bastion.company.com User jumpuser IdentityFile ~/.ssh/bastion_key ControlMaster auto ControlPath ~/.ssh/control-%r@%h:%p ControlPersist 10m`SSH Agent Configuration
SSH Agent manages private keys in memory, eliminating the need to enter passphrases repeatedly.
#### Start SSH Agent
`bash
Start agent
eval $(ssh-agent)Add keys to agent
ssh-add ~/.ssh/id_ed25519 ssh-add ~/.ssh/work_key ssh-add ~/.ssh/admin_keyList loaded keys
ssh-add -lRemove specific key
ssh-add -d ~/.ssh/work_keyRemove all keys
ssh-add -D`#### Automatic Agent Startup
Add to ~/.bashrc or ~/.zshrc:
`bash
SSH Agent auto-start
if [ -z "$SSH_AUTH_SOCK" ]; then eval $(ssh-agent -s) ssh-add ~/.ssh/id_ed25519 fi`Connection Testing and Debugging
#### Test SSH Connection
`bash
Basic connection test
ssh -T user@server.example.comVerbose connection (debug level 1)
ssh -v user@server.example.comVery verbose (debug level 3)
ssh -vvv user@server.example.comTest with specific key
ssh -i ~/.ssh/specific_key user@server.example.comTest configuration
ssh -F ~/.ssh/test_config user@server.example.com`Advanced Security Configurations {#advanced-security}
Multi-Factor Authentication
Combine key-based authentication with additional factors for enhanced security.
#### TOTP Integration
Install and configure Google Authenticator PAM module:
`bash
Install PAM module
sudo apt-get install libpam-google-authenticatorConfigure for user
google-authenticator`Configure SSH to require both key and TOTP:
`
In /etc/ssh/sshd_config
AuthenticationMethods publickey,keyboard-interactiveIn /etc/pam.d/sshd
auth required pam_google_authenticator.so`SSH Key Rotation
Regular key rotation enhances security by limiting exposure time.
#### Automated Key Rotation Script
`bash
#!/bin/bash
ssh_key_rotation.sh
KEY_TYPE="ed25519" KEY_PATH="$HOME/.ssh" BACKUP_PATH="$HOME/.ssh/backup" SERVERS_FILE="$HOME/.ssh/servers.txt"
Create backup directory
mkdir -p "$BACKUP_PATH"Generate new key pair
NEW_KEY="$KEY_PATH/id_${KEY_TYPE}_$(date +%Y%m%d)" ssh-keygen -t "$KEY_TYPE" -f "$NEW_KEY" -N "" -C "rotated-$(date +%Y%m%d)"Distribute new public key
while read -r server; do echo "Updating key on $server" ssh-copy-id -i "${NEW_KEY}.pub" "$server" done < "$SERVERS_FILE"Backup old keys
mv "$KEY_PATH/id_$KEY_TYPE" "$BACKUP_PATH/id_${KEY_TYPE}_$(date +%Y%m%d).old" mv "$KEY_PATH/id_${KEY_TYPE}.pub" "$BACKUP_PATH/id_${KEY_TYPE}_$(date +%Y%m%d).pub.old"Install new keys
mv "$NEW_KEY" "$KEY_PATH/id_$KEY_TYPE" mv "${NEW_KEY}.pub" "$KEY_PATH/id_${KEY_TYPE}.pub"Set correct permissions
chmod 600 "$KEY_PATH/id_$KEY_TYPE" chmod 644 "$KEY_PATH/id_${KEY_TYPE}.pub"echo "Key rotation completed"
`
Network Security Enhancements
#### Port Knocking
Implement port knocking for additional security:
`bash
Install knockd
sudo apt-get install knockdConfigure /etc/knockd.conf
[options] UseSyslog[openSSH] sequence = 7000,8000,9000 seq_timeout = 5 command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 22 -j ACCEPT tcpflags = syn
[closeSSH]
sequence = 9000,8000,7000
seq_timeout = 5
command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
`
Client usage:
`bash
Knock to open SSH port
knock server.example.com 7000 8000 9000Connect via SSH
ssh user@server.example.comKnock to close SSH port
knock server.example.com 9000 8000 7000`#### VPN Integration
Combine SSH with VPN for layered security:
`bash
OpenVPN configuration example
In SSH config
Host secure-server HostName 10.8.0.100 User admin IdentityFile ~/.ssh/vpn_key ProxyCommand nc -X connect -x vpn-proxy:1080 %h %p`Troubleshooting {#troubleshooting}
Common Issues and Solutions
#### Permission Problems
Issue: SSH key authentication fails due to incorrect permissions.
Diagnosis:
`bash
ls -la ~/.ssh/
`
Solution:
`bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
chmod 600 ~/.ssh/authorized_keys
`
#### Key Not Found
Issue: SSH cannot find the private key.
Diagnosis:
`bash
ssh-add -l
ssh -vvv user@server.example.com
`
Solution:
`bash
Add key to agent
ssh-add ~/.ssh/id_ed25519Or specify key explicitly
ssh -i ~/.ssh/id_ed25519 user@server.example.com`#### Server Configuration Issues
Issue: Server rejects key authentication.
Diagnosis:
`bash
Check server logs
sudo tail -f /var/log/auth.logTest SSH daemon configuration
sudo sshd -t`Common Solutions:
`bash
Ensure PubkeyAuthentication is enabled
grep PubkeyAuthentication /etc/ssh/sshd_configCheck authorized_keys file location
grep AuthorizedKeysFile /etc/ssh/sshd_configVerify SELinux contexts (if applicable)
restorecon -R ~/.ssh/`Debug Information Analysis
#### SSH Client Debug Output
`bash
ssh -vvv user@server.example.com
`
Key Debug Messages:
| Message | Meaning |
|---------|---------|
| debug1: Offering RSA public key | Client offers key for authentication |
| debug1: Server accepts key | Server accepts the offered key |
| debug1: Authentication succeeded | Key authentication successful |
| debug1: key_load_public: No such file | Public key file not found |
#### SSH Server Debug Mode
`bash
Run SSH daemon in debug mode
sudo /usr/sbin/sshd -d -p 2223`Notes:
- -d: Debug mode
- -p 2223: Use alternative port
- Provides detailed authentication process information
Recovery Procedures
#### Locked Out Recovery
If key authentication fails and password authentication is disabled:
1. Physical Access Method:
`bash
# Access server console directly
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
# Temporarily enable password authentication
PasswordAuthentication yes
# Restart SSH service
sudo systemctl restart sshd
`
2. Alternative User Method:
`bash
# Use different user account with access
ssh alternate_user@server.example.com
# Fix primary user's SSH configuration
sudo -u primary_user bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
`
Best Practices {#best-practices}
Security Best Practices
#### Key Management Guidelines
| Practice | Description | Implementation |
|----------|-------------|----------------|
| Use Strong Keys | Prefer Ed25519 or RSA 4096-bit | ssh-keygen -t ed25519 |
| Protect Private Keys | Use passphrases and secure storage | ssh-keygen -N "passphrase" |
| Regular Rotation | Rotate keys periodically | Automated rotation scripts |
| Principle of Least Privilege | Limit key access scope | Restricted authorized_keys |
| Audit Key Usage | Monitor and log key usage | Centralized logging |
#### Server Hardening Checklist
`bash
1. Disable password authentication
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config2. Disable root login
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config3. Change default port
sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config4. Limit login attempts
echo "MaxAuthTries 3" >> /etc/ssh/sshd_config5. Set idle timeout
echo "ClientAliveInterval 300" >> /etc/ssh/sshd_config echo "ClientAliveCountMax 2" >> /etc/ssh/sshd_config6. Disable unused features
echo "X11Forwarding no" >> /etc/ssh/sshd_config echo "AllowAgentForwarding no" >> /etc/ssh/sshd_config7. Restart SSH service
systemctl restart sshd`Operational Best Practices
#### Documentation Standards
Maintain comprehensive documentation:
`
SSH Key Inventory:
- Key ID: admin_ed25519_20240101
- Algorithm: Ed25519
- Created: 2024-01-01
- Purpose: Server administration
- Servers: prod-web-01, prod-db-01
- Expiration: 2024-12-31
- Contact: admin@company.com
`
#### Backup Procedures
`bash
#!/bin/bash
SSH key backup script
BACKUP_DIR="/secure/backup/ssh-keys/$(date +%Y%m%d)" SSH_DIR="$HOME/.ssh"
Create backup directory
mkdir -p "$BACKUP_DIR"Backup SSH directory
tar -czf "$BACKUP_DIR/ssh_backup_$(date +%Y%m%d_%H%M%S).tar.gz" -C "$HOME" .ssh/Encrypt backup
gpg --cipher-algo AES256 --compress-algo 1 --s2k-cipher-algo AES256 \ --s2k-digest-algo SHA512 --s2k-mode 3 --s2k-count 65011712 \ --force-mdc --encrypt -r admin@company.com \ "$BACKUP_DIR/ssh_backup_$(date +%Y%m%d_%H%M%S).tar.gz"Remove unencrypted backup
rm "$BACKUP_DIR/ssh_backup_$(date +%Y%m%d_%H%M%S).tar.gz"echo "SSH key backup completed: $BACKUP_DIR"
`
Monitoring and Auditing {#monitoring}
SSH Connection Monitoring
#### Log Analysis
SSH connections are typically logged to /var/log/auth.log or /var/log/secure.
Important Log Entries:
`bash
Successful key authentication
grep "Accepted publickey" /var/log/auth.logFailed authentication attempts
grep "Failed publickey" /var/log/auth.logConnection summaries
grep "session opened\|session closed" /var/log/auth.log`#### Real-time Monitoring
`bash
Monitor SSH connections in real-time
tail -f /var/log/auth.log | grep sshdMonitor specific user connections
tail -f /var/log/auth.log | grep "user admin"Monitor failed attempts
tail -f /var/log/auth.log | grep "Failed\|Invalid"`Automated Security Monitoring
#### SSH Monitoring Script
`bash
#!/bin/bash
ssh_monitor.sh
LOG_FILE="/var/log/auth.log" ALERT_EMAIL="security@company.com" THRESHOLD=5
Count failed attempts in last hour
FAILED_ATTEMPTS=$(grep "$(date -d '1 hour ago' '+%b %d %H')" "$LOG_FILE" | grep "Failed publickey" | wc -l)if [ "$FAILED_ATTEMPTS" -gt "$THRESHOLD" ]; then echo "ALERT: $FAILED_ATTEMPTS failed SSH attempts in the last hour" | \ mail -s "SSH Security Alert" "$ALERT_EMAIL" fi
Generate daily summary
if [ "$(date +%H:%M)" = "23:59" ]; then { echo "Daily SSH Activity Summary - $(date +%Y-%m-%d)" echo "========================================" echo "Successful logins: $(grep "$(date '+%b %d')" "$LOG_FILE" | grep "Accepted publickey" | wc -l)" echo "Failed attempts: $(grep "$(date '+%b %d')" "$LOG_FILE" | grep "Failed publickey" | wc -l)" echo "Unique source IPs: $(grep "$(date '+%b %d')" "$LOG_FILE" | grep "sshd" | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | sort -u | wc -l)" } | mail -s "Daily SSH Summary" "$ALERT_EMAIL" fi`Compliance and Auditing
#### SSH Configuration Audit
`bash
#!/bin/bash
ssh_audit.sh
CONFIG_FILE="/etc/ssh/sshd_config" REPORT_FILE="/tmp/ssh_audit_$(date +%Y%m%d).txt"
{ echo "SSH Security Configuration Audit - $(date)" echo "=============================================" # Check critical security settings echo "Password Authentication: $(grep "^PasswordAuthentication" "$CONFIG_FILE" || echo "NOT SET")" echo "Root Login: $(grep "^PermitRootLogin" "$CONFIG_FILE" || echo "NOT SET")" echo "Public Key Authentication: $(grep "^PubkeyAuthentication" "$CONFIG_FILE" || echo "NOT SET")" echo "SSH Port: $(grep "^Port" "$CONFIG_FILE" || echo "Default (22)")" echo "Max Auth Tries: $(grep "^MaxAuthTries" "$CONFIG_FILE" || echo "NOT SET")" # Check key algorithms echo "" echo "Supported Key Algorithms:" ssh -Q key # Check active connections echo "" echo "Current SSH Sessions:" who | grep pts } > "$REPORT_FILE"
echo "Audit report generated: $REPORT_FILE"
`
This comprehensive guide provides a complete foundation for implementing secure SSH with key-based authentication. The configuration examples, security practices, and monitoring procedures ensure robust protection while maintaining operational efficiency. Regular review and updates of these configurations will help maintain security effectiveness as threats evolve.