diff --git a/etc/kayobe/ansible/rekey-hosts.yml b/etc/kayobe/ansible/rekey-hosts.yml new file mode 100644 index 000000000..a72da3ac7 --- /dev/null +++ b/etc/kayobe/ansible/rekey-hosts.yml @@ -0,0 +1,117 @@ +--- +# Playbook to rotate SSH keys across the cloud. By default it will rotate the +# standard keys used by kayobe/kolla-ansible, but it can be configured for any +# keys. + +- name: Rekey hosts + hosts: overcloud,seed,seed-hypervisor,infra-vms + gather_facts: false + vars: + # The existing key is the key that is currently used to access overcloud hosts + existing_private_key_path: "{{ ssh_private_key_path }}" + existing_public_key_path: "{{ ssh_public_key_path }}" + # The new key is the key that will be generated by this playbook + new_private_key_path: "{{ ssh_private_key_path }}" + new_public_key_path: "{{ ssh_public_key_path }}" + new_key_type: "{{ ssh_key_type }}" + # The existing key will locally be moved to deprecated_key_path once it is replaced + deprecated_key_path: ~/old_ssh_key + rekey_users: + - stack + - kolla + rekey_remove_existing_key: false + tasks: + - name: Stat existing private key file + ansible.builtin.stat: + path: "{{ existing_private_key_path }}" + register: stat_result + delegate_to: localhost + run_once: true + + - name: Fail when existing private key does not exist + ansible.builtin.fail: + msg: "No existing private key file found. Check existing_private_key_path is set correctly." + when: + - not stat_result.stat.exists + delegate_to: localhost + run_once: true + + - name: Stat existing public key file + ansible.builtin.stat: + path: "{{ existing_public_key_path }}" + register: stat_result + delegate_to: localhost + run_once: true + + - name: Fail when existing public key does not exist + ansible.builtin.fail: + msg: "No existing public key file found. Check existing_public_key_path is set correctly." + when: + - not stat_result.stat.exists + delegate_to: localhost + run_once: true + + - name: Generate a new SSH key + community.crypto.openssh_keypair: + path: "{{ existing_private_key_path }}_new" + type: "{{ new_key_type }}" + delegate_to: localhost + run_once: true + + - name: Set new authorized keys + vars: + lookup_path: "{{ existing_private_key_path }}_new.pub" + ansible.posix.authorized_key: + user: "{{ item }}" + state: present + key: "{{ lookup('file', lookup_path) }}" + loop: "{{ rekey_users }}" + become: true + + - name: Locally deprecate existing key (private) + command: "mv {{ existing_private_key_path }} {{ deprecated_key_path }}" + delegate_to: localhost + run_once: true + + - name: Locally deprecate existing key (public) + command: "mv {{ existing_public_key_path }} {{ deprecated_key_path }}.pub" + delegate_to: localhost + run_once: true + + - name: Locally promote new key (private) + command: "mv {{ existing_private_key_path }}_new {{ new_private_key_path }}" + delegate_to: localhost + run_once: true + + - name: Locally promote new key (public) + command: "mv {{ existing_private_key_path }}_new.pub {{ new_public_key_path }}" + delegate_to: localhost + run_once: true + + - block: + - name: Stat old key file + ansible.builtin.stat: + path: "{{ deprecated_key_path }}.pub" + register: stat_result + delegate_to: localhost + run_once: true + + - name: Fail when deprecated public key does not exist + ansible.builtin.fail: + msg: "No deprecated public key file found. Check deprecated_key_path is set correctly." + when: + - not stat_result.stat.exists + delegate_to: localhost + run_once: true + + - name: Remove old key from hosts + vars: + lookup_path: "{{ deprecated_key_path }}.pub" + ansible.posix.authorized_key: + user: "{{ item }}" + state: absent + key: "{{ lookup('file', lookup_path) }}" + loop: "{{ rekey_users }}" + become: true + tags: remove-key + when: rekey_remove_existing_key | bool diff --git a/releasenotes/notes/add-rekey-playbook-0065c5057b1639f8.yaml b/releasenotes/notes/add-rekey-playbook-0065c5057b1639f8.yaml new file mode 100644 index 000000000..5e75a51ad --- /dev/null +++ b/releasenotes/notes/add-rekey-playbook-0065c5057b1639f8.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Added the ``rekey-hosts.yml`` playbook to automatically rotate the SSH + keys on all hosts.