feat/renew-certificates #26

Merged
lanson merged 9 commits from feat/renew-certificates into main 2024-11-13 20:41:33 +00:00
16 changed files with 337 additions and 33 deletions

View File

@ -2,7 +2,7 @@
# defaults # defaults
hashistack_ca_directory: "{{ hashistack_sub_configuration_directories['certificates'] }}" hashistack_ca_directory: "{{ hashistack_sub_configuration_directories['certificates'] }}"
hashistack_ca_use_cryptography: false hashistack_ca_use_cryptography: false
hashistack_ca_action: "noop" # hashistack_ca_action: "noop"
hashistack_ca_domain: example.com hashistack_ca_domain: example.com
hashistack_ca_directory_owner: "{{ lookup('env', 'USER') }}" hashistack_ca_directory_owner: "{{ lookup('env', 'USER') }}"
@ -79,37 +79,52 @@ hashistack_ca_leaf_renew_threshold: 30d
############################ ############################
hashistack_ca_consul_org_name: "{{ hashistack_ca_root_org_name }}" hashistack_ca_consul_org_name: "{{ hashistack_ca_root_org_name }}"
hashistack_ca_consul_common_name: "{{ inventory_hostname }}" hashistack_ca_consul_common_name: "{{ inventory_hostname }}"
hashistack_ca_consul_csr_sans: hashistack_ca_consul_csr_sans: >
- "DNS:{{ inventory_hostname }}" {{
- "DNS:consul.service.consul" [
- "DNS:localhost" "DNS:" + inventory_hostname,
- "IP:{{ api_interface_address }}" "DNS:consul.service.consul",
- "IP:127.0.0.1" "DNS:localhost",
- "{{ 'DNS:server.' ~ consul_datacenter ~ '.' ~ consul_domain if consul_enable_server else omit }}" "IP:" + api_interface_address,
"IP:127.0.0.1"
]
+ ([ "DNS:server." + consul_datacenter + "." + consul_domain ] if consul_enable_server else [])
}}
########################### ###########################
# Nomad Leaf Certificates # # Nomad Leaf Certificates #
########################### ###########################
hashistack_ca_nomad_org_name: "{{ hashistack_ca_root_org_name }}" hashistack_ca_nomad_org_name: "{{ hashistack_ca_root_org_name }}"
hashistack_ca_nomad_common_name: "{{ inventory_hostname }}" hashistack_ca_nomad_common_name: "{{ inventory_hostname }}"
hashistack_ca_nomad_csr_sans: hashistack_ca_nomad_csr_sans: >
- "DNS:{{ inventory_hostname }}" {{
- "DNS:localhost" [
- "IP:{{ api_interface_address }}" "DNS:" + inventory_hostname,
- "IP:127.0.0.1" "DNS:localhost",
- "{{ 'DNS:server.' ~ nomad_region ~ '.nomad' if nomad_enable_server else omit }}" "IP:" + api_interface_address,
- "{{ 'DNS:nomad.service.consul' if (nomad_enable_server and enable_consul) else omit }}" "IP:127.0.0.1"
]
+ ([ "DNS:server." + nomad_region + ".nomad" ] if nomad_enable_server else [])
+ ([ "DNS:client." + nomad_region + ".nomad" ] if nomad_enable_client else [])
+ ([ "DNS:nomad.service.consul" ] if (nomad_enable_server and enable_consul) else [])
}}
########################### ###########################
# Vault Leaf Certificates # # Vault Leaf Certificates #
########################### ###########################
hashistack_ca_vault_org_name: "{{ hashistack_ca_root_org_name }}" hashistack_ca_vault_org_name: "{{ hashistack_ca_root_org_name }}"
hashistack_ca_vault_common_name: "{{ inventory_hostname }}" hashistack_ca_vault_common_name: "{{ inventory_hostname }}"
hashistack_ca_vault_csr_sans: hashistack_ca_vault_csr_sans: >
- "DNS:{{ inventory_hostname }}" {{
- "{{ 'DNS:active.vault.service.consul' if enable_consul else omit }}" [
- "{{ 'DNS:standby.vault.service.consul' if enable_consul else omit }}" "DNS:" + inventory_hostname,
- "{{ 'DNS:vault.service.consul' if enable_consul else omit }}" "DNS:localhost",
- "DNS:localhost" "IP:" + api_interface_address,
- "IP:{{ api_interface_address }}" "IP:127.0.0.1"
- "IP:127.0.0.1" ]
+ ([
"DNS:active.vault.service.consul",
"DNS:standby.vault.service.consul",
"DNS:vault.service.consul"
] if enable_consul else [])
}}

