From 20344bdebe24d2ff27a78d6ccc680dd4af5d5732 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Sun, 10 Nov 2024 17:07:14 +0100 Subject: [PATCH] feat: add automatic reload of vault service for certificate reloading This feature adds logic to automatically reload the vault service if tls is enbabled and the certificates have changed. This only tracks certificates copied by the extra_files logic. --- roles/vault/tasks/configure.yml | 66 +++++++++++++++++++++++++++++++++ roles/vault/tasks/install.yml | 2 +- roles/vault/tasks/main.yml | 14 ++++++- roles/vault/vars/main.yml | 16 ++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/roles/vault/tasks/configure.yml b/roles/vault/tasks/configure.yml index a8fe340..a4f71e0 100644 --- a/roles/vault/tasks/configure.yml +++ b/roles/vault/tasks/configure.yml @@ -24,6 +24,31 @@ when: _vault_env_file.changed or _vault_config_file.changed +- name: "Vault | Gather initial checksums for certificate files" + ansible.builtin.stat: + path: "{{ item }}" + checksum_algorithm: sha1 + loop: "{{ vault_certificates_reload_watchlist }}" + when: vault_enable_tls + register: _vault_initial_cert_checksums + +- name: "Vault | Normalize initial checksums" + ansible.builtin.set_fact: + # This needs to be optimized, but I have spent so much time on it not + # working that I will keep it as is for now, and we'll see later. + _vault_initial_checksums_normalized: >- + {% filter trim %} + {% set checksums = [] %} + {% for item in _vault_initial_cert_checksums.results %} + {% set _ = checksums.append({ + 'item': item.item, + 'initial_checksum': (item.stat.checksum | default('absent')) + }) %} + {% endfor %} + {{ checksums }} + {% endfilter %} + when: vault_enable_tls + - name: "Vault | Copy extra configuration files" when: vault_extra_files block: @@ -72,3 +97,44 @@ loop_control: loop_var: dir_source_item when: _vault_dir_sources is defined + +- name: "Vault | Gather final checksums for certificate files" + ansible.builtin.stat: + path: "{{ item }}" + checksum_algorithm: sha1 + loop: "{{ vault_certificates_reload_watchlist }}" + when: vault_enable_tls + register: _vault_final_cert_checksums + +- name: "Vault | Normalize final checksums" + ansible.builtin.set_fact: + # This needs to be optimized, but I have spent so much time on it not + # working that I will keep it as is for now, and we'll see later. + _vault_final_checksums_normalized: >- + {% filter trim %} + {% set checksums = [] %} + {% for item in _vault_final_cert_checksums.results %} + {% set _ = checksums.append({ + 'item': item.item, + 'final_checksum': (item.stat.checksum | default('absent')) + }) %} + {% endfor %} + {{ checksums }} + {% endfilter %} + when: vault_enable_tls + +- name: "Vault | Merge initial and final checksum lists" + ansible.builtin.set_fact: + _vault_checksums_list: >- + {{ + _vault_initial_checksums_normalized | + community.general.lists_mergeby(_vault_final_checksums_normalized, 'item') + }} + when: vault_enable_tls + +- name: "Vault | Determine if certificates have changed or were newly added" + ansible.builtin.set_fact: + _vault_service_need_reload: true + when: + - vault_enable_tls + - _vault_checksums_list | json_query('[?initial_checksum!=final_checksum]') | list| length > 0 diff --git a/roles/vault/tasks/install.yml b/roles/vault/tasks/install.yml index 0e61b73..0fc88b5 100644 --- a/roles/vault/tasks/install.yml +++ b/roles/vault/tasks/install.yml @@ -137,7 +137,7 @@ - name: "Vault | Set reload-check & restart-check variable" ansible.builtin.set_fact: - _vault_service_need_reload: true + _vault_service_need_daemon_reload: true _vault_service_need_restart: true when: _vault_unit_file.changed # noqa: no-handler diff --git a/roles/vault/tasks/main.yml b/roles/vault/tasks/main.yml index 89aa5ba..aecbb10 100644 --- a/roles/vault/tasks/main.yml +++ b/roles/vault/tasks/main.yml @@ -2,6 +2,7 @@ # task/main file for vault - name: "Vault | Set reload-check & restart-check variable" ansible.builtin.set_fact: + _vault_service_need_daemon_reload: false _vault_service_need_reload: false _vault_service_need_restart: false @@ -33,13 +34,24 @@ - name: "Vault | Reload systemd daemon" ansible.builtin.systemd: daemon_reload: true - when: _vault_service_need_reload + when: _vault_service_need_daemon_reload - name: "Vault | Start service: {{ vault_service_name }}" ansible.builtin.include_tasks: rolling_restart.yml when: + - vault_start_service - _vault_service_need_restart - "hostvars[host_item].inventory_hostname == inventory_hostname" with_items: "{{ ansible_play_batch }}" loop_control: loop_var: host_item + +- name: "Vault | Reload service: {{ vault_service_name }}" + ansible.builtin.service: + name: "{{ vault_service_name }}" + state: reloaded + throttle: 1 + when: + - vault_start_service + - _vault_service_need_reload + - not _vault_service_need_restart diff --git a/roles/vault/vars/main.yml b/roles/vault/vars/main.yml index 4d990f5..be12d70 100644 --- a/roles/vault/vars/main.yml +++ b/roles/vault/vars/main.yml @@ -15,6 +15,22 @@ vault_github_project: hashicorp/vault vault_github_url: https://github.com vault_repository_url: https://releases.hashicorp.com/vault +vault_certificates_reload_watchlist: | + {% filter trim %} + {% set watchlist = [] %} + {% for listener in vault_configuration.listener %} + {% if listener.get('tcp') %} + {% for key in ['tls_key_file', 'tls_cert_file', 'tls_client_ca_file'] %} + {% if listener['tcp'].get(key) %} + {{ watchlist.append(listener['tcp'][key]) }} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} + {{ watchlist | unique }} + {% endfilter %} + + vault_configuration: cluster_name: "{{ vault_cluster_name }}" cluster_addr: "{{ 'https' if vault_enable_tls else 'http'}}://{{ vault_cluster_addr }}:8201"