SSH Keys & Key-based Authentication: Complete Guide to Secure SSH Management

Master SSH key management and key-based authentication. This comprehensive guide covers everything from generating secure SSH keys to advanced configuration, troubleshooting, and security best practices for production environments.

SSH Key-based Authentication Flow Client Machine Private Key ~/.ssh/id_ed25519 Securely stored, never transmitted SSH Agent Manages keys in memory Provides passphrase caching SSH Client ssh user@server Initiates authentication Network Server Machine Authorized Keys ~/.ssh/authorized_keys Stores public keys SSH Daemon (sshd) Validates authentication Manages connections Access Granted Shell session created Secure channel established Challenge-Response
SSH key-based authentication flow from client to server

Why Use SSH Key Authentication?

SSH key authentication provides stronger security than password-based authentication and enables automated, passwordless access to remote systems.

  • Enhanced Security: Cryptographically secure, resistant to brute-force attacks
  • Passwordless Access: No need to type passwords for each connection
  • Automation Friendly: Essential for scripts, CI/CD, and automated deployments
  • Auditability: Each key can be traced to specific users or systems
  • Revocability: Easy to revoke access by removing public keys
  • Multi-factor Support: Can combine with passwords for 2FA

1. SSH Key Types & Algorithms

🔐
Ed25519
ssh-ed25519
Modern elliptic curve algorithm. Fast, secure, and recommended for new keys. High Security Recommended
🔑
RSA 4096
ssh-rsa
Traditional RSA with 4096-bit keys. Widely supported but larger than Ed25519. High Security
🗝️
ECDSA
ecdsa-sha2-nistp256
Elliptic Curve DSA. Good security but less common than Ed25519. Medium Security
⚠️
RSA 2048
ssh-rsa
Legacy RSA with 2048-bit keys. Considered weak by modern standards. Low Security Deprecated
🚫
DSA
ssh-dss
Digital Signature Algorithm. Insecure and deprecated. Never use. Insecure Deprecated

Key Algorithm Comparison

Algorithm Key Size Security Level Performance Compatibility Recommendation Ed25519 256 bits High Fastest OpenSSH 6.5+ ✅ Use for new keys RSA 4096 4096 bits High Good Universal ✅ Good for compatibility ECDSA 521 521 bits High Good OpenSSH 5.7+ 🟡 Acceptable RSA 3072 3072 bits Medium Good Universal 🟡 Minimum for RSA RSA 2048 2048 bits Low Good Universal ❌ Do not use DSA 1024 1024 bits Insecure Poor Legacy only ❌ Never use

2. Generating SSH Keys

