|
| 1 | +--- |
| 2 | +# Playbook to rotate SSH keys across the cloud. By default it will rotate the |
| 3 | +# standard keys used by kayobe/kolla-ansible, but it can be configured for any |
| 4 | +# keys. |
| 5 | + |
| 6 | +- name: Rekey hosts |
| 7 | + hosts: overcloud,seed,seed-hypervisor,infra-vms |
| 8 | + gather_facts: false |
| 9 | + vars: |
| 10 | + # The existing key is the key that is currently used to access overcloud hosts |
| 11 | + existing_private_key_path: "{{ ssh_private_key_path }}" |
| 12 | + existing_public_key_path: "{{ ssh_public_key_path }}" |
| 13 | + # The new key is the key that will be generated by this playbook |
| 14 | + new_private_key_path: "{{ ssh_private_key_path }}" |
| 15 | + new_public_key_path: "{{ ssh_public_key_path }}" |
| 16 | + new_key_type: "{{ ssh_key_type }}" |
| 17 | + # The existing key will locally be moved to deprecated_key_path once it is replaced |
| 18 | + deprecated_key_path: ~/old_ssh_key |
| 19 | + rekey_users: |
| 20 | + - stack |
| 21 | + - kolla |
| 22 | + rekey_remove_existing_key: false |
| 23 | + tasks: |
| 24 | + - name: Stat existing private key file |
| 25 | + ansible.builtin.stat: |
| 26 | + path: "{{ existing_private_key_path }}" |
| 27 | + register: stat_result |
| 28 | + delegate_to: localhost |
| 29 | + run_once: true |
| 30 | + |
| 31 | + - name: Fail when existing private key does not exist |
| 32 | + ansible.builtin.fail: |
| 33 | + msg: "No existing private key file found. Check existing_private_key_path is set correctly." |
| 34 | + when: |
| 35 | + - not stat_result.stat.exists |
| 36 | + delegate_to: localhost |
| 37 | + run_once: true |
| 38 | + |
| 39 | + - name: Stat existing public key file |
| 40 | + ansible.builtin.stat: |
| 41 | + path: "{{ existing_public_key_path }}" |
| 42 | + register: stat_result |
| 43 | + delegate_to: localhost |
| 44 | + run_once: true |
| 45 | + |
| 46 | + - name: Fail when existing public key does not exist |
| 47 | + ansible.builtin.fail: |
| 48 | + msg: "No existing public key file found. Check existing_public_key_path is set correctly." |
| 49 | + when: |
| 50 | + - not stat_result.stat.exists |
| 51 | + delegate_to: localhost |
| 52 | + run_once: true |
| 53 | + |
| 54 | + - name: Generate a new SSH key |
| 55 | + community.crypto.openssh_keypair: |
| 56 | + path: "{{ existing_private_key_path }}_new" |
| 57 | + type: "{{ new_key_type }}" |
| 58 | + delegate_to: localhost |
| 59 | + run_once: true |
| 60 | + |
| 61 | + - name: Set new authorized keys |
| 62 | + vars: |
| 63 | + lookup_path: "{{ existing_private_key_path }}_new.pub" |
| 64 | + ansible.posix.authorized_key: |
| 65 | + user: "{{ item }}" |
| 66 | + state: present |
| 67 | + key: "{{ lookup('file', lookup_path) }}" |
| 68 | + loop: "{{ rekey_users }}" |
| 69 | + become: true |
| 70 | + |
| 71 | + - name: Locally deprecate existing key (private) |
| 72 | + command: "mv {{ existing_private_key_path }} {{ deprecated_key_path }}" |
| 73 | + delegate_to: localhost |
| 74 | + run_once: true |
| 75 | + |
| 76 | + - name: Locally deprecate existing key (public) |
| 77 | + command: "mv {{ existing_public_key_path }} {{ deprecated_key_path }}.pub" |
| 78 | + delegate_to: localhost |
| 79 | + run_once: true |
| 80 | + |
| 81 | + - name: Locally promote new key (private) |
| 82 | + command: "mv {{ existing_private_key_path }}_new {{ new_private_key_path }}" |
| 83 | + delegate_to: localhost |
| 84 | + run_once: true |
| 85 | + |
| 86 | + - name: Locally promote new key (public) |
| 87 | + command: "mv {{ existing_private_key_path }}_new.pub {{ new_public_key_path }}" |
| 88 | + delegate_to: localhost |
| 89 | + run_once: true |
| 90 | + |
| 91 | + - block: |
| 92 | + - name: Stat old key file |
| 93 | + ansible.builtin.stat: |
| 94 | + path: "{{ deprecated_key_path }}.pub" |
| 95 | + register: stat_result |
| 96 | + delegate_to: localhost |
| 97 | + run_once: true |
| 98 | + |
| 99 | + - name: Fail when deprecated public key does not exist |
| 100 | + ansible.builtin.fail: |
| 101 | + msg: "No deprecated public key file found. Check deprecated_key_path is set correctly." |
| 102 | + when: |
| 103 | + - not stat_result.stat.exists |
| 104 | + delegate_to: localhost |
| 105 | + run_once: true |
| 106 | + |
| 107 | + - name: Remove old key from hosts |
| 108 | + vars: |
| 109 | + lookup_path: "{{ deprecated_key_path }}.pub" |
| 110 | + ansible.posix.authorized_key: |
| 111 | + user: "{{ item }}" |
| 112 | + state: absent |
| 113 | + key: "{{ lookup('file', lookup_path) }}" |
| 114 | + loop: "{{ rekey_users }}" |
| 115 | + become: true |
| 116 | + tags: remove-key |
| 117 | + when: rekey_remove_existing_key | bool |
0 commit comments