View File

@ -24,6 +24,31 @@
when: _consul_env_file.changed or when: _consul_env_file.changed or
_consul_config_file.changed _consul_config_file.changed
- name: "Consul | Gather initial checksums for certificate files"
ansible.builtin.stat:
path: "{{ item }}"
checksum_algorithm: sha1
loop: "{{ consul_certificates_reload_watchlist }}"
when: consul_enable_tls
register: _consul_initial_cert_checksums
- name: "Consul | 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.
_consul_initial_checksums_normalized: >-
{% filter trim %}
{% set checksums = [] %}
{% for item in _consul_initial_cert_checksums.results %}
{% set _ = checksums.append({
'item': item.item,
'initial_checksum': (item.stat.checksum | default('absent'))
}) %}
{% endfor %}
{{ checksums }}
{% endfilter %}
when: consul_enable_tls
- name: "Consul | Copy extra configuration files" - name: "Consul | Copy extra configuration files"
when: consul_extra_files when: consul_extra_files
block: block:
@ -72,3 +97,44 @@
loop_control: loop_control:
loop_var: dir_source_item loop_var: dir_source_item
when: _consul_dir_sources is defined when: _consul_dir_sources is defined
- name: "Consul | Gather final checksums for certificate files"
ansible.builtin.stat:
path: "{{ item }}"
checksum_algorithm: sha1
loop: "{{ consul_certificates_reload_watchlist }}"
when: consul_enable_tls
register: _consul_final_cert_checksums
- name: "Consul | 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.
_consul_final_checksums_normalized: >-
{% filter trim %}
{% set checksums = [] %}
{% for item in _consul_final_cert_checksums.results %}
{% set _ = checksums.append({
'item': item.item,
'final_checksum': (item.stat.checksum | default('absent'))
}) %}
{% endfor %}
{{ checksums }}
{% endfilter %}
when: consul_enable_tls
- name: "Consul | Merge initial and final checksum lists"
ansible.builtin.set_fact:
_consul_checksums_list: >-
{{
_consul_initial_checksums_normalized |
community.general.lists_mergeby(_consul_final_checksums_normalized, 'item')
}}
when: consul_enable_tls
- name: "Consul | Determine if certificates have changed or were newly added"
ansible.builtin.set_fact:
_consul_service_need_reload: true
when:
- consul_enable_tls
- _consul_checksums_list | json_query('[?initial_checksum!=final_checksum]') | list| length > 0

View File

@ -136,6 +136,6 @@
- name: "Consul | Set reload-check & restart-check variable" - name: "Consul | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_consul_service_need_reload: true _consul_service_need_daemon_reload: true
_consul_service_need_restart: true _consul_service_need_restart: true
when: _consul_unit_file.changed # noqa: no-handler when: _consul_unit_file.changed # noqa: no-handler

View File

