Deploy SSH Keys

This role deploys SSH public keys to user accounts on target systems. It verifies user existence, creates necessary `.

ARA Ansible Bash Debian RedHat SSH YAML

Deploy SSH Keys Role

Overview

This role deploys SSH public keys to user accounts on target systems. It verifies user existence, creates necessary .ssh directories with proper permissions, adds public keys to authorized_keys files, and ensures correct ownership and permissions for SSH authentication to work properly.

Purpose

  • Automated Access: Deploy SSH keys for automated Ansible access
  • User Management: Configure SSH access for multiple users simultaneously
  • Security: Ensure proper file permissions (0700 for .ssh, 0600 for authorized_keys)
  • Idempotency: Safe to run multiple times without duplicating keys
  • Flexibility: Skip users that don’t exist on target system
  • Non-Exclusive: Adds keys without removing existing ones

Requirements

  • Ansible 2.9 or higher
  • SSH public key files stored in roles/deploy_ssh_keys/files/ directory
  • Target users must exist on the system (role checks and skips non-existent users)
  • Proper sudo/root permissions to modify user home directories

Role Variables

Required Variables

This role has no required variables - it uses defaults that can be overridden.

Optional Variables

VariableDefaultDescription
deploy_ssh_keys_usersSee defaultsList of user configurations with SSH keys
deploy_ssh_keys_ssh_dir_mode0700Permission mode for .ssh directory
deploy_ssh_keys_authorized_keys_mode0600Permission mode for authorized_keys file

Variable Details

deploy_ssh_keys_users

List of user configurations specifying which SSH keys to deploy to which users.

Structure:

deploy_ssh_keys_users:
  - username: user_account_name
    key_file: public_key_filename.pub
    comment: "Description of this key"

Default configuration:

deploy_ssh_keys_users:
  - username: ansibleuser
    key_file: ansible_user.pub
    comment: "Ansible automation key from mint-vm"
  - username: bjoffrey
    key_file: bjoffrey_user.pub
    comment: "bjoffrey interactive SSH key (PuTTY)"

Example custom configuration:

deploy_ssh_keys_users:
  - username: webadmin
    key_file: webadmin_rsa.pub
    comment: "Web server administrator key"
  - username: deploy
    key_file: deploy_ed25519.pub
    comment: "CI/CD deployment key"
  - username: backup
    key_file: backup_rsa.pub
    comment: "Backup automation key"

deploy_ssh_keys_ssh_dir_mode

Permission mode for the .ssh directory. Must be 0700 for SSH to accept it.

Example:

deploy_ssh_keys_ssh_dir_mode: '0700'

deploy_ssh_keys_authorized_keys_mode

Permission mode for the authorized_keys file. Must be 0600 or 0644 for SSH to accept it.

Example:

deploy_ssh_keys_authorized_keys_mode: '0600'

Dependencies

This role has no dependencies on other Ansible roles, but requires:

  • SSH public key files placed in roles/deploy_ssh_keys/files/ directory
  • Target user accounts already created on the system

Example Playbook

Basic Usage

---
- name: Deploy SSH Keys to All Hosts
  hosts: all
  become: true

  roles:
    - deploy_ssh_keys

With Custom Users

---
- name: Deploy SSH Keys for Custom Users
  hosts: webservers
  become: true

  vars:
    deploy_ssh_keys_users:
      - username: deploy
        key_file: deploy_key.pub
        comment: "Deployment automation key"
      - username: monitoring
        key_file: monitoring_key.pub
        comment: "Monitoring agent key"

  roles:
    - deploy_ssh_keys

For Specific Host Group

---
- name: Deploy Admin SSH Keys to Critical Infrastructure
  hosts: critical_infrastructure
  become: true

  vars:
    deploy_ssh_keys_users:
      - username: sysadmin
        key_file: sysadmin_ed25519.pub
        comment: "System administrator emergency access"

  roles:
    - deploy_ssh_keys

What This Role Does

  1. Checks user existence using getent for each configured user
  2. Filters to existing users (skips users not on system)
  3. Displays found users for verification
  4. Creates .ssh directories for each user with mode 0700
  5. Sets directory ownership to user:user
  6. Deploys public keys to authorized_keys using authorized_key module
  7. Preserves existing keys (exclusive: false)
  8. Adds key comments for identification
  9. Verifies file permissions on authorized_keys (mode 0600)
  10. Sets file ownership to user:user
  11. Displays success message with hostname

SSH Key File Structure

Directory Layout

roles/deploy_ssh_keys/files/
├── ansible_user.pub
├── bjoffrey_user.pub
├── deploy_key.pub
└── monitoring_key.pub

Public Key Format

Public keys should be in standard OpenSSH format:

RSA Example:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC... user@hostname

Ed25519 Example:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@hostname

User Existence Checking

The role intelligently handles non-existent users:

  1. Checks all users in deploy_ssh_keys_users list
  2. Uses getent passwd to verify existence
  3. Skips non-existent users without failing
  4. Processes only existing users

Example scenario:

deploy_ssh_keys_users:
  - username: ansibleuser  # Exists on all hosts
  - username: webadmin     # Only exists on webservers
  - username: dbadmin      # Only exists on databases

Result:

  • Web servers: Deploys keys for ansibleuser and webadmin
  • Database servers: Deploys keys for ansibleuser and dbadmin
  • Other servers: Deploys keys for ansibleuser only

Permissions and Ownership

Critical SSH Permissions

SSH is strict about file permissions. The role enforces:

PathModeOwnerGroup
~/.ssh/0700useruser
~/.ssh/authorized_keys0600useruser

Why these permissions:

  • 0700 on .ssh: Only owner can read/write/execute (SSH requirement)
  • 0600 on authorized_keys: Only owner can read/write (SSH security)
  • User ownership: SSH refuses to use files owned by wrong user

Permission Verification

The role explicitly verifies permissions after deployment using the file module to ensure SSH will accept the configuration.

Non-Exclusive Key Management

The role uses exclusive: false in the authorized_key module:

  • Preserves existing keys: Does not remove manually added keys
  • Adds new keys: Appends configured keys to file
  • Idempotent: Running multiple times doesn’t duplicate keys
  • Safe: Won’t lock out users with existing keys

Key Comments

Each deployed key includes a comment for identification:

- username: deploy
  key_file: deploy_key.pub
  comment: "CI/CD deployment key"

Result in authorized_keys:

ssh-rsa AAAAB3NzaC1... CI/CD deployment key

Benefits:

  • Identify key purpose in authorized_keys file
  • Track which automation added the key
  • Easier key audit and management

Security Considerations

  • Public Keys Only: Role deploys public keys, private keys never leave secure storage
  • No Password Auth: Deploying SSH keys enables passwordless authentication
  • Proper Permissions: Enforces SSH security requirements
  • User Isolation: Keys owned by target user, not root
  • Non-Destructive: Doesn’t remove existing keys (preserves manual access)
  • Audit Trail: Key comments identify source and purpose

Tags

This role does not define any tags. Use playbook-level tags if needed:

- hosts: all
  roles:
    - deploy_ssh_keys
  tags:
    - ssh
    - access
    - security
    - users

Notes

  • Public key files must exist in roles/deploy_ssh_keys/files/ directory
  • Role requires become: true (root/sudo access)
  • SSH daemon must be running on target hosts
  • Role does not create user accounts (users must pre-exist)
  • Role does not modify SSH server configuration (sshd_config)
  • Works with any SSH key type (RSA, Ed25519, ECDSA, etc.)

Troubleshooting

”User does not exist” warnings

Symptom: User skipped, key not deployed

Solution: This is normal behavior. The role only deploys to existing users. Either:

  • Create the user account first (using user module)
  • Remove the user from deploy_ssh_keys_users list
  • Use host-specific variables to target correct users per host

SSH still prompts for password

Check:

  1. Verify public key in authorized_keys: cat ~/.ssh/authorized_keys
  2. Check file permissions: ls -la ~/.ssh/
  3. Verify SSH daemon allows key auth: grep PubkeyAuthentication /etc/ssh/sshd_config
  4. Check SSH logs: tail -f /var/log/secure (RedHat) or /var/log/auth.log (Debian)
  5. Test with verbose client: ssh -vvv user@host

Permission denied (publickey)

Common causes:

  • Wrong private key on client
  • Public key not in authorized_keys
  • Incorrect file permissions (fixed by role, but verify: ls -la ~/.ssh/)
  • SELinux context (RedHat): restorecon -R ~/.ssh/
  • Home directory permissions too open (should be 755 or 700)

File not found error

Error: Could not find or access 'files/key_file.pub'

Solution:

# Verify file exists
ls roles/deploy_ssh_keys/files/

# Add missing key file
cp /path/to/key.pub roles/deploy_ssh_keys/files/

“FAILED: invalid permissions on authorized_keys”

This error comes from SSH daemon, not the role. The role explicitly sets correct permissions, but check:

# Verify permissions
ls -la ~/.ssh/authorized_keys

# Should show: -rw------- (0600)
# If not, manually fix:
chmod 600 ~/.ssh/authorized_keys

Key Generation

To generate new SSH keys for use with this role:

RSA (Traditional, widely compatible)

ssh-keygen -t rsa -b 4096 -C "automation@homelab" -f ~/.ssh/automation_rsa
cp ~/.ssh/automation_rsa.pub roles/deploy_ssh_keys/files/
ssh-keygen -t ed25519 -C "automation@homelab" -f ~/.ssh/automation_ed25519
cp ~/.ssh/automation_ed25519.pub roles/deploy_ssh_keys/files/

Key Generation Best Practices

  • Use Ed25519 for modern systems (smaller, faster, more secure)
  • Use RSA 4096-bit for compatibility with older systems
  • Add meaningful comments with -C flag
  • Protect private keys (never commit to git, use ansible-vault if needed)
  • Use passphrases for interactive keys (not automation keys)

Testing SSH Key Authentication

After deploying keys:

# Test connection (should not prompt for password)
ssh user@target-host

# Test with specific key
ssh -i ~/.ssh/automation_rsa user@target-host

# Verbose test (shows authentication process)
ssh -vvv user@target-host

Integration with Ansible Automation

ansible.cfg Configuration

[defaults]
remote_user = ansibleuser
private_key_file = ~/.ssh/ansible_user

[privilege_escalation]
become = true
become_method = sudo
become_user = root

Inventory Configuration

all:
  vars:
    ansible_user: ansibleuser
    ansible_ssh_private_key_file: ~/.ssh/ansible_user

Best Practices

  1. Separate keys by purpose (interactive vs automation)
  2. Use descriptive filenames (e.g., ansible_automation.pub, admin_emergency.pub)
  3. Add meaningful comments for each key
  4. Test on single host before deploying widely
  5. Keep private keys secure (never in git repository)
  6. Rotate keys periodically (update public key files and re-run role)
  7. Document key owners in comments
  8. Use Ed25519 for new deployments
  9. Backup private keys securely (encrypted backup)
  10. Audit authorized_keys regularly

Alternative: Manual Deployment

If you prefer manual deployment:

# Copy public key to target
ssh-copy-id -i ~/.ssh/key.pub user@target-host

# Or manually
cat ~/.ssh/key.pub | ssh user@target-host \
  "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

This role is often used with:

  • User management roles: Create user accounts before deploying keys
  • Security hardening roles: Disable password auth, configure SSH daemon
  • Sudo configuration roles: Grant sudo access to automated users

License

MIT

Author

Created for homelab infrastructure management.