From bdf1055f9dbaadcc5a575c4e9d839a82daeae4d5 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Sun, 30 Apr 2023 00:16:08 +0200 Subject: [PATCH] refactored tests and updated readme. added ca_pem template file --- README.md | 53 +++++++++++-------- molecule/default/tests/test_default.py | 43 ++++++++++++++- molecule/with_custom_config/converge.yml | 4 +- .../with_custom_config/group_vars/all.yml | 5 +- molecule/with_custom_config/prepare.yml | 10 ++-- .../with_custom_config/tests/test_default.py | 6 ++- ...{consul_ca.pem.j2 => consul_ca.pem.tpl.j2} | 2 +- templates/consul_config.hcl.j2 | 6 +-- 8 files changed, 93 insertions(+), 36 deletions(-) rename templates/{consul_ca.pem.j2 => consul_ca.pem.tpl.j2} (94%) diff --git a/README.md b/README.md index 45d7e00..3383609 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,37 @@ -Renew vault certificates +Renew consul certificates ========= > This repository is only a mirror. Development and testing is done on a private gitlab server. -This role install consul-template and configure a service to automate renewal of TLS certificates for Hashicorp Vault on **debian-based** distributions. +This role install consul-template and configure a service to automate renewal of TLS certificates for Hashicorp Consul on **debian-based** distributions. Requirements ------------ -This role assume that you already have installed a vault server on the host, and is only here to assist in automating the certificate renewal process. +This role assume that you already have installed a consul server on the host, and is only here to assist in automating the certificate renewal process. Role Variables -------------- -Available variables are listed below, along with default values. A sample file for the default values is available in `default/renew_vault_certificates.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. +Available variables are listed below, along with default values. A sample file for the default values is available in `default/renew_consul_certificates.yml.sample` in case you need it for any `group_vars` or `host_vars` configuration. ```yaml -renew_vault_certificates_config_dir: /etc/consul-template.d/vault # by default, set to /etc/consul-template.d/vault +renew_consul_certificates_config_dir: /etc/consul-template.d/consul # by default, set to /etc/consul-template.d/consul ``` This variable defines where the files for the role are stored (consul-template configuration + templates). ```yaml -renew_vault_certificates_vault_user: vault # by default, set to vault +renew_vault_certificates_consul_user: consul # by default, set to consul ``` -This variable defines the user that'll be running the certificate renewal service. Defaults to `vault`, and should be present on the host prior to playing this role (ideally when installing vault). +This variable defines the user that'll be running the certificate renewal service. Defaults to `consul`, and should be present on the host prior to playing this role (ideally when installing consul). ```yaml -renew_vault_certificates_vault_group: vault # by default, set to vault +renew_vault_certificates_consul_group: consul # by default, set to consul ``` -This variable defines the group that'll be running the certificate renewal service. Defaults to `vault`, and should be present on the host prior to playing this role (ideally when installing vault). +This variable defines the group that'll be running the certificate renewal service. Defaults to `consul`, and should be present on the host prior to playing this role (ideally when installing consul). ```yaml renew_vault_certificates_vault_addr: https://127.0.0.1:8200 # by default, set to https://127.0.0.1:8200 ``` -This variable defines the address the consul-template service will query to get the new certificates. Defaults to localhost, but can be changed if vault isnt reachable on localhost (because of missing certificates SANs for example). +This variable defines the address the consul-template service will query to get the new certificates. Defaults to localhost, but can be changed if vault isnt reachable on localhost. ```yaml renew_vault_certificates_vault_token: mysupersecretvaulttokenthatyoushouldchange # by default, set to a dummy string @@ -49,31 +49,42 @@ renew_vault_certificates_vault_token_renew: true # by default, set to true This variable defines whether or not to renew the vault token. It should probably be `true`, and you should have a periodic token to handle this. ```yaml -renew_vault_certificates_cert_dest: /opt/vault/tls/cert.pem # by default, set to /opt/vault/tls/cert.pem +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem # by default, set to /opt/consul/tls/ca.pem ``` -This variable defines where to copy the certificates upon renewal. Default to `/opt/vault/tls/cert.pem` but should be changed depending on where you store the certificates. +This variable defines where to copy the certificate authority upon renewal. Default to `/opt/consul/tls/ca.pem` but should be changed depending on where you store the certificate authority. ```yaml -renew_vault_certificates_key_dest: /opt/vault/tls/key.pem # by default, set to /opt/vault/tls/cert.pem +renew_vault_certificates_cert_dest: /opt/consul/tls/cert.pem # by default, set to /opt/consul/tls/cert.pem ``` -This variable defines where to copy the private keys upon renewal. Default to `/opt/vault/tls/key.pem` but should be changed depending on where you store the keys. +This variable defines where to copy the certificates upon renewal. Default to `/opt/consul/tls/cert.pem` but should be changed depending on where you store the certificates. ```yaml -renew_vault_certificates_info: # by default, set to: +renew_consul_certificates_key_dest: /opt/consul/tls/key.pem # by default, set to /opt/consul/tls/cert.pem +``` +This variable defines where to copy the private keys upon renewal. Default to `/opt/consul/tls/key.pem` but should be changed depending on where you store the keys. + +```yaml +renew_consul_certificates_info: # by default, set to: issuer_path: pki/issue/your-issuer - common_name: vault01.example.com + common_name: consul01.example.com ttl: 90d + is_server: false include_consul_service: false ``` -This variable defines the path on vault to retrieve the certificates, as well as the common name and TTL to use for it. It can also include vault aliases in case you have registered vault services in a consul cluster (`active.vault.service.consul,` `standby.vault.service.consul`, `vault.service.consul`). +This variable defines the path on vault to retrieve the certificates, as well as the common name and TTL to use for it. It can also include consul aliases in case you have registered consul services in itself (`consul.service.consul`). It also handles whether or not to append the server.yourdc.consul SAN, in case you're enforcing hostname checking. ```yaml -renew_vault_certificates_consul_service_name: vault.service.consul # by default, set to vault.service.consul +renew_consul_certificates_consul_dc_name: dc1.consul # by default, set to dc1.consul ``` -This variable defines the vault service name in consul. Default is `vault.service.consul` +In case you enforce hostname checking, set this variable to your desired dc and consul domain. This is used to forge the SAN that will be checked by consul to only allow specific nodes to be managers. ```yaml -renew_vault_certificates_start_service: false +renew_consul_certificates_consul_service_name: consul.service.consul # by default, set to consul.service.consul +``` +This variable defines the consul service name in consul. Default is `consul.service.consul` + +```yaml +renew_consul_certificates_start_service: false ``` This variable defines whether or not to start the service after creating it. By default, it is only enabled, but not started, in case you're building golden images (in which case you probably don't want a certificate generated during the build process). @@ -90,7 +101,7 @@ Including an example of how to use your role (for instance, with variables passe # calling the role inside a playbook with either the default or group_vars/host_vars - hosts: servers roles: - - ednxzu.renew_vault_certificates + - ednxzu.renew_consul_certificates ``` License diff --git a/molecule/default/tests/test_default.py b/molecule/default/tests/test_default.py index d243e0f..984de8e 100644 --- a/molecule/default/tests/test_default.py +++ b/molecule/default/tests/test_default.py @@ -6,4 +6,45 @@ def test_hosts_file(host): etc_hosts = host.file("/etc/hosts") assert etc_hosts.exists assert etc_hosts.user == "root" - assert etc_hosts.group == "root" \ No newline at end of file + assert etc_hosts.group == "root" + +def test_consul_template_config(host): + """Validate /etc/consul-template.d/consul/ files.""" + etc_consul_template_d_consul_config_hcl = host.file("/etc/consul-template.d/consul/consul_config.hcl") + assert etc_consul_template_d_consul_config_hcl.exists + assert etc_consul_template_d_consul_config_hcl.user == "consul" + assert etc_consul_template_d_consul_config_hcl.group == "consul" + assert etc_consul_template_d_consul_config_hcl.mode == 0o600 + +def test_template_files(host): + """Validate /etc/consul-template.d/consul/templates/ files.""" + consul_ca_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_ca.pem.tpl") + consul_cert_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_cert.pem.tpl") + consul_key_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_key.pem.tpl") + for file in consul_cert_pem_tpl, consul_key_pem_tpl: + assert file.exists + assert file.user == "consul" + assert file.group == "consul" + assert file.mode == 0o600 + assert consul_ca_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }}\n{{ .Data.issuing_ca }}\n{{ end }}\n' + assert consul_cert_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }}\n{{ .Data.certificate }}\n{{ end }}\n' + assert consul_key_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost" "ip_sans=127.0.0.1" }}\n{{ .Data.private_key }}\n{{ end }}\n' + +def test_consul_certs_service_file(host): + """Validate consul-certs service file.""" + etc_systemd_system_consul_certs_service = host.file("/etc/systemd/system/consul-certs.service") + assert etc_systemd_system_consul_certs_service.exists + assert etc_systemd_system_consul_certs_service.user == "root" + assert etc_systemd_system_consul_certs_service.group == "root" + assert etc_systemd_system_consul_certs_service.mode == 0o644 + assert etc_systemd_system_consul_certs_service.content_string != "" + +def test_consul_certs_service(host): + """Validate consul-certs service.""" + consul_certs_service = host.service("consul-certs.service") + assert consul_certs_service.is_enabled + assert not consul_certs_service.is_running + assert consul_certs_service.systemd_properties["Restart"] == "on-failure" + assert consul_certs_service.systemd_properties["User"] == "consul" + assert consul_certs_service.systemd_properties["Group"] == "consul" + assert consul_certs_service.systemd_properties["FragmentPath"] == "/etc/systemd/system/consul-certs.service" diff --git a/molecule/with_custom_config/converge.yml b/molecule/with_custom_config/converge.yml index 897496d..d9ad3ce 100644 --- a/molecule/with_custom_config/converge.yml +++ b/molecule/with_custom_config/converge.yml @@ -2,6 +2,6 @@ - name: Converge hosts: all tasks: - - name: "Include ednxzu.renew_vault_certificates" + - name: "Include ednxzu.renew_consul_certificates" ansible.builtin.include_role: - name: "ednxzu.renew_vault_certificates" + name: "ednxzu.renew_consul_certificates" diff --git a/molecule/with_custom_config/group_vars/all.yml b/molecule/with_custom_config/group_vars/all.yml index 2c06ecf..b57a796 100644 --- a/molecule/with_custom_config/group_vars/all.yml +++ b/molecule/with_custom_config/group_vars/all.yml @@ -6,12 +6,15 @@ renew_consul_certificates_vault_addr: "https://consul.example.com" renew_consul_certificates_vault_token: mysupersecretconsultokenthatyoushouldchange renew_consul_certificates_vault_token_unwrap: false renew_consul_certificates_vault_token_renew: true +renew_consul_certificates_ca_dest: /opt/consul/tls/ca.pem renew_consul_certificates_cert_dest: /opt/consul/tls/cert.pem renew_consul_certificates_key_dest: /opt/consul/tls/key.pem renew_consul_certificates_info: - issuer_path: pki/issue/consul-issuer + issuer_path: pki/issue/your-issuer common_name: consul01.example.com ttl: 90d + is_server: true include_consul_service: true +renew_consul_certificates_consul_dc_name: dc1.consul renew_consul_certificates_consul_service_name: consul.service.consul renew_consul_certificates_start_service: false diff --git a/molecule/with_custom_config/prepare.yml b/molecule/with_custom_config/prepare.yml index de48134..d63429c 100644 --- a/molecule/with_custom_config/prepare.yml +++ b/molecule/with_custom_config/prepare.yml @@ -2,14 +2,14 @@ - name: Prepare hosts: all tasks: - - name: "Create group vault" + - name: "Create group consul" ansible.builtin.group: - name: "vault" + name: "consul" state: present - - name: "Create user vault" + - name: "Create user consul" ansible.builtin.user: - name: "vault" - group: "vault" + name: "consul" + group: "consul" shell: /bin/false state: present diff --git a/molecule/with_custom_config/tests/test_default.py b/molecule/with_custom_config/tests/test_default.py index 70bf16f..a057534 100644 --- a/molecule/with_custom_config/tests/test_default.py +++ b/molecule/with_custom_config/tests/test_default.py @@ -18,6 +18,7 @@ def test_consul_template_config(host): def test_template_files(host): """Validate /etc/consul-template.d/consul/templates/ files.""" + consul_ca_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_ca.pem.tpl") consul_cert_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_cert.pem.tpl") consul_key_pem_tpl = host.file("/etc/consul-template.d/consul/templates/consul_key.pem.tpl") for file in consul_cert_pem_tpl, consul_key_pem_tpl: @@ -25,8 +26,9 @@ def test_template_files(host): assert file.user == "consul" assert file.group == "consul" assert file.mode == 0o600 - assert consul_cert_pem_tpl.content_string == '{{ with secret "pki/issue/consul-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,consul.service.consul,active.consul.service.consul,standby.consul.service.consul" "ip_sans=127.0.0.1" }}\n{{ .Data.certificate }}\n{{ .Data.issuing_ca }}\n{{ end }}\n' - assert consul_key_pem_tpl.content_string == '{{ with secret "pki/issue/consul-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,consul.service.consul,active.consul.service.consul,standby.consul.service.consul" "ip_sans=127.0.0.1" }}\n{{ .Data.private_key }}\n{{ end }}\n' + assert consul_ca_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }}\n{{ .Data.issuing_ca }}\n{{ end }}\n' + assert consul_cert_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }}\n{{ .Data.certificate }}\n{{ end }}\n' + assert consul_key_pem_tpl.content_string == '{{ with secret "pki/issue/your-issuer" "common_name=consul01.example.com" "ttl=90d" "alt_names=localhost,server.dc1.consul,consul.service.consul" "ip_sans=127.0.0.1" }}\n{{ .Data.private_key }}\n{{ end }}\n' def test_consul_certs_service_file(host): """Validate consul-certs service file.""" diff --git a/templates/consul_ca.pem.j2 b/templates/consul_ca.pem.tpl.j2 similarity index 94% rename from templates/consul_ca.pem.j2 rename to templates/consul_ca.pem.tpl.j2 index 545fbb1..65e4826 100644 --- a/templates/consul_ca.pem.j2 +++ b/templates/consul_ca.pem.tpl.j2 @@ -2,4 +2,4 @@ {% raw %}{{ .Data.issuing_ca }}{% endraw %} -{% raw %}{{ end }}{% endraw %} \ No newline at end of file +{% raw %}{{ end }}{% endraw %} diff --git a/templates/consul_config.hcl.j2 b/templates/consul_config.hcl.j2 index 10f7f14..cf34570 100644 --- a/templates/consul_config.hcl.j2 +++ b/templates/consul_config.hcl.j2 @@ -11,7 +11,7 @@ template { perms = 0700 user = "{{ renew_consul_certificates_consul_user }}" group = "{{ renew_consul_certificates_consul_group }}" - command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && pkill -SIGHUP vault '" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" } template { @@ -20,7 +20,7 @@ template { perms = 0700 user = "{{ renew_consul_certificates_consul_user }}" group = "{{ renew_consul_certificates_consul_group }}" - command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && pkill -SIGHUP vault '" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" } template { @@ -29,5 +29,5 @@ template { perms = 0700 user = "{{ renew_consul_certificates_consul_user }}" group = "{{ renew_consul_certificates_consul_group }}" - command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && pkill -SIGHUP vault '" + command = "sh -c 'echo \"$(date) Update certificate and key file for {{ renew_consul_certificates_info['common_name'] }}\" && consul reload '" }