@ -2,6 +2,7 @@
# task/main file for consul # task/main file for consul
- name: "Consul | Set reload-check & restart-check variable" - name: "Consul | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_consul_service_need_daemon_reload: false
_consul_service_need_reload: false _consul_service_need_reload: false
_consul_service_need_restart: false _consul_service_need_restart: false
@ -37,11 +38,23 @@
- name: "Consul | Reload systemd daemon" - name: "Consul | Reload systemd daemon"
ansible.builtin.systemd: ansible.builtin.systemd:
daemon_reload: true daemon_reload: true
when: _consul_service_need_reload when: _consul_service_need_daemon_reload
- name: "Consul | Start service: {{ consul_service_name }}" - name: "Consul | Start service: {{ consul_service_name }}"
ansible.builtin.service: ansible.builtin.service:
name: "{{ consul_service_name }}" name: "{{ consul_service_name }}"
state: restarted state: restarted
throttle: 1 throttle: 1
when: _consul_service_need_restart when:
- consul_start_service
- _consul_service_need_restart
- name: "Consul | Reload service: {{ consul_service_name }}"
ansible.builtin.service:
name: "{{ consul_service_name }}"
state: reloaded
throttle: 1
when:
- consul_start_service
- _consul_service_need_reload
- not _consul_service_need_restart

View File

@ -21,6 +21,19 @@ consul_github_project: hashicorp/consul
consul_github_url: https://github.com consul_github_url: https://github.com
consul_repository_url: https://releases.hashicorp.com/consul consul_repository_url: https://releases.hashicorp.com/consul
consul_certificates_reload_watchlist: |
{% filter trim %}
{% set watchlist = [] %}
{% for block, config in (consul_configuration.tls | default({})).items() %}
{% for key in ['ca_file', 'cert_file', 'key_file'] %}
{% if config.get(key) %}
{{ watchlist.append(config[key]) }}
{% endif %}
{% endfor %}
{% endfor %}
{{ watchlist | unique }}
{% endfilter %}
consul_configuration: consul_configuration:
domain: "{{ consul_domain }}" domain: "{{ consul_domain }}"
datacenter: "{{ consul_datacenter }}" datacenter: "{{ consul_datacenter }}"

View File

@ -45,3 +45,15 @@
when: when:
- hashistack_ca_renew_leaf - hashistack_ca_renew_leaf
- "('consul_servers' in group_names) or ('consul_agents' in group_names)" - "('consul_servers' in group_names) or ('consul_agents' in group_names)"
- name: "Nomad leaf certificates | Import renew_nomad.yml"
ansible.builtin.include_tasks: renew/renew_nomad.yml
when:
- hashistack_ca_renew_leaf
- "('nomad_servers' in group_names) or ('nomad_clients' in group_names)"
- name: "Vault leaf certificates | Import renew_vault.yml"
ansible.builtin.include_tasks: renew/renew_vault.yml
when:
- hashistack_ca_renew_leaf
- "'vault_servers' in group_names"

View File

@ -2,7 +2,7 @@
# meta file for nomad # meta file for nomad
galaxy_info: galaxy_info:
namespace: "ednz_cloud" namespace: "ednz_cloud"
role_name: "hashicorp_nomad" role_name: "nomad"
author: "Bertrand Lanson" author: "Bertrand Lanson"
description: "Install and configure hashicorp nomad for debian-based distros." description: "Install and configure hashicorp nomad for debian-based distros."
license: "license (BSD, MIT)" license: "license (BSD, MIT)"

View File

