·10 min read

SSH Key Rotation: Automating Credential Lifecycle

Implement automated SSH key rotation to reduce risk from compromised keys. Learn rotation strategies, automation tools, and zero-downtime updates.

SSHSecurityAutomationEnterpriseKey Management

SSH keys don't expire like passwords, but they should be rotated regularly. Compromised keys can provide unauthorized access indefinitely. Automated key rotation ensures security without manual overhead.

Why Rotate SSH Keys?

Risks of not rotating:

  • Compromised keys provide permanent access
  • Former employees retain access
  • Key sprawl (hundreds of unknown keys)
  • Compliance violations (SOC2, PCI-DSS require rotation)

Benefits of rotation:

  • Limit exposure window
  • Revoke access automatically
  • Audit trail of key usage
  • Meet compliance requirements

Rotation Strategies

Strategy 1: Time-Based Rotation

Rotate keys every N days:

# Rotate every 90 days
ROTATION_INTERVAL=90

Pros: Predictable, easy to schedule
Cons: Doesn't respond to incidents

Strategy 2: Event-Based Rotation

Rotate on specific events:

  • Employee departure
  • Security incident
  • Compliance audit
  • Key compromise suspected

Pros: Responsive to threats
Cons: Requires monitoring

Strategy 3: Hybrid Approach

Combine time-based and event-based:

  • Regular rotation (90 days)
  • Immediate rotation on security events
  • Gradual rollout for large fleets

Manual Rotation Process

Step 1: Generate New Key

# Generate new key
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_new -C "user@example.com-2026"

# Start SSH agent with new key
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519_new

Step 2: Deploy New Key

# Copy new key to servers
for server in server1 server2 server3; do
  ssh-copy-id -i ~/.ssh/id_ed25519_new.pub user@$server
done

Step 3: Test New Key

# Test connection with new key
for server in server1 server2 server3; do
  ssh -i ~/.ssh/id_ed25519_new user@$server 'echo "Success"'
done

Step 4: Remove Old Key

# Remove old key from servers
for server in server1 server2 server3; do
  ssh user@$server "sed -i '/old-key-comment/d' ~/.ssh/authorized_keys"
done

Step 5: Update SSH Config

# ~/.ssh/config
Host server1 server2 server3
    IdentityFile ~/.ssh/id_ed25519_new
    IdentitiesOnly yes

Automated Rotation Script

Basic Rotation Script

#!/bin/bash
# rotate-keys.sh - Automated SSH key rotation

set -e

SERVERS="server1 server2 server3"
OLD_KEY=~/.ssh/id_ed25519_old
NEW_KEY=~/.ssh/id_ed25519_new
BACKUP_KEY=~/.ssh/id_ed25519_backup

echo "Starting SSH key rotation..."

# Step 1: Backup current key
echo "Backing up current key..."
cp ~/.ssh/id_ed25519 $OLD_KEY 2>/dev/null || true
cp ~/.ssh/id_ed25519.pub $OLD_KEY.pub 2>/dev/null || true

# Step 2: Generate new key
echo "Generating new key..."
ssh-keygen -t ed25519 -f $NEW_KEY -N "" -C "rotated-$(date +%Y%m%d)"

# Step 3: Deploy new key
echo "Deploying new key to servers..."
for server in $SERVERS; do
  echo "  Deploying to $server..."
  ssh-copy-id -i $NEW_KEY.pub user@$server
done

# Step 4: Test new key
echo "Testing new key..."
for server in $SERVERS; do
  if ssh -i $NEW_KEY -o ConnectTimeout=5 user@$server 'exit' 2>/dev/null; then
    echo "  ✓ $server"
  else
    echo "  ✗ $server - FAILED"
    exit 1
  fi
done

# Step 5: Remove old key
echo "Removing old key from servers..."
for server in $SERVERS; do
  ssh user@$server "
    # Remove old key (by comment)
    sed -i '/rotated-/d' ~/.ssh/authorized_keys
    # Keep only new key
    cat >> ~/.ssh/authorized_keys <<EOF
$(cat $NEW_KEY.pub)
EOF
  "
done

# Step 6: Update local config
echo "Updating SSH config..."
mv $NEW_KEY ~/.ssh/id_ed25519
mv $NEW_KEY.pub ~/.ssh/id_ed25519.pub

# Step 7: Restart SSH agent
echo "Restarting SSH agent..."
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519

echo "✓ Key rotation complete"

