Automated Key Distribution

Automated Key Distribution

Manual key distribution doesn't scale and introduces security risks. Automated distribution systems ensure keys reach authorized systems quickly and securely while maintaining audit trails and access controls.

Implement automated key distribution:

#!/bin/bash
# ssh-key-distribution.sh
# Automated SSH key distribution system

# Configuration
DISTRIBUTION_CONFIG="/etc/ssh-distribution/config.json"
ANSIBLE_INVENTORY="/etc/ansible/hosts"
DISTRIBUTION_LOG="/var/log/ssh-key-distribution.log"

# Load distribution rules from configuration
load_distribution_rules() {
    if [ ! -f "$DISTRIBUTION_CONFIG" ]; then
        cat > "$DISTRIBUTION_CONFIG" << 'EOF'
{
    "distribution_rules": [
        {
            "key_pattern": "dev-*",
            "target_groups": ["development_servers"],
            "target_users": ["devuser"],
            "key_options": "no-port-forwarding,no-X11-forwarding"
        },
        {
            "key_pattern": "prod-*",
            "target_groups": ["production_servers"],
            "target_users": ["produser"],
            "key_options": "from=\"10.0.0.0/8\",no-port-forwarding"
        },
        {
            "key_pattern": "admin-*",
            "target_groups": ["all_servers"],
            "target_users": ["root", "admin"],
            "key_options": ""
        }
    ],
    "notification_endpoints": [
        "https://slack.webhook.url",
        "[email protected]"
    ]
}
EOF
    fi
    
    echo "$DISTRIBUTION_CONFIG"
}

# Distribute key to target systems
distribute_key() {
    local key_id=$1
    local public_key=$2
    local key_options=$3
    local target_groups=$4
    local target_users=$5
    
    log "Starting distribution of key $key_id"
    
    # Create Ansible playbook for distribution
    cat > "/tmp/distribute_key_${key_id}.yml" << EOF
---
- name: Distribute SSH Key ${key_id}
  hosts: ${target_groups}
  become: yes
  tasks:
    - name: Ensure .ssh directory exists
      file:
        path: "/home/{{ item }}/.ssh"
        state: directory
        owner: "{{ item }}"
        group: "{{ item }}"
        mode: '0700'
      loop: ${target_users}
      
    - name: Add public key to authorized_keys
      lineinfile:
        path: "/home/{{ item }}/.ssh/authorized_keys"
        line: "${key_options} ${public_key} ${key_id}"
        create: yes
        owner: "{{ item }}"
        group: "{{ item }}"
        mode: '0600'
      loop: ${target_users}
      
    - name: Log key distribution
      lineinfile:
        path: "/var/log/ssh_keys_distributed.log"
        line: "{{ ansible_date_time.iso8601 }} - Added key ${key_id} for users ${target_users}"
        create: yes
EOF
    
    # Execute distribution
    ansible-playbook -i "$ANSIBLE_INVENTORY" "/tmp/distribute_key_${key_id}.yml" \
        --extra-vars "ansible_ssh_private_key_file=/opt/ssh-distribution/deploy_key" \
        >> "$DISTRIBUTION_LOG" 2>&1
    
    local result=$?
    
    # Clean up
    rm -f "/tmp/distribute_key_${key_id}.yml"
    
    if [ $result -eq 0 ]; then
        log "Successfully distributed key $key_id"
        send_notification "success" "Key $key_id distributed successfully"
    else
        log "ERROR: Failed to distribute key $key_id"
        send_notification "failure" "Key $key_id distribution failed"
    fi
    
    return $result
}

# Remove key from all systems
remove_key_distribution() {
    local key_id=$1
    
    log "Removing key $key_id from all systems"
    
    # Create removal playbook
    cat > "/tmp/remove_key_${key_id}.yml" << EOF
---
- name: Remove SSH Key ${key_id}
  hosts: all
  become: yes
  tasks:
    - name: Find authorized_keys files
      find:
        paths: ["/home", "/root"]
        patterns: "authorized_keys"
        recurse: yes
      register: auth_keys_files
      
    - name: Remove key from authorized_keys
      lineinfile:
        path: "{{ item.path }}"
        regexp: ".*${key_id}$"
        state: absent
      loop: "{{ auth_keys_files.files }}"
      
    - name: Log key removal
      lineinfile:
        path: "/var/log/ssh_keys_removed.log"
        line: "{{ ansible_date_time.iso8601 }} - Removed key ${key_id}"
        create: yes
EOF
    
    # Execute removal
    ansible-playbook -i "$ANSIBLE_INVENTORY" "/tmp/remove_key_${key_id}.yml" \
        >> "$DISTRIBUTION_LOG" 2>&1
    
    rm -f "/tmp/remove_key_${key_id}.yml"
    
    log "Key $key_id removed from all systems"
}

# Monitor key distribution health
monitor_distribution_health() {
    log "Checking key distribution health..."
    
    # Create health check playbook
    cat > "/tmp/key_health_check.yml" << 'EOF'
---
- name: SSH Key Distribution Health Check
  hosts: all
  become: yes
  gather_facts: no
  tasks:
    - name: Check authorized_keys files
      find:
        paths: ["/home", "/root"]
        patterns: "authorized_keys"
        recurse: yes
      register: auth_keys_files
      
    - name: Validate authorized_keys permissions
      stat:
        path: "{{ item.path }}"
      loop: "{{ auth_keys_files.files }}"
      register: file_stats
      
    - name: Report issues
      debug:
        msg: "WARNING: {{ item.stat.path }} has incorrect permissions {{ item.stat.mode }}"
      when: item.stat.mode != "0600"
      loop: "{{ file_stats.results }}"
EOF
    
    # Run health check
    ansible-playbook -i "$ANSIBLE_INVENTORY" "/tmp/key_health_check.yml" \
        >> "$DISTRIBUTION_LOG" 2>&1
    
    rm -f "/tmp/key_health_check.yml"
}

# Sync keys with identity provider
sync_with_identity_provider() {
    log "Syncing SSH keys with identity provider..."
    
    # Example: Sync with LDAP
    ldapsearch -x -H ldap://ldap.example.com \
        -D "cn=admin,dc=example,dc=com" \
        -w "$LDAP_PASSWORD" \
        -b "ou=users,dc=example,dc=com" \
        "(objectClass=posixAccount)" \
        uid sshPublicKey | \
    while read -r line; do
        if [[ $line =~ ^uid:\ (.+) ]]; then
            current_user="${BASH_REMATCH[1]}"
        elif [[ $line =~ ^sshPublicKey:\ (.+) ]]; then
            ssh_key="${BASH_REMATCH[1]}"
            
            # Distribute key for user
            distribute_key "ldap-$current_user" "$ssh_key" "" "all_servers" "[$current_user]"
        fi
    done
}