@ -24,6 +24,31 @@
when: _nomad_env_file.changed or when: _nomad_env_file.changed or
_nomad_config_file.changed _nomad_config_file.changed
- name: "Nomad | Gather initial checksums for certificate files"
ansible.builtin.stat:
path: "{{ item }}"
checksum_algorithm: sha1
loop: "{{ nomad_certificates_reload_watchlist }}"
when: nomad_enable_tls
register: _nomad_initial_cert_checksums
- name: "Nomad | 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.
_nomad_initial_checksums_normalized: >-
{% filter trim %}
{% set checksums = [] %}
{% for item in _nomad_initial_cert_checksums.results %}
{% set _ = checksums.append({
'item': item.item,
'initial_checksum': (item.stat.checksum | default('absent'))
}) %}
{% endfor %}
{{ checksums }}
{% endfilter %}
when: nomad_enable_tls
- name: "Nomad | Copy extra configuration files" - name: "Nomad | Copy extra configuration files"
when: nomad_extra_files when: nomad_extra_files
block: block:
@ -72,3 +97,44 @@
loop_control: loop_control:
loop_var: dir_source_item loop_var: dir_source_item
when: _nomad_dir_sources is defined when: _nomad_dir_sources is defined
- name: "Nomad | Gather final checksums for certificate files"
ansible.builtin.stat:
path: "{{ item }}"
checksum_algorithm: sha1
loop: "{{ nomad_certificates_reload_watchlist }}"
when: nomad_enable_tls
register: _nomad_final_cert_checksums
- name: "Nomad | 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.
_nomad_final_checksums_normalized: >-
{% filter trim %}
{% set checksums = [] %}
{% for item in _nomad_final_cert_checksums.results %}
{% set _ = checksums.append({
'item': item.item,
'final_checksum': (item.stat.checksum | default('absent'))
}) %}
{% endfor %}
{{ checksums }}
{% endfilter %}
when: nomad_enable_tls
- name: "Nomad | Merge initial and final checksum lists"
ansible.builtin.set_fact:
_nomad_checksums_list: >-
{{
_nomad_initial_checksums_normalized |
community.general.lists_mergeby(_nomad_final_checksums_normalized, 'item')
}}
when: nomad_enable_tls
- name: "Nomad | Determine if certificates have changed or were newly added"
ansible.builtin.set_fact:
_nomad_service_need_reload: true
when:
- nomad_enable_tls
- _nomad_checksums_list | json_query('[?initial_checksum!=final_checksum]') | list| length > 0

View File

@ -136,6 +136,6 @@
- name: "Nomad | Set reload-check & restart-check variable" - name: "Nomad | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_nomad_service_need_reload: true _nomad_service_need_daemon_reload: true
_nomad_service_need_restart: true _nomad_service_need_restart: true
when: _nomad_unit_file.changed # noqa: no-handler when: _nomad_unit_file.changed # noqa: no-handler

View File

@ -2,6 +2,7 @@
# task/main file for nomad # task/main file for nomad
- name: "Nomad | Set reload-check & restart-check variable" - name: "Nomad | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_nomad_service_need_daemon_reload: false
_nomad_service_need_reload: false _nomad_service_need_reload: false
_nomad_service_need_restart: false _nomad_service_need_restart: false
@ -33,11 +34,23 @@
- name: "Nomad | Reload systemd daemon" - name: "Nomad | Reload systemd daemon"
ansible.builtin.systemd: ansible.builtin.systemd:
daemon_reload: true daemon_reload: true
when: _nomad_service_need_reload when: _nomad_service_need_daemon_reload
- name: "Nomad | Start service: {{ nomad_service_name }}" - name: "Nomad | Start service: {{ nomad_service_name }}"
ansible.builtin.service: ansible.builtin.service:
name: "{{ nomad_service_name }}" name: "{{ nomad_service_name }}"
state: restarted state: restarted
throttle: 1 throttle: 1
when: _nomad_service_need_restart when:
- nomad_start_service
- _nomad_service_need_restart
- name: "Nomad | Reload service: {{ nomad_service_name }}"
ansible.builtin.service:
name: "{{ nomad_service_name }}"
state: reloaded
throttle: 1
when:
- nomad_start_service
- _nomad_service_need_reload
- not _nomad_service_need_restart

View File

