From c843085a02d4571ad2e5b9d7ec55283998c60ff5 Mon Sep 17 00:00:00 2001 From: Clark Boylan Date: Wed, 15 Nov 2023 10:16:26 -0800 Subject: [PATCH] Add ssh key rotation to gitea ssh key management This change refactors how gerrit's key(s) in gitea are managed. The motivation behind this is to allow us to do key rotation with overlap in accepted keys. To do this we first check whcih keys are present. Then any missing keys are added. Finally we remove any keys which are not in our key options. This also corrects a bug where replacing keys would've required two Ansible passed to delete the old key then add the new key. All keys should be properly set in a single Ansible pass with this update. Change-Id: I1eaf5ae89542e3e4f479c77e4df72a34d65d9c46 --- inventory/service/group_vars/gitea.yaml | 6 ++- playbooks/roles/gitea/tasks/main.yaml | 70 +++++++++++++++++++------ 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/inventory/service/group_vars/gitea.yaml b/inventory/service/group_vars/gitea.yaml index 16ca146016..2456f32af7 100644 --- a/inventory/service/group_vars/gitea.yaml +++ b/inventory/service/group_vars/gitea.yaml @@ -1,5 +1,9 @@ gitea_root_email: infra-root@openstack.org -gitea_gerrit_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVuhTMAz1H2Jr9AC3py9A0vlNna6Sdt4yrvZOayxukPqQ7GPZd+Mo7MVyypxLD479N2mA09JAdsbq1eTiPP8ksEkB+dNxZzw8mY1653R/IXSW6J9xPcoDa88HF2s/xHN24IWzgiDjNNe79AQ+sKleByEQZ++xXny3MRpy258hKUvAtjjOLOnM1PBs8JNOzBL+UPgWRgSX6GG0qywJZqjD1Qx5kvH9RTRLi+tcMhEi4laN7BYvn4csY0sYzTzPG4ZTu3ootIJoRlQGtQ0LmoFO1vSwyEJUags6/ZZGjgy3jl3kwcU/b8ZnFlF4MDw1OB1QqMb4r6bMHbXNIupp4zJbz gerrit-replication-2014-04-25 +# Gerrit replication key(s). When these values are identical only one key +# is created in Gitea. When they are different two different keys are added. +# This allows for key rotation. +gitea_gerrit_public_key_A: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVuhTMAz1H2Jr9AC3py9A0vlNna6Sdt4yrvZOayxukPqQ7GPZd+Mo7MVyypxLD479N2mA09JAdsbq1eTiPP8ksEkB+dNxZzw8mY1653R/IXSW6J9xPcoDa88HF2s/xHN24IWzgiDjNNe79AQ+sKleByEQZ++xXny3MRpy258hKUvAtjjOLOnM1PBs8JNOzBL+UPgWRgSX6GG0qywJZqjD1Qx5kvH9RTRLi+tcMhEi4laN7BYvn4csY0sYzTzPG4ZTu3ootIJoRlQGtQ0LmoFO1vSwyEJUags6/ZZGjgy3jl3kwcU/b8ZnFlF4MDw1OB1QqMb4r6bMHbXNIupp4zJbz gerrit-replication-2014-04-25 +gitea_gerrit_public_key_B: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVuhTMAz1H2Jr9AC3py9A0vlNna6Sdt4yrvZOayxukPqQ7GPZd+Mo7MVyypxLD479N2mA09JAdsbq1eTiPP8ksEkB+dNxZzw8mY1653R/IXSW6J9xPcoDa88HF2s/xHN24IWzgiDjNNe79AQ+sKleByEQZ++xXny3MRpy258hKUvAtjjOLOnM1PBs8JNOzBL+UPgWRgSX6GG0qywJZqjD1Qx5kvH9RTRLi+tcMhEi4laN7BYvn4csY0sYzTzPG4ZTu3ootIJoRlQGtQ0LmoFO1vSwyEJUags6/ZZGjgy3jl3kwcU/b8ZnFlF4MDw1OB1QqMb4r6bMHbXNIupp4zJbz gerrit-replication-2014-04-25 iptables_extra_public_tcp_ports: - 222 - 3000 diff --git a/playbooks/roles/gitea/tasks/main.yaml b/playbooks/roles/gitea/tasks/main.yaml index 025f077cf5..666e275514 100644 --- a/playbooks/roles/gitea/tasks/main.yaml +++ b/playbooks/roles/gitea/tasks/main.yaml @@ -119,7 +119,7 @@ send_notify: false source_id: 0 username: gerrit -- name: Check if gerrit ssh key exists +- name: List keys to determine which updates are necessary. uri: user: root password: "{{ gitea_root_password }}" @@ -129,19 +129,17 @@ status_code: 200 register: gerrit_key_check no_log: true -- name: Delete old gerrit ssh key - when: gerrit_key_check.json | length > 0 and gerrit_key_check.json[0].key != gitea_gerrit_public_key - no_log: true - uri: - user: root - password: "{{ gitea_root_password }}" - force_basic_auth: true - url: "https://localhost:3000/api/v1/user/keys/{{ gerrit_key_check.json[0].id }}" - validate_certs: false - method: DELETE - status_code: 204 -- name: Add gerrit ssh key - when: gerrit_key_check.json | length == 0 +# We want to allow for multiple keys in order to do key rotations. +# Check if both keys are present. If a key is not present then add it +# to Gitea. Keep in mind the two keys may be the same in which case +# we can skip the second key creation. Finally clean up any keys +# that don't match the two keys. This allows us to do key rotations. +- name: Determine if key A and key B are already present + set_fact: + key_A_present: "{{ gerrit_key_check.json | selectattr('key', 'equalto', gitea_gerrit_public_key_A ) | list | length > 0 }}" + key_B_present: "{{ gerrit_key_check.json | selectattr('key', 'equalto', gitea_gerrit_public_key_B ) | list | length > 0 }}" +- name: Add gerrit ssh key A + when: not key_A_present no_log: true uri: user: root @@ -153,9 +151,49 @@ status_code: 201 body_format: json body: - key: "{{ gitea_gerrit_public_key }}" + key: "{{ gitea_gerrit_public_key_A }}" read_only: false - title: "Gerrit replication key" + title: "Gerrit replication key A" +- name: Add gerrit ssh key B + when: not key_B_present and gitea_gerrit_public_key_A != gitea_gerrit_public_key_B + no_log: true + uri: + user: root + password: "{{ gitea_root_password }}" + force_basic_auth: true + url: "https://localhost:3000/api/v1/admin/users/gerrit/keys" + validate_certs: false + method: POST + status_code: 201 + body_format: json + body: + key: "{{ gitea_gerrit_public_key_B }}" + read_only: false + title: "Gerrit replication key B" +- name: List keys again to ensure key ids are correct for deletion. + uri: + user: root + password: "{{ gitea_root_password }}" + force_basic_auth: true + url: "https://localhost:3000/api/v1/users/gerrit/keys" + validate_certs: false + status_code: 200 + register: gerrit_key_check + no_log: true +- name: Delete old gerrit ssh keys + when: existing_pubkey.key != gitea_gerrit_public_key_A and existing_pubkey.key != gitea_gerrit_public_key_B + no_log: true + uri: + user: root + password: "{{ gitea_root_password }}" + force_basic_auth: true + url: "https://localhost:3000/api/v1/user/keys/{{ existing_pubkey.id }}" + validate_certs: false + method: DELETE + status_code: 204 + loop: "{{ gerrit_key_check.json }}" + loop_control: + loop_var: existing_pubkey - name: Set up cron job to pack git refs cron: name: pack-git-refs