--- # fix-ssh-host-keys.yaml # # Detects cloned VMs that share the same SSH host key and regenerates a # unique key set on each one, then refreshes the controller's known_hosts. # # Run with host key checking disabled for this one remediation pass, # since known_hosts is currently in a conflicted state: # # ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook fix-ssh-host-keys.yaml # # The `duplicate_fingerprint` guard means only hosts presenting the shared # key get touched. Hosts with an already-unique key are left alone. - name: Regenerate shared SSH host keys on cloned guests hosts: all become: true gather_facts: false vars: # The shared key every clone is currently presenting. duplicate_fingerprint: "SHA256:AZekUU+Wwn6S6sCjGD0SdkhVgj3WVqVdiVYa1AXYW8A" tasks: - name: Read current ED25519 host key fingerprint ansible.builtin.command: cmd: ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub register: hostkey_fp changed_when: false failed_when: false - name: Regenerate host keys if this host shares the duplicate key when: duplicate_fingerprint in (hostkey_fp.stdout | default('')) block: - name: Remove existing host keys ansible.builtin.shell: cmd: rm -f /etc/ssh/ssh_host_* # rm on a glob isn't idempotent-reportable; treat as changed. changed_when: true - name: Generate a fresh unique set of host keys ansible.builtin.command: cmd: ssh-keygen -A changed_when: true - name: Restart SSH so the new key is served ansible.builtin.service: name: ssh state: restarted - name: Note that this host was remediated ansible.builtin.debug: msg: "{{ inventory_hostname }} had the shared key and was regenerated." - name: Refresh known_hosts on the Ansible controller hosts: localhost gather_facts: false vars: known_hosts_path: "{{ lookup('env', 'HOME') }}/.ssh/known_hosts" target_hosts: "{{ groups['all'] | difference(['localhost']) }}" tasks: - name: Remove stale entries for every managed host ansible.builtin.command: cmd: "ssh-keygen -f {{ known_hosts_path }} -R {{ item }}" loop: "{{ target_hosts }}" changed_when: false - name: Rescan and add current keys ansible.builtin.shell: cmd: "ssh-keyscan -t ed25519,rsa,ecdsa {{ item }} >> {{ known_hosts_path }}" loop: "{{ target_hosts }}" changed_when: true