@ -15,6 +15,18 @@ nomad_github_project: hashicorp/nomad
nomad_github_url: https://github.com nomad_github_url: https://github.com
nomad_repository_url: https://releases.hashicorp.com/nomad nomad_repository_url: https://releases.hashicorp.com/nomad
nomad_certificates_reload_watchlist: |
{% filter trim %}
{% set watchlist = [] %}
{% set config = nomad_configuration.get('tls', {}) %}
{% for key in ['ca_file', 'cert_file', 'key_file'] %}
{% if config.get(key) %}
{{ watchlist.append(config[key]) }}
{% endif %}
{% endfor %}
{{ watchlist | unique }}
{% endfilter %}
nomad_configuration: nomad_configuration:
datacenter: "{{ nomad_datacenter }}" datacenter: "{{ nomad_datacenter }}"
region: "{{ nomad_region }}" region: "{{ nomad_region }}"

View File

@ -2,7 +2,7 @@
# meta file for vault # meta file for vault
galaxy_info: galaxy_info:
namespace: "ednz_cloud" namespace: "ednz_cloud"
role_name: "hashicorp_vault" role_name: "vault"
author: "Bertrand Lanson" author: "Bertrand Lanson"
description: "Install and configure hashicorp vault for debian-based distros." description: "Install and configure hashicorp vault for debian-based distros."
license: "license (BSD, MIT)" license: "license (BSD, MIT)"

View File

@ -24,6 +24,31 @@
when: _vault_env_file.changed or when: _vault_env_file.changed or
_vault_config_file.changed _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" - name: "Vault | Copy extra configuration files"
when: vault_extra_files when: vault_extra_files
block: block:
@ -72,3 +97,44 @@
loop_control: loop_control:
loop_var: dir_source_item loop_var: dir_source_item
when: _vault_dir_sources is defined 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

View File

@ -137,7 +137,7 @@
- name: "Vault | Set reload-check & restart-check variable" - name: "Vault | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_vault_service_need_reload: true _vault_service_need_daemon_reload: true
_vault_service_need_restart: true _vault_service_need_restart: true
when: _vault_unit_file.changed # noqa: no-handler when: _vault_unit_file.changed # noqa: no-handler

View File

@ -2,6 +2,7 @@
# task/main file for vault # task/main file for vault
- name: "Vault | Set reload-check & restart-check variable" - name: "Vault | Set reload-check & restart-check variable"
ansible.builtin.set_fact: ansible.builtin.set_fact:
_vault_service_need_daemon_reload: false
_vault_service_need_reload: false _vault_service_need_reload: false
_vault_service_need_restart: false _vault_service_need_restart: false
@ -33,13 +34,24 @@
- name: "Vault | Reload systemd daemon" - name: "Vault | Reload systemd daemon"
ansible.builtin.systemd: ansible.builtin.systemd:
daemon_reload: true daemon_reload: true
when: _vault_service_need_reload when: _vault_service_need_daemon_reload
- name: "Vault | Start service: {{ vault_service_name }}" - name: "Vault | Start service: {{ vault_service_name }}"
ansible.builtin.include_tasks: rolling_restart.yml ansible.builtin.include_tasks: rolling_restart.yml
when: when:
- vault_start_service
- _vault_service_need_restart - _vault_service_need_restart
- "hostvars[host_item].inventory_hostname == inventory_hostname" - "hostvars[host_item].inventory_hostname == inventory_hostname"
with_items: "{{ ansible_play_batch }}" with_items: "{{ ansible_play_batch }}"
loop_control: loop_control:
loop_var: host_item 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

View File

@ -15,6 +15,22 @@ vault_github_project: hashicorp/vault
vault_github_url: https://github.com vault_github_url: https://github.com
vault_repository_url: https://releases.hashicorp.com/vault 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: vault_configuration:
cluster_name: "{{ vault_cluster_name }}" cluster_name: "{{ vault_cluster_name }}"
cluster_addr: "{{ 'https' if vault_enable_tls else 'http'}}://{{ vault_cluster_addr }}:8201" cluster_addr: "{{ 'https' if vault_enable_tls else 'http'}}://{{ vault_cluster_addr }}:8201"