From 812a2bb04a96bc21a684107e20b68c0e98129d89 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Wed, 3 Apr 2024 23:55:01 +0200 Subject: [PATCH] feat(certs): generate_certs playbook now generate internal CA for vault --- .../vault_servers/config/tls/cert.pem | 0 .../vault_servers/config/tls/key.pem | 0 molecule/no_tls_multi_node/prepare.yml | 3 + playbooks/generate_certs.yml | 190 +++++++++++++++--- playbooks/group_vars/all/globals.yml | 2 +- playbooks/group_vars/all/vault.yml | 24 +++ roles/hashicorp_consul | 2 +- roles/hashicorp_vault | 2 +- 8 files changed, 189 insertions(+), 34 deletions(-) delete mode 100644 molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/cert.pem delete mode 100644 molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/key.pem diff --git a/molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/cert.pem b/molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/cert.pem deleted file mode 100644 index e69de29..0000000 diff --git a/molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/key.pem b/molecule/no_tls_multi_node/etc/hashistack/vault_servers/config/tls/key.pem deleted file mode 100644 index e69de29..0000000 diff --git a/molecule/no_tls_multi_node/prepare.yml b/molecule/no_tls_multi_node/prepare.yml index 6c57e49..9973f22 100644 --- a/molecule/no_tls_multi_node/prepare.yml +++ b/molecule/no_tls_multi_node/prepare.yml @@ -1,4 +1,7 @@ --- +- name: Include certificate generation playbook + ansible.builtin.import_playbook: ednz_cloud.hashistack.generate_certs.yml + - name: Include bootstrap playbook ansible.builtin.import_playbook: ednz_cloud.hashistack.bootstrap.yml diff --git a/playbooks/generate_certs.yml b/playbooks/generate_certs.yml index 99d5fd8..51d3881 100644 --- a/playbooks/generate_certs.yml +++ b/playbooks/generate_certs.yml @@ -6,11 +6,21 @@ gather_facts: true become: true tasks: - - name: "Generate self-signed certificates" # noqa: run-once[task] + - name: "Create temporary cert directory in {{ sub_configuration_directories['certificates'] }}" # noqa: run-once[task] + ansible.builtin.file: + path: "{{ sub_configuration_directories['certificates'] }}/external" + state: directory + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + mode: "0755" + delegate_to: localhost + run_once: true + + - name: "Generate external certificates" # noqa: run-once[task] delegate_to: localhost run_once: true block: - - name: "Create temporary cert directory in {{ sub_configuration_directories['certificates'] }}" + - name: "Create temporary cert directory in {{ sub_configuration_directories['certificates'] }}" # noqa: run-once[task] ansible.builtin.file: path: "{{ sub_configuration_directories['certificates'] }}/external" state: directory @@ -18,43 +28,161 @@ group: "{{ lookup('env', 'USER') }}" mode: "0755" - - name: "Generate self-signed certificate" + - name: "Create private keys" + community.crypto.openssl_privatekey: + path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.fqdn }}.pem.key" + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + loop: + - name: nomad + fqdn: "{{ nomad_fqdn }}" + - name: vault + fqdn: "{{ vault_fqdn }}" + - name: consul + fqdn: "{{ consul_fqdn }}" + + - name: "Create certificate signing request" + community.crypto.openssl_csr_pipe: + privatekey_path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.fqdn }}.pem.key" + common_name: "{{ item.fqdn }}" + organization_name: EDNZ Cloud + register: csr + loop: + - name: nomad + fqdn: "{{ nomad_fqdn }}" + - name: vault + fqdn: "{{ vault_fqdn }}" + - name: consul + fqdn: "{{ consul_fqdn }}" + + - name: "Create self-signed certificate from CSR" + community.crypto.x509_certificate: + path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.item.fqdn }}.pem" + csr_content: "{{ item.csr }}" + privatekey_path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.item.fqdn }}.pem.key" + provider: selfsigned + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + loop: "{{ csr.results }}" + + - name: "Generate internal certificates" + tags: + - never + - internal + delegate_to: localhost + vars: + hashistack_ca_key_path: "{{ sub_configuration_directories['certificates'] }}/internal/ca.key" + hashistack_ca_cert_path: "{{ sub_configuration_directories['certificates'] }}/internal/ca.pem" + block: + - name: "Create internal CA" # noqa: run-once[task] + run_once: true block: - - name: "Create private keys" - community.crypto.openssl_privatekey: - path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.fqdn }}.pem.key" + - name: "Create temporary cert directory in {{ sub_configuration_directories['certificates'] }}" # noqa: run-once[task] + ansible.builtin.file: + path: "{{ sub_configuration_directories['certificates'] }}/internal" + state: directory owner: "{{ lookup('env', 'USER') }}" group: "{{ lookup('env', 'USER') }}" - loop: - - name: nomad - fqdn: "{{ nomad_fqdn }}" - - name: vault - fqdn: "{{ vault_fqdn }}" - - name: consul - fqdn: "{{ consul_fqdn }}" + mode: "0755" - - name: "Create certificate signing request" + - name: "Create CA private key" + community.crypto.openssl_privatekey: + path: "{{ hashistack_ca_key_path }}" + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + + - name: "Create CA signing request" community.crypto.openssl_csr_pipe: - privatekey_path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.fqdn }}.pem.key" - common_name: "{{ item.fqdn }}" - organization_name: Ansible, Inc. - register: csr - loop: - - name: nomad - fqdn: "{{ nomad_fqdn }}" - - name: vault - fqdn: "{{ vault_fqdn }}" - - name: consul - fqdn: "{{ consul_fqdn }}" + privatekey_path: "{{ hashistack_ca_key_path }}" + common_name: "CA" + organization_name: EDNZ Cloud + use_common_name_for_san: false + basic_constraints: + - CA:TRUE + basic_constraints_critical: true + key_usage: + - keyCertSign + key_usage_critical: true + register: ca_csr - - name: "Create self-signed certificate from CSR" + - name: "Create self-signed CA certificate from CSR" community.crypto.x509_certificate: - path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.item.fqdn }}.pem" - csr_content: "{{ item.csr }}" - privatekey_path: "{{ sub_configuration_directories['certificates'] }}/external/{{ item.item.fqdn }}.pem.key" + path: "{{ hashistack_ca_cert_path }}" + csr_content: "{{ ca_csr.csr }}" + privatekey_path: "{{ hashistack_ca_key_path }}" provider: selfsigned owner: "{{ lookup('env', 'USER') }}" group: "{{ lookup('env', 'USER') }}" - loop: "{{ csr.results }}" - - fail: + - name: "Create Vault certificates" + when: + - "'vault_servers' in group_names" + vars: + vault_private_key_path: "{{ sub_configuration_directories['certificates'] }}/vault/{{ inventory_hostname }}/key.pem" + vault_certificate_path: "{{ sub_configuration_directories['certificates'] }}/vault/{{ inventory_hostname }}/cert.pem" + block: + - name: "Create temporary cert directory in {{ sub_configuration_directories['certificates'] }}" # noqa: run-once[task] + ansible.builtin.file: + path: "{{ sub_configuration_directories['certificates'] }}/vault/{{ inventory_hostname }}" + state: directory + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + mode: "0755" + + - name: "Create Vault certificate keys" + community.crypto.openssl_privatekey: + path: "{{ vault_private_key_path }}" + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + + - name: "Create CSRs for Vault servers" + community.crypto.openssl_csr_pipe: + privatekey_path: "{{ vault_private_key_path }}" + common_name: "{{ inventory_hostname }}" + subject_alt_name: + - "DNS:{{ inventory_hostname }}" + - "DNS:active.vault.service.consul" + - "DNS:standby.vault.service.consul" + - "DNS:vault.service.consul" + - "DNS:localhost" + - "IP:{{ api_interface_address }}" + - "IP:127.0.0.1" + extended_key_usage: + - TLS Web Server Authentication + - TLS Web Client Authentication + organization_name: EDNZ Cloud + use_common_name_for_san: false + register: vault_csr + + - name: "Sign certificates with internal CA" + community.crypto.x509_certificate: + path: "{{ vault_certificate_path }}" + csr_content: "{{ vault_csr.csr }}" + provider: ownca + ownca_path: "{{ hashistack_ca_cert_path }}" + ownca_privatekey_path: "{{ hashistack_ca_key_path }}" + ownca_not_after: "+365d" + ownca_not_before: "-1d" + + - name: "Concatenate CA and Child certificates" + block: + - name: "Read content of ca.pem" + ansible.builtin.slurp: + src: "{{ hashistack_ca_cert_path }}" + register: ca_pem_content + + - name: "Read content of cert.pem" + ansible.builtin.slurp: + src: "{{ vault_certificate_path }}" + register: cert_pem_content + + - name: "Concatenate certificates" + ansible.builtin.copy: + content: | + {{ cert_pem_content['content'] | b64decode }}{{ ca_pem_content['content'] | b64decode }} + dest: "{{ vault_certificate_path }}" + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + mode: "0644" + + - fail: \ No newline at end of file diff --git a/playbooks/group_vars/all/globals.yml b/playbooks/group_vars/all/globals.yml index 1894cf7..b1ab810 100644 --- a/playbooks/group_vars/all/globals.yml +++ b/playbooks/group_vars/all/globals.yml @@ -165,7 +165,6 @@ vault_service_registration_configuration: ################# vault_enable_plugins: true -vault_plugin_directory: "{{ hashi_vault_extra_files_dst }}/plugin" ########### # logging # @@ -189,3 +188,4 @@ extra_vault_container_volumes: [] ##################### vault_extra_configuration: {} +vault_extra_files_list: [] diff --git a/playbooks/group_vars/all/vault.yml b/playbooks/group_vars/all/vault.yml index 6ddfe2c..49bf0c4 100644 --- a/playbooks/group_vars/all/vault.yml +++ b/playbooks/group_vars/all/vault.yml @@ -31,6 +31,24 @@ vault_external_backend_servers: | {% endfor %} ] +###################### +# vault internal tls # +###################### + +vault_certificates_directory: "{{ hashi_vault_config_dir }}/tls" +vault_certificates_extra_files_dir: + - src: "{{ sub_configuration_directories['certificates'] }}/vault/{{ inventory_hostname }}" + dest: "{{ hashi_vault_config_dir }}/tls/cert" + +################# +# vault plugins # +################# + +vault_plugin_directory: "{{ hashi_vault_config_dir }}/plugin" +vault_plugin_extra_files_dir: + - src: "{{ sub_configuration_directories['vault_servers'] }}/plugin" + dest: "{{ hashi_vault_config_dir }}/plugin" + ######################## # vault role variables # ######################## @@ -42,6 +60,12 @@ hashi_vault_env_variables: {} hashi_vault_config_dir: "/etc/vault.d" hashi_vault_data_dir: "/opt/vault" hashi_vault_extra_files: true +hashi_vault_extra_files_list: "{{ ([] + + (vault_certificates_extra_files_dir if vault_enable_tls else []) + + (vault_plugin_extra_files_dir if vault_enable_plugins else []) + + vault_extra_files_list) + | unique + }}" hashi_vault_extra_files_src: "{{ sub_configuration_directories.vault_servers }}/config" hashi_vault_extra_files_dst: "{{ hashi_vault_config_dir }}/config" hashi_vault_extra_container_volumes: "{{ default_container_extra_volumes | union(extra_vault_container_volumes) | unique }}" diff --git a/roles/hashicorp_consul b/roles/hashicorp_consul index a322d3c..59868f0 160000 --- a/roles/hashicorp_consul +++ b/roles/hashicorp_consul @@ -1 +1 @@ -Subproject commit a322d3c144806ea2524651996e19ff9885b90e16 +Subproject commit 59868f06aa64f72e1f8547bcd78c48f26ce58b9c diff --git a/roles/hashicorp_vault b/roles/hashicorp_vault index db96aa6..36b74e4 160000 --- a/roles/hashicorp_vault +++ b/roles/hashicorp_vault @@ -1 +1 @@ -Subproject commit db96aa6bf3af97c282407a559a199b34da34c15e +Subproject commit 36b74e452acb204bf7d76e8037ffa8449e5508f5