Advanced Rotation with Ansible

# rotate-ssh-keys.yml
---
- name: Rotate SSH keys
  hosts: all
  become: yes
  vars:
    new_key_pub: "{{ lookup('file', '~/.ssh/id_ed25519_new.pub') }}"
  
  tasks:
    - name: Backup authorized_keys
      copy:
        src: /root/.ssh/authorized_keys
        dest: /root/.ssh/authorized_keys.backup
        remote_src: yes
    
    - name: Add new key
      authorized_key:
        user: root
        key: "{{ new_key_pub }}"
        state: present
    
    - name: Test new key
      command: ssh -i /root/.ssh/id_ed25519_new localhost exit
      delegate_to: localhost
      ignore_errors: yes
      register: test_result
    
    - name: Remove old keys
      authorized_key:
        user: root
        key: "{{ item }}"
        state: absent
      loop: "{{ old_keys }}"
      when: test_result.rc == 0

Run:

ansible-playbook -i inventory rotate-ssh-keys.yml

Zero-Downtime Rotation

Overlap Period

Keep both old and new keys active during transition:

# Server authorized_keys
# Old key (valid until 2026-11-01)
ssh-ed25519 AAAA... old-key-comment

# New key (valid from 2026-10-17)
ssh-ed25519 AAAA... new-key-comment

Gradual Rollout

#!/bin/bash
# gradual-rotation.sh

# Phase 1: Deploy new key to 10% of servers
servers_10=$(shuf -n 10% servers.txt)
for server in $servers_10; do
  ssh-copy-id -i new_key.pub user@$server
done

# Phase 2: Test and monitor
sleep 24h

# Phase 3: Deploy to remaining servers
servers_90=$(comm -23 servers.txt <(echo "$servers_10" | sort))
for server in $servers_90; do
  ssh-copy-id -i new_key.pub user@$server
done

# Phase 4: Remove old keys
for server in $(cat servers.txt); do
  ssh user@$server "sed -i '/old-key/d' ~/.ssh/authorized_keys"
done

Enterprise Key Management

SSH Certificate Authority

Use SSH certificates instead of keys:

# Generate CA key
ssh-keygen -f ca_key -N ""

# Sign user key
ssh-keygen -s ca_key -I user@example.com -n user -V +90d user_key.pub

# Server trusts CA
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca_key.pub

Benefits:

  • Automatic expiration
  • Centralized trust
  • No key distribution
  • Easy revocation

HashiCorp Vault SSH Secrets

# Configure Vault
vault write ssh/config/ca generate_signing_key=true

# Issue short-lived certificate
vault write ssh/sign/otp_key_role \
    ip=192.168.1.100 \
    valid_principals=user

AWS Systems Manager

# Send SSH public key to instance
aws ssm send-ssh-public-key \
  --instance-id i-1234567890abcdef0 \
  --instance-os-user ec2-user \
  --ssh-public-key file://key.pub

FoxTerm Key Rotation Support

FoxTerm simplifies enterprise key rotation:

Visual Key Management

  • View all SSH keys across servers
  • Track key age and usage
  • Identify unused keys
  • One-click rotation

Automated Rotation

  • Schedule regular rotation (30/60/90 days)
  • Zero-downtime overlap period
  • Automatic testing and rollback
  • Audit log of all rotations

Certificate Management

  • SSH CA integration
  • Automatic certificate renewal
  • Expiration notifications
  • Revocation management

Compliance Reporting

  • Key inventory report
  • Rotation compliance status
  • Audit trail
  • Export for compliance audits

Best Practices

  1. Rotate regularly — Every 90 days maximum
  2. Automate rotation — Scripts or tools like FoxTerm
  3. Test before removing — Verify new key works
  4. Overlap period — Keep both keys active during transition
  5. Use certificates — SSH CA for large fleets
  6. Audit regularly — Review authorized_keys files
  7. Monitor usage — Track which keys are used
  8. Backup before rotation — Keep old keys as backup
  9. Document process — Clear rotation procedures
  10. Compliance tracking — Meet SOC2/PCI-DSS requirements

Conclusion

SSH key rotation is essential for enterprise security. Automated rotation eliminates manual overhead while ensuring keys are regularly updated.

FoxTerm makes key rotation visual and automated, with scheduling, testing, and compliance reporting.


FoxTerm Pro includes enterprise SSH key rotation and management. Download at foxterm.app.