Automated SSH Public Key Distribution: Scalable Solutions for Multi-Admin Environments


1 views

When managing multiple servers across teams, SSH public key authentication solves password fatigue but introduces new administrative overhead. Traditional authorized_keys editing becomes unsustainable at scale:

# Problematic manual approach
ssh admin@server1 "echo 'ssh-rsa AAAAB3Nza... user1@pc' >> ~/.ssh/authorized_keys"
ssh admin@server2 "echo 'ssh-rsa AAAAB3Nza... user1@pc' >> ~/.ssh/authorized_keys"
# Repeat for N servers and M users...

Modern tooling provides three architectural approaches:

1. Configuration Management Integration

Ansible's authorized_key module enables declarative management:

# ansible/playbooks/ssh_keys.yml
- hosts: all_servers
  tasks:
    - name: Add developer keys
      ansible.posix.authorized_key:
        user: "{{ deploy_user }}"
        state: present
        key: "{{ lookup('file', 'keys/{{ user }}.pub') }}"
      when: "'developers' in group_names"

2. Dedicated SSH Key Distribution Tools

Open-source solutions like ssh-cert-authority provide RBAC capabilities:

# Generate time-bound certificates
ssh-cert-authority -b 30d -n dev_team user1.pub
# Outputs signed certificate valid for 30 days

3. Cloud-Native IAM Bridges

AWS EC2 Instance Connect demonstrates cloud provider integrations:

# Push temporary key via AWS CLI
aws ec2-instance-connect send-ssh-public-key \
  --instance-id i-1234567890 \
  --availability-zone us-west-2a \
  --instance-os-user ec2-user \
  --ssh-public-key file://my_key.pub

Implementing periodic key rotation prevents stale credentials:

#!/bin/bash
# Monthly key rotation script
for user in $(getent passwd | grep '/home' | cut -d: -f1); do
  rotate_key "$user" --expiry 30 --notify-email "$user@company.com"
done

Centralized logging with fail2ban enhances security:

# /etc/fail2ban/jail.d/ssh.conf
[sshd]
enabled = true
maxretry = 3
findtime = 1h
bantime = 1d
logpath = /var/log/ssh_keys_audit.log

Managing SSH public keys across multiple systems with rotating team members creates significant operational overhead. Consider these common scenarios:

  • New team members require access to 15+ servers
  • Compromised keys need immediate revocation across all environments
  • Role changes demand granular permission updates

1. Ansible with Vault:

# ansible/playbooks/ssh_keys.yml
- hosts: all_servers
  vars_files:
    - vault/keys.yml
  tasks:
    - name: Deploy authorized_keys
      ansible.posix.authorized_key:
        user: "{{ deploy_user }}"
        state: present
        key: "{{ item }}"
      with_items: "{{ ssh_keys }}"

2. Puppet SSH Module:

# puppet/manifests/ssh_keys.pp
class ssh_keys {
  ssh_authorized_key { 'dev1@company':
    user => 'deploy',
    type => 'ssh-rsa',
    key  => 'AAAAB3Nza...',
  }
}

AWS Systems Manager example for EC2 instances:

# AWS CLI command
aws ssm send-command \
  --document-name "AWS-RunShellScript" \
  --parameters 'commands=["echo ssh-rsa AAAAB3... >> ~/.ssh/authorized_keys"]' \
  --instance-ids i-1234567890abcdef0

Python script with parallel execution:

import paramiko
from concurrent.futures import ThreadPoolExecutor

def update_key(host):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(host, username='keyupdater')
    
    with open('authorized_keys', 'r') as f:
        key_content = f.read()
    
    sftp = ssh.open_sftp()
    with sftp.file('/home/user/.ssh/authorized_keys', 'w') as f:
        f.write(key_content)
    
    ssh.close()

hosts = ['server1', 'server2', 'server3']
with ThreadPoolExecutor(max_workers=10) as executor:
    executor.map(update_key, hosts)
  • Implement key expiration policies
  • Use certificate-based SSH when possible
  • Audit logs for all key modifications
  • Enforce MFA for key rotation procedures