# Generate Ed25519 key (Recommended)
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519
ssh-keygen -t ed25519 -C "work_laptop" -f ~/.ssh/work_ed25519
ssh-keygen -t ed25519 -a 100 # 100 key derivation rounds
# Generate RSA 4096 key
ssh-keygen -t rsa -b 4096 -C "server_access" -f ~/.ssh/id_rsa_4096
ssh-keygen -t rsa -b 4096 -o -a 100 # New format with KDF
# Generate ECDSA key
ssh-keygen -t ecdsa -b 521 -C "ecdsa_key" -f ~/.ssh/id_ecdsa
# Advanced key generation options
ssh-keygen -t ed25519 -C "$(hostname)-$(date +%Y-%m-%d)"
ssh-keygen -t rsa -b 4096 -N "" -f ~/.ssh/deploy_key # No passphrase (for automation)
ssh-keygen -t ed25519 -f ~/.ssh/github -C "github@$(hostname)"
# View generated keys
ls -la ~/.ssh/id_* # List private keys
ls -la ~/.ssh/*.pub # List public keys
file ~/.ssh/id_ed25519 # Check key type
# Key generation with specific comment
ssh-keygen -t ed25519 -C "$(whoami)@$(hostname)-$(date +%Y%m%d)"
ssh-keygen -t rsa -b 4096 -C "production-deploy-$(date +%s)"
Private Key
Public Key
Authorized Keys

Key File Structure

# Private Key File (~/.ssh/id_ed25519)
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACD7g6M9J4Hx8X7JjKkK7WQ3pLm1oYzR8tNvq2wK5jQ7AAAAqJ3e5XOd3uVz
...
-----END OPENSSH PRIVATE KEY-----

# Public Key File (~/.ssh/id_ed25519.pub)
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPuDoz0ngfHxfsmMqQrtZDekubWhjNHy02+rbArmNDs your_email@example.com

# Components of public key:
# 1. Key type: ssh-ed25519
# 2. Public key: AAAAC3NzaC1lZDI1NTE5AAAAIPuDoz0ngfHxfsmMqQ...
# 3. Comment: your_email@example.com
SSH Key Generation & Management Workflow 1. Generate Key ssh-keygen -t ed25519 Choose algorithm 2. Set Passphrase Strong, memorable Optional but recommended 3. Copy Public Key ssh-copy-id user@host Distribute to servers 4. Test Connection ssh -v user@host Verify authentication Key Management Commands: ssh-keygen -l -f key.pub # Show fingerprint ssh-add -l # List agent keys
Complete SSH key generation and management workflow

3. Managing SSH Keys on Servers

Copying Public Keys to Servers

# Method 1: ssh-copy-id (easiest)
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostname
ssh-copy-id -i ~/.ssh/id_ed25519 user@hostname # Works with private key too
ssh-copy-id -p 2222 user@hostname # Non-standard port
# Method 2: Manual copy (more control)
cat ~/.ssh/id_ed25519.pub | ssh user@hostname "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
ssh user@hostname "echo '$(cat ~/.ssh/id_ed25519.pub)' >> ~/.ssh/authorized_keys"
# Method 3: Using scp
scp ~/.ssh/id_ed25519.pub user@hostname:~/mykey.pub
ssh user@hostname "cat ~/mykey.pub >> ~/.ssh/authorized_keys && rm ~/mykey.pub"
# Method 4: For multiple keys
for key in ~/.ssh/*.pub; do ssh-copy-id -i "$key" user@hostname; done
cat ~/.ssh/*.pub | ssh user@hostname "cat >> ~/.ssh/authorized_keys"
# Verify key was added
ssh user@hostname "cat ~/.ssh/authorized_keys" | grep "your_key"
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no user@hostname echo "Success"

authorized_keys File Format

# ~/.ssh/authorized_keys - Server-side public key storage
# Each line contains one public key with optional options

# Basic key entry
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPuDoz0ngfHxfsmMqQrtZDekubWhjNHy02+rbArmNDs alice@laptop

# Key with command restriction
command="/usr/bin/rbash",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAA... deploy@ci

# Key with source IP restriction
from="192.168.1.0/24,10.0.0.0/8" ssh-rsa AAA... admin@workstation

# Key with expiration date
expiry-time="2025-12-31" ssh-ed25519 AAA... temp@contractor

# Key for specific command only
command="scp",restrict ssh-ed25519 AAA... backup@server

# Multiple restrictions combined
command="/usr/bin/rbash",from="10.0.0.5",no-port-forwarding,no-pty ssh-rsa AAA... restricted@host

# Environment variable setting
environment="PATH=/usr/bin" ssh-ed25519 AAA... script@automation

# Certificate authority signed key
cert-authority,principals="admin,root" ssh-rsa AAA... ca@organization

# Tunnel-only key
permitopen="localhost:8080",permitlisten="localhost:9090" ssh-ed25519 AAA... tunnel@proxy

Server-side Configuration

/etc/ssh/sshd_config - Key Authentication Settings
# Enable public key authentication
PubkeyAuthentication yes

# Location of authorized_keys files
AuthorizedKeysFile      .ssh/authorized_keys .ssh/authorized_keys2

# Allow users to place keys in ~/.ssh/authorized_keys
StrictModes yes

# Disable password authentication (after key setup)
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

# Allow agent forwarding (use with caution)
AllowAgentForwarding yes

# Key algorithms to accept (modern defaults)
PubkeyAcceptedAlgorithms +ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com

# Disable weak key types
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512

# Limit authentication attempts
MaxAuthTries 3
MaxSessions 10

# Disable empty passwords
PermitEmptyPasswords no

# Root login restrictions
PermitRootLogin prohibit-password  # Root can login with key only

# Restrict users/groups
AllowUsers alice bob charlie
AllowGroups ssh-users

# Restrict key options
AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
AuthorizedKeysCommandUser nobody

# ChrootDirectory for SFTP-only users
Match User sftpuser
    ChrootDirectory /var/sftp
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

4. SSH Agent & Key Management

SSH Agent Usage

# Start SSH agent
eval "$(ssh-agent -s)" # Start agent
ssh-agent bash # Start shell with agent
systemctl --user start ssh-agent # Systemd user service
# Add keys to agent
ssh-add ~/.ssh/id_ed25519 # Add specific key
ssh-add # Add default keys (~/.ssh/id_*)
ssh-add -K ~/.ssh/id_ed25519 # Store in macOS keychain
ssh-add -t 3600 ~/.ssh/id_ed25519 # Key expires in 1 hour
ssh-add -c ~/.ssh/id_ed25519 # Confirm each use
# List keys in agent
ssh-add -l # List key fingerprints
ssh-add -L # List public keys
ssh-add -E md5 -l # List with MD5 fingerprints
ssh-add -E sha256 -l # List with SHA256 fingerprints
# Manage agent keys
ssh-add -d ~/.ssh/id_rsa # Remove specific key
ssh-add -D # Remove all keys
ssh-add -x # Lock agent with password
ssh-add -X # Unlock agent
# Agent forwarding
ssh -A user@hostname # Enable agent forwarding
ssh -o ForwardAgent=yes user@hostname # Alternative syntax
# Debug agent
echo $SSH_AUTH_SOCK # Check agent socket
ssh-add -T ~/.ssh/id_ed25519.pub # Test if key is in agent

Persistent SSH Agent Configuration

# ~/.bashrc or ~/.zshrc - Persistent SSH agent setup

# SSH Agent configuration
SSH_ENV="$HOME/.ssh/agent-environment"

function start_agent {
    echo "Initializing new SSH agent..."
    /usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
    echo "succeeded"
    chmod 600 "${SSH_ENV}"
    . "${SSH_ENV}" > /dev/null
    /usr/bin/ssh-add;
}

# Source SSH settings, if applicable
if [ -f "${SSH_ENV}" ]; then
    . "${SSH_ENV}" > /dev/null
    ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
        start_agent;
    }
else
    start_agent;
fi

# Automatically add keys on startup (optional)
keys_to_add=(
    "$HOME/.ssh/id_ed25519"
    "$HOME/.ssh/work_key"
    "$HOME/.ssh/github"
)

for key in "${keys_to_add[@]}"; do
    if [[ -f "$key" ]] && ! ssh-add -l | grep -q "$(ssh-keygen -lf "$key" | awk '{print $2}')"; then
        echo "Adding SSH key: $(basename "$key")"
        ssh-add "$key"
    fi
done

# Git SSH configuration
export GIT_SSH_COMMAND="ssh -o IdentitiesOnly=yes -i ~/.ssh/github"

5. Advanced SSH Key Management

Key Rotation & Migration

1 Generate new key pair
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "$(whoami)@$(hostname)-$(date +%Y%m%d)"
2 Add new public key to servers (alongside old key)
ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@server
3 Test new key works
ssh -i ~/.ssh/id_ed25519_new user@server "echo 'New key works'"
4 Remove old key from servers
# Get old key fingerprint
OLD_FINGERPRINT=$(ssh-keygen -lf ~/.ssh/id_ed25519 | awk '{print $2}')

# Remove from server
ssh user@server "sed -i '/$OLD_FINGERPRINT/d' ~/.ssh/authorized_keys"
5 Replace old key with new key
mv ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.old
mv ~/.ssh/id_ed25519.pub ~/.ssh/id_ed25519.pub.old
mv ~/.ssh/id_ed25519_new ~/.ssh/id_ed25519
mv ~/.ssh/id_ed25519_new.pub ~/.ssh/id_ed25519.pub

Multiple SSH Keys & Config File

~/.ssh/config - Advanced SSH Configuration
# ~/.ssh/config - SSH client configuration

# Global settings
Host *
    AddKeysToAgent yes
    UseKeychain yes                    # macOS keychain integration
    IdentitiesOnly yes                 # Only use specified identities
    ServerAliveInterval 60             # Keep connections alive
    ServerAliveCountMax 3
    TCPKeepAlive yes
    Compression yes
    LogLevel ERROR

# Personal GitHub
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/github
    IdentitiesOnly yes

# Work GitHub
Host github-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/work_github
    IdentitiesOnly yes

# Production server
Host production
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/deploy_key
    IdentitiesOnly yes
    ForwardAgent no                    # Security: no agent forwarding to prod
    ServerAliveInterval 30
    ServerAliveCountMax 5

# Development server
Host dev
    HostName 192.168.1.100
    User developer
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes                   # Safe: agent forwarding in dev
    LocalForward 8080 localhost:80    # Port forwarding

# Jump host/bastion configuration
Host internal-*
    ProxyJump bastion
    ForwardAgent no

Host bastion
    HostName bastion.example.com
    User admin
    IdentityFile ~/.ssh/bastion_key

Host internal-web
    HostName 10.0.1.10
    User webadmin

Host internal-db
    HostName 10.0.1.20
    User dbadmin

# AWS EC2 instances
Host *.compute.amazonaws.com
    User ec2-user
    IdentityFile ~/.ssh/aws_key.pem
    StrictHostKeyChecking accept-new   # Auto-accept new host keys

# Legacy server with old algorithms
Host legacy
    HostName legacy.example.com
    User admin
    IdentityFile ~/.ssh/legacy_rsa
    HostKeyAlgorithms +ssh-rsa        # Enable legacy algorithms
    KexAlgorithms +diffie-hellman-group14-sha1

# SFTP-only server
Host sftp-server
    HostName sftp.example.com
    User upload
    IdentityFile ~/.ssh/sftp_key
    Subsystem sftp internal-sftp

Certificate-based Authentication

# Create Certificate Authority (CA)
ssh-keygen -t ed25519 -f ~/.ssh/ca_key -C "CA Key"

# Sign user key with CA
ssh-keygen -s ~/.ssh/ca_key -I "alice@company" -n alice,bob -V +52w ~/.ssh/id_ed25519.pub

# Result: ~/.ssh/id_ed25519-cert.pub
# -----BEGIN CERTIFICATE-----
# ...

# Server configuration (/etc/ssh/sshd_config)
TrustedUserCAKeys /etc/ssh/ca.pub
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u

# Client configuration (~/.ssh/config)
Host *.example.com
    CertificateFile ~/.ssh/id_ed25519-cert.pub
    IdentityFile ~/.ssh/id_ed25519

6. Security Best Practices

Critical Security Practices:
1. Use strong passphrases: Always protect private keys with passphrases
2. Regular key rotation: Rotate keys every 6-12 months or after security incidents
3. Disable password authentication: Once keys are working, disable PasswordAuthentication
4. Use key restrictions: Limit keys with from=, command=, no-port-forwarding options
5. Secure private keys: chmod 600 for private keys, chmod 644 for public keys
6. Audit authorized_keys: Regularly review and remove unused keys
7. Use modern algorithms: Prefer Ed25519 over RSA, avoid DSA completely
8. Limit agent forwarding: Only enable when absolutely necessary
9. Monitor SSH access: Review /var/log/auth.log or /var/log/secure
10. Implement fail2ban: Protect against brute-force attacks

Security Hardening Script

#!/bin/bash
# ssh-security-hardening.sh - Harden SSH configuration

set -e

echo "=== SSH Security Hardening ==="

# Backup original config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)

# Apply security settings
cat >> /etc/ssh/sshd_config << 'EOF'

# Security hardening
Protocol 2
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

# Key exchange algorithms
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256

# Ciphers
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com

# Authentication limits
MaxAuthTries 3
MaxSessions 10
LoginGraceTime 60
ClientAliveInterval 300
ClientAliveCountMax 2

# Restrict users
AllowUsers alice bob charlie
# AllowGroups ssh-users

# Disable unused features
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
PermitTunnel no
PrintMotd no
TCPKeepAlive no
Compression no

# Chroot for SFTP
Subsystem sftp internal-sftp
EOF

# Set proper permissions
chmod 600 /etc/ssh/sshd_config
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_* 2>/dev/null || true
chmod 644 ~/.ssh/*.pub 2>/dev/null || true

# Restart SSH service
systemctl restart sshd

echo "SSH security hardening complete!"
echo "Test connection before closing current session."

7. Troubleshooting SSH Key Issues

Problem Symptoms Solution Diagnostic Commands Permission denied (publickey) Key rejected, falls back to password Check permissions, verify key is in authorized_keys ssh -v, ls -la ~/.ssh Agent refused operation Key not loaded or agent not running Start agent, add key: ssh-add echo $SSH_AUTH_SOCK, ssh-add -l Too many authentication failures Blocked after multiple attempts Use specific key: ssh -i key.pem ssh -o IdentitiesOnly=yes Algorithm negotiation failed Client/server algorithm mismatch Update SSH versions, enable legacy algorithms ssh -Q cipher, ssh -Q kex Connection timeout Network/firewall issues Check network, firewall rules, SSH port telnet host 22, nc -zv host 22 Host key verification failed Changed server key Remove old key from known_hosts ssh-keygen -R hostname Key ignored by server Key in agent but not used Server may restrict key types or options ssh -o PreferredAuthentications=publickey

Debugging SSH Connections

# Verbose debugging
ssh -vvv user@hostname # Maximum verbosity
ssh -v -o PreferredAuthentications=publickey user@hostname
# Test specific key
ssh -i ~/.ssh/id_ed25519 -v user@hostname # Force specific key
ssh -o IdentitiesOnly=yes -i ~/.ssh/key user@hostname
# Check server-side logs
tail -f /var/log/auth.log # Debian/Ubuntu
tail -f /var/log/secure # RHEL/CentOS
journalctl -u sshd -f # Systemd systems
# Verify key fingerprints
ssh-keygen -lf ~/.ssh/id_ed25519.pub # Local fingerprint
ssh-keyscan -t ed25519 hostname | ssh-keygen -lf - # Remote fingerprint
# Check supported algorithms
ssh -Q key # Query supported key types
ssh -Q cipher # Query ciphers
ssh -Q kex # Query KEX algorithms
# Test without config file
ssh -F /dev/null user@hostname # Ignore ~/.ssh/config

Common Permission Issues

# Fix SSH directory permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_*          # Private keys
chmod 644 ~/.ssh/*.pub         # Public keys
chmod 644 ~/.ssh/known_hosts
chmod 600 ~/.ssh/config        # If exists

# Fix home directory permissions (important!)
chmod 755 ~
chown -R $(whoami):$(whoami) ~/.ssh

# Check SELinux context (RHEL/CentOS)
ls -Z ~/.ssh
restorecon -Rv ~/.ssh

# Verify with ssh in debug mode
ssh -vvv user@localhost 2>&1 | grep -i "permission"

8. Automation & Scripting with SSH Keys

Automated Deployment Script

#!/bin/bash
# deploy.sh - Automated deployment using SSH keys

set -euo pipefail

# Configuration
DEPLOY_KEY="$HOME/.ssh/deploy_key"
DEPLOY_USER="deploy"
DEPLOY_HOST="production.example.com"
APP_DIR="/var/www/myapp"
BACKUP_DIR="/var/backups/myapp"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Logging function
log() {
    echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}

error() {
    echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" >&2
}

# Check if deploy key exists
if [[ ! -f "$DEPLOY_KEY" ]]; then
    error "Deploy key not found: $DEPLOY_KEY"
    exit 1
fi

# Set restrictive permissions on deploy key
chmod 600 "$DEPLOY_KEY"

# SSH command with deploy key
SSH_CMD="ssh -i '$DEPLOY_KEY' -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR $DEPLOY_USER@$DEPLOY_HOST"

# Function to run remote command
run_remote() {
    log "Running: $1"
    eval "$SSH_CMD '$1'"
    local status=$?
    if [[ $status -ne 0 ]]; then
        error "Command failed with exit code: $status"
        return $status
    fi
}

# Main deployment process
log "Starting deployment to $DEPLOY_HOST"

# 1. Create backup
log "Creating backup..."
run_remote "tar -czf $BACKUP_DIR/backup-$(date +%Y%m%d-%H%M%S).tar.gz -C $APP_DIR ."

# 2. Pull latest code
log "Pulling latest code..."
run_remote "cd $APP_DIR && git pull origin main"

# 3. Install dependencies
log "Installing dependencies..."
run_remote "cd $APP_DIR && npm ci --only=production"

# 4. Run database migrations
log "Running database migrations..."
run_remote "cd $APP_DIR && npm run migrate"

# 5. Restart application
log "Restarting application..."
run_remote "sudo systemctl restart myapp"

# 6. Verify deployment
log "Verifying deployment..."
run_remote "curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/health" | grep -q "200" && \
    log "Deployment successful!" || \
    error "Health check failed"

log "Deployment completed successfully!"

Ansible SSH Key Configuration

# ansible/ssh-keys.yml - Ansible playbook for SSH key management
- name: Configure SSH keys on servers
  hosts: all
  become: yes
  vars:
    ssh_users:
      - name: alice
        keys:
          - "ssh-ed25519 AAA... alice@laptop"
          - "ssh-ed25519 AAA... alice@work"
      - name: bob
        keys:
          - "ssh-ed25519 AAA... bob@desktop"
      - name: deploy
        keys:
          - "ssh-ed25519 AAA... deploy@ci"
  
  tasks:
    - name: Ensure .ssh directory exists
      file:
        path: "/home/{{ item.name }}/.ssh"
        state: directory
        mode: '0700'
        owner: "{{ item.name }}"
        group: "{{ item.name }}"
      loop: "{{ ssh_users }}"
      when: item.name != 'root'
    
    - name: Deploy authorized_keys
      copy:
        dest: "/home/{{ item.name }}/.ssh/authorized_keys"
        content: "{{ item.keys | join('\n') }}"
        mode: '0600'
        owner: "{{ item.name }}"
        group: "{{ item.name }}"
      loop: "{{ ssh_users }}"
      when: item.name != 'root'
    
    - name: Configure SSH daemon
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "^{{ item.key }}"
        line: "{{ item.key }} {{ item.value }}"
        state: present
        validate: '/usr/sbin/sshd -t -f %s'
      loop:
        - { key: 'PasswordAuthentication', value: 'no' }
        - { key: 'PubkeyAuthentication', value: 'yes' }
        - { key: 'PermitRootLogin', value: 'prohibit-password' }
        - { key: 'MaxAuthTries', value: '3' }
      notify: restart sshd
  
  handlers:
    - name: restart sshd
      service:
        name: sshd
        state: restarted

Master SSH Key Management

SSH key-based authentication is fundamental to secure system administration, automation, and modern infrastructure management. By mastering key generation, management, and security practices, you can create robust, scalable, and secure access controls for your systems.

Remember: Security is a process, not a product. Regularly audit your SSH keys, rotate them periodically, and follow the principle of least privilege. Use modern algorithms like Ed25519, implement proper key restrictions, and always protect private keys with strong passphrases.

Next Steps: Audit your current SSH keys with ssh-add -l and find ~/.ssh -name "*.pub" -exec ssh-keygen -lf {} \;. Rotate any weak or old keys. Implement a centralized SSH key management system for teams. Set up SSH certificates for large-scale environments. As you gain experience, you'll appreciate the power and flexibility that proper SSH key management provides.