diff --git a/.gitignore b/.gitignore index 514fff4..02e5a4e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ roles/ednz_cloud.* vault_config.yml consul_config.yml **/certificates/** +**/secrets/credentials.yml +**/secrets/vault.yml +**/.ansible-vault diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..81f2416 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,19 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.35.1 + hooks: + - id: yamllint + args: [-c=./.yamllint] + - repo: https://github.com/commitizen-tools/commitizen + rev: v3.24.0 + hooks: + - id: commitizen + - id: commitizen-branch + stages: + - post-commit + - push diff --git a/molecule/no_tls_multi_node/converge.yml b/molecule/no_tls_multi_node/converge.yml index 474348c..daad78c 100644 --- a/molecule/no_tls_multi_node/converge.yml +++ b/molecule/no_tls_multi_node/converge.yml @@ -1,6 +1,3 @@ --- -# - name: Include a playbook from a collection -# ansible.builtin.import_playbook: ednz_cloud.hashistack.generate_certs.yml - - name: Include a playbook from a collection ansible.builtin.import_playbook: ednz_cloud.hashistack.deploy.yml diff --git a/molecule/no_tls_multi_node/prepare.yml b/molecule/no_tls_multi_node/prepare.yml index 9973f22..f5a76e2 100644 --- a/molecule/no_tls_multi_node/prepare.yml +++ b/molecule/no_tls_multi_node/prepare.yml @@ -2,6 +2,9 @@ - name: Include certificate generation playbook ansible.builtin.import_playbook: ednz_cloud.hashistack.generate_certs.yml +# - name: Include credentials generation playbook +# ansible.builtin.import_playbook: ednz_cloud.hashistack.generate_credentials.yml + - name: Include bootstrap playbook ansible.builtin.import_playbook: ednz_cloud.hashistack.bootstrap.yml diff --git a/playbooks/deploy.yml b/playbooks/deploy.yml index 059377e..fbf6641 100644 --- a/playbooks/deploy.yml +++ b/playbooks/deploy.yml @@ -11,10 +11,6 @@ file: tasks/load_vars.yml tags: - always - # - haproxy - # - consul - # - vault - # - nomad - name: "Deploy Consul Control Plane" ansible.builtin.import_tasks: diff --git a/playbooks/generate_certs.yml b/playbooks/generate_certs.yml index 2fc8545..dc2913c 100644 --- a/playbooks/generate_certs.yml +++ b/playbooks/generate_certs.yml @@ -1,5 +1,5 @@ --- -# hashistack deployment playbook +# hashistack generate certificates playbook - name: "Generate certificates" hosts: all strategy: linear @@ -272,4 +272,4 @@ group: "{{ lookup('env', 'USER') }}" mode: "0644" - # - fail: \ No newline at end of file + # - fail: diff --git a/playbooks/generate_credentials.yml b/playbooks/generate_credentials.yml new file mode 100644 index 0000000..4f155f1 --- /dev/null +++ b/playbooks/generate_credentials.yml @@ -0,0 +1,33 @@ +--- +# hashistack generate certificates playbook +- name: "Generate credentials" + hosts: localhost + strategy: linear + gather_facts: true + become: true + tasks: + - name: "Generate consul credentials" + block: + - name: "Generate consul root credentials" + ansible.builtin.set_fact: + _consul_root_token: "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}" + + - name: "Generate consul agents credentials" + ansible.builtin.set_fact: + _consul_agents_token: "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}" + + - name: "Generate nomad credentials" + block: + - name: "Generate nomad root credentials" + ansible.builtin.set_fact: + _nomad_root_token: "{{ lookup('password', '/dev/null chars=ascii_letters,digits') | to_uuid }}" + + - name: "Write credentials file" + ansible.builtin.template: + src: templates/credentials.yml.j2 + dest: "{{ sub_configuration_directories['secrets'] }}/{{ configuration_credentials_vars_file }}" + owner: "{{ lookup('env', 'USER') }}" + group: "{{ lookup('env', 'USER') }}" + mode: '0644' + + # - fail: diff --git a/playbooks/group_vars/all/all.yml b/playbooks/group_vars/all/all.yml index bd2035b..d5b9469 100644 --- a/playbooks/group_vars/all/all.yml +++ b/playbooks/group_vars/all/all.yml @@ -3,7 +3,7 @@ # helper options # ################## -manage_pip_packages_allow_break_system_packages: true +manage_pip_packages_allow_break_system_packages: "{{ ansible_distribution == 'Debian' and ansible_distribution_version == '12' }}" vault_versions: host: "{{ vault_version if vault_version != 'latest' else vault_version + '*' }}" @@ -19,12 +19,14 @@ nomad_versions: configuration_directory: "{{ lookup('env', 'PWD') }}/etc/hashistack" sub_configuration_directories: + secrets: "{{ configuration_directory }}/secrets" certificates: "{{ configuration_directory }}/certificates" nomad_servers: "{{ configuration_directory }}/nomad_servers" vault_servers: "{{ configuration_directory }}/vault_servers" consul_servers: "{{ configuration_directory }}/consul_servers" configuration_global_vars_file: "globals.yml" +configuration_credentials_vars_file: "credentials.yml" hashistack_remote_config_dir: "/etc/hashistack" hashistack_remote_data_dir: "/opt/hashistack" diff --git a/playbooks/group_vars/all/consul.yml b/playbooks/group_vars/all/consul.yml index ce65dda..1914609 100644 --- a/playbooks/group_vars/all/consul.yml +++ b/playbooks/group_vars/all/consul.yml @@ -83,7 +83,7 @@ hashi_consul_configuration: dns_config: "{{ consul_dns_configuration }}" ports: dns: 8600 - http: "{{ ('8500'|int) if not }}" + http: 8500 # "{{ ('8500'|int) if not }}" https: -1 grpc: 8502 grpc_tls: 8503 diff --git a/playbooks/group_vars/all/vault.yml b/playbooks/group_vars/all/vault.yml index 1287b32..01f2ca4 100644 --- a/playbooks/group_vars/all/vault.yml +++ b/playbooks/group_vars/all/vault.yml @@ -65,6 +65,7 @@ hashi_vault_extra_files_list: "{{ ([] + (vault_plugin_extra_files_dir if vault_enable_plugins else []) + vault_extra_files_list) | unique + | sort }}" hashi_vault_extra_files_src: "{{ sub_configuration_directories.vault_servers }}/config" hashi_vault_extra_files_dst: "{{ hashi_vault_config_dir }}/config" diff --git a/playbooks/preflight.yml b/playbooks/preflight.yml index c826b15..0ec807e 100644 --- a/playbooks/preflight.yml +++ b/playbooks/preflight.yml @@ -305,6 +305,3 @@ fail_msg: >- The python sdk for docker is really out of date, you need to install a more recent version of it in order to use this tool. - - # - name: "Fail" - # fail: diff --git a/playbooks/tasks/consul/consul_deploy.yml b/playbooks/tasks/consul/consul_deploy.yml index 9ee2028..7a890e4 100644 --- a/playbooks/tasks/consul/consul_deploy.yml +++ b/playbooks/tasks/consul/consul_deploy.yml @@ -7,7 +7,7 @@ - name: "Wait for consul cluster to initialize" # noqa: run-once[task] ansible.builtin.uri: - url: "http://{{ api_interface_address }}:8500" + url: "http://{{ api_interface_address }}:8500" # TODO: this should be dynamic (http/https) validate_certs: no return_content: yes status_code: @@ -19,6 +19,7 @@ - name: "Initialize consul cluster" # noqa: run-once[task] community.general.consul_acl_bootstrap: + bootstrap_secret: "{{ _credentials.consul.root_token.secret_id }}" host: "{{ hashi_consul_configuration['advertise_addr'] }}" port: 8500 scheme: http @@ -28,27 +29,27 @@ register: _consul_init_secret when: hashi_consul_configuration.acl.enabled - - name: "Write consul configuration to file" # noqa: run-once[task] no-handler - ansible.builtin.blockinfile: - marker: "## -- {root_token} ANSIBLE MANAGED BLOCK ##" - block: "{{ - { - 'root_token':{ - 'accessor_id': _consul_init_secret.result.AccessorID, - 'secret_id': _consul_init_secret.result.SecretID - } - } | to_nice_yaml - }}" - path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - mode: "0644" - when: _consul_init_secret.result is defined - run_once: true - delegate_to: localhost + # - name: "Write consul configuration to file" # noqa: run-once[task] no-handler + # ansible.builtin.blockinfile: + # marker: "## -- {root_token} ANSIBLE MANAGED BLOCK ##" + # block: "{{ + # { + # 'root_token':{ + # 'accessor_id': _consul_init_secret.result.AccessorID, + # 'secret_id': _consul_init_secret.result.SecretID + # } + # } | to_nice_yaml + # }}" + # path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" + # mode: "0644" + # when: _consul_init_secret.result is defined + # run_once: true + # delegate_to: localhost - - name: "Load consul cluster variables" - ansible.builtin.include_vars: - file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - name: _consul_cluster_config + # - name: "Load consul cluster variables" + # ansible.builtin.include_vars: + # file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" + # name: _consul_cluster_config - name: "Create consul agents token" when: @@ -57,14 +58,14 @@ block: - name: "Create consul agents token" # noqa: run-once[task] no-handler run_once: true - delegate_to: localhost block: - name: "Create consul agent policy" community.general.consul_policy: - host: "{{ hashi_consul_configuration['advertise_addr'] }}" - token: "{{ _consul_cluster_config.root_token.secret_id }}" + token: "{{ _credentials.consul.root_token.secret_id }}" + host: "{{ api_interface_address }}" port: 8500 - scheme: http + scheme: http # TODO: this should be dynamic + validate_certs: false state: present name: agents-policy rules: "{{ consul_default_agent_policy }}" @@ -74,55 +75,65 @@ vars: consul_full_url: "http://{{ hashi_consul_configuration['advertise_addr'] }}:8500" consul_token_body: + Description: "Consul agents token" + SecretID: "{{ _credentials.consul.tokens.agent }}" Policies: - ID: "{{ _consul_agent_policy.policy.ID }}" ansible.builtin.uri: url: "{{ consul_full_url }}/v1/acl/token" method: PUT headers: - X-Consul-Token: "{{ _consul_cluster_config.root_token.secret_id }}" + X-Consul-Token: "{{ _credentials.consul.root_token.secret_id }}" body: "{{ consul_token_body | to_json }}" status_code: - 200 register: _consul_agent_token + changed_when: _consul_agent_token.status == 200 - - name: "Write consul agents token to file" # no-handler - ansible.builtin.blockinfile: - marker: "## -- {tokens} ANSIBLE MANAGED BLOCK ##" - block: "{{ - { - 'tokens':{ - 'agent': _consul_agent_token.json.SecretID - } - } | to_nice_yaml - }}" - path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - mode: "0644" - when: "'OK' in _consul_agent_token.msg" + - name: "Restart consul service" + ansible.builtin.service: + name: "consul_container" + state: restarted + throttle: 1 + when: _consul_agent_token.changed - - name: "Merge token configuration" - delegate_to: localhost - block: - - name: "Stat consul secrets file" - ansible.builtin.stat: - path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - register: _consul_config_file + # - name: "Write consul agents token to file" # no-handler + # ansible.builtin.blockinfile: + # marker: "## -- {tokens} ANSIBLE MANAGED BLOCK ##" + # block: "{{ + # { + # 'tokens':{ + # 'agent': _consul_agent_token.json.SecretID + # } + # } | to_nice_yaml + # }}" + # path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" + # mode: "0644" + # when: "'OK' in _consul_agent_token.msg" - - name: "Load consul secrets file" - ansible.builtin.include_vars: - file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - name: _consul_cluster_config - when: _consul_config_file.stat.exists + # - name: "Merge token configuration" + # delegate_to: localhost + # block: + # - name: "Stat consul secrets file" + # ansible.builtin.stat: + # path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" + # register: _consul_config_file + # + # - name: "Load consul secrets file" + # ansible.builtin.include_vars: + # file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" + # name: _consul_cluster_config + # when: _consul_config_file.stat.exists + # + # - name: "Merge token configuration" + # vars: + # _config_to_merge: + # acl: + # tokens: "{{ _consul_cluster_config.tokens }}" + # ansible.builtin.set_fact: + # hashi_consul_configuration: "{{ hashi_consul_configuration | default({}) | combine(_config_to_merge, recursive=true) }}" + # when: _consul_cluster_config.tokens is defined - - name: "Merge token configuration" - vars: - _config_to_merge: - acl: - tokens: "{{ _consul_cluster_config.tokens }}" - ansible.builtin.set_fact: - hashi_consul_configuration: "{{ hashi_consul_configuration | default({}) | combine(_config_to_merge, recursive=true) }}" - when: _consul_cluster_config.tokens is defined - - - name: "Include ednz_cloud.hashistack.hashicorp_consul" - ansible.builtin.include_role: - name: ednz_cloud.hashistack.hashicorp_consul + # - name: "Include ednz_cloud.hashistack.hashicorp_consul" + # ansible.builtin.include_role: + # name: ednz_cloud.hashistack.hashicorp_consul diff --git a/playbooks/tasks/consul/consul_vars.yml b/playbooks/tasks/consul/consul_vars.yml index 8e2a3a8..9458a95 100644 --- a/playbooks/tasks/consul/consul_vars.yml +++ b/playbooks/tasks/consul/consul_vars.yml @@ -36,35 +36,14 @@ - name: "Consul | Merge token configuration" delegate_to: localhost block: - - name: "Consul | Stat consul secrets file" - ansible.builtin.stat: - path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - register: _consul_config_file - - - name: "Consul | Load consul secrets file" - ansible.builtin.include_vars: - file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - name: _consul_cluster_config - when: _consul_config_file.stat.exists - - name: "Consul | Merge token configuration" vars: _config_to_merge: acl: - tokens: "{{ _consul_cluster_config.tokens }}" + tokens: + agent: "{{ _credentials.consul.tokens.agent }}" ansible.builtin.set_fact: hashi_consul_configuration: "{{ hashi_consul_configuration | default({}) | combine(_config_to_merge, recursive=true) }}" - when: _consul_cluster_config.tokens is defined - - - name: "Consul | Create secrets file if not present" - ansible.builtin.file: - path: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - state: touch - owner: "{{ lookup('env', 'USER') }}" - group: "{{ lookup('env', 'USER') }}" - mode: "0644" - run_once: true - when: not _consul_config_file.stat.exists - name: "Consul | Merge extra configuration settings" vars: diff --git a/playbooks/tasks/haproxy/haproxy_deploy.yml b/playbooks/tasks/haproxy/haproxy_deploy.yml index 9b1a998..656aa5c 100644 --- a/playbooks/tasks/haproxy/haproxy_deploy.yml +++ b/playbooks/tasks/haproxy/haproxy_deploy.yml @@ -12,14 +12,9 @@ - name: "Register haproxy services in consul" when: enable_consul | bool block: - - name: "Load consul cluster variables" - ansible.builtin.include_vars: - file: "{{ sub_configuration_directories.consul_servers }}/consul_config.yml" - name: _consul_cluster_config - - name: "Register haproxy services in consul" community.general.consul: - token: "{{ _consul_cluster_config.root_token.secret_id }}" + token: "{{ _credentials.consul.root_token.secret_id }}" service_name: haproxy service_port: 80 interval: 20s diff --git a/playbooks/tasks/load_vars.yml b/playbooks/tasks/load_vars.yml index f8174e7..77a2527 100644 --- a/playbooks/tasks/load_vars.yml +++ b/playbooks/tasks/load_vars.yml @@ -1,68 +1,20 @@ --- # hashistack variable injection playbook - name: "Load global variables" - block: - - name: "Stat global configuration file" - ansible.builtin.stat: - path: "{{ configuration_directory }}/{{ configuration_global_vars_file }}" - register: _global_config_file - delegate_to: localhost + ansible.builtin.import_tasks: + file: misc/load_global_vars.yml - - name: "Make sure global configuration file exists" - ansible.builtin.assert: - that: - - _global_config_file.stat.exists - delegate_to: localhost - - - name: "Load global variables" - ansible.builtin.include_vars: - dir: "{{ configuration_directory }}" - files_matching: "{{ configuration_global_vars_file }}" - depth: 1 - delegate_to: localhost +- name: "Load credentials variables" + ansible.builtin.import_tasks: + file: misc/load_credentials_vars.yml - name: "Load group specific variables" - block: - - name: "Stat group specific config file" - ansible.builtin.stat: - path: "{{ configuration_directory }}/{{ group_name }}/{{ configuration_global_vars_file }}" - register: _group_config_file - loop: "{{ group_names }}" - loop_control: - loop_var: group_name - - - name: Load group specific variables - ansible.builtin.include_vars: - dir: "{{ configuration_directory }}/{{ item.group_name }}" - files_matching: "{{ configuration_global_vars_file }}" - depth: 1 - loop: "{{ _group_config_file.results }}" - when: item.stat.exists - and item.group_name in group_names - loop_control: - loop_var: item - delegate_to: localhost + ansible.builtin.import_tasks: + file: misc/load_group_vars.yml - name: "Load host specific variables" - block: - - name: "Stat host specific config file" - ansible.builtin.stat: - path: "{{ configuration_directory }}/{{ group_name }}/{{ inventory_hostname }}/{{ configuration_global_vars_file }}" - register: _host_config_file - loop: "{{ group_names }}" - loop_control: - loop_var: group_name - delegate_to: localhost - - - name: Load host specific variables - ansible.builtin.include_vars: - dir: "{{ configuration_directory }}/{{ item.group_name }}/{{ inventory_hostname }}" - files_matching: "{{ configuration_global_vars_file }}" - loop: "{{ _host_config_file.results }}" - when: item.stat.exists - loop_control: - loop_var: item - delegate_to: localhost + ansible.builtin.import_tasks: + file: misc/load_host_vars.yml - name: "Ensure remote directories exists" ansible.builtin.file: @@ -77,72 +29,8 @@ - "{{ hashistack_remote_data_dir }}" - name: "Load custom CA certificates" - block: - - name: "Check if CA directory exists" - ansible.builtin.stat: - path: "{{ sub_configuration_directories['certificates'] }}/ca" - register: _hashistack_ca_directory - delegate_to: localhost - - - name: "Find custom ca certificates to copy" - ansible.builtin.find: - paths: "{{ sub_configuration_directories['certificates'] }}/ca" - patterns: "*.crt" - register: _hashistack_cacert_files - delegate_to: localhost - when: _hashistack_ca_directory.stat.exists and _hashistack_ca_directory.stat.isdir - - - ansible.builtin.debug: - msg: "{{ _hashistack_cacert_files }}" - - - name: "Ensure remote ca directory exists" - ansible.builtin.file: - path: "{{ hashistack_remote_config_dir }}/ca" - state: directory - owner: root - group: root - mode: 0755 - - - name: "Copy custom ca certificates" - ansible.builtin.copy: - src: "{{ item.path }}" - dest: "{{ hashistack_remote_config_dir }}/ca/{{ item.path | basename }}" - owner: root - group: root - mode: 0644 - loop: "{{ _hashistack_cacert_files.files }}" - register: _hashistack_copied_ca - - - name: "Copy and update trust store" - block: - - name: "Copy ca certificates to /usr/loca/share/ca-certificates" - ansible.builtin.file: - state: link - src: "{{ item.dest }}" - dest: "/usr/local/share/ca-certificates/hashistack-customca-{{ item.dest | basename }}" - owner: root - group: root - loop: "{{ _hashistack_copied_ca.results }}" - register: _hashistack_usr_local_share_ca_certificates - - - name: "Update the trust store" - ansible.builtin.command: update-ca-certificates - changed_when: false - when: _hashistack_usr_local_share_ca_certificates.changed - - # - name: "Initialize list of CA certificates" - # ansible.builtin.set_fact: - # hashistack_cacert_extra_files: [] - # delegate_to: localhost - - # - name: "Add custom CA to list of extra certificates" - # ansible.builtin.set_fact: - # hashistack_cacert_extra_files: "{{ - # hashistack_cacert_extra_files | default([]) - # + [{'src': item.path, 'dest': '/etc/ssl/certs/hashistack-custom-' + item.path | basename}] }}" - # loop: "{{ _hashistack_cacert_files.files }}" - # delegate_to: localhost - # when: _hashistack_cacert_files.matched > 0 + ansible.builtin.import_tasks: + file: misc/load_ca_certificates.yml - name: "Merge consul configurations" ansible.builtin.import_tasks: @@ -157,10 +45,3 @@ when: - enable_vault | bool - "'vault_servers' in group_names" - -- debug: - msg: "{{ deploy_haproxy_frontends }}" - -- debug: - msg: "{{ deploy_haproxy_backends }}" -# - fail: diff --git a/playbooks/tasks/misc/load_all_vars.yml b/playbooks/tasks/misc/load_all_vars.yml new file mode 100644 index 0000000..9142d0d --- /dev/null +++ b/playbooks/tasks/misc/load_all_vars.yml @@ -0,0 +1,216 @@ +--- +# hashistack variable injection playbook +- name: "Load global variables" + block: + - name: "Stat global configuration file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ configuration_global_vars_file }}" + register: _global_config_file + delegate_to: localhost + + - name: "Make sure global configuration file exists" + ansible.builtin.assert: + that: + - _global_config_file.stat.exists + fail_msg: >- + Main configuration file {{ _global_config_file.stat.path }} was not found, cannot continue without it. + delegate_to: localhost + + - name: "Load global variables" + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}" + files_matching: "{{ configuration_global_vars_file }}" + depth: 1 + delegate_to: localhost + +- name: "Load credentials variables" + block: + - name: "Stat credentials file" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['secrets'] }}/{{ configuration_credentials_vars_file }}" + register: _credentials_file + delegate_to: localhost + + - name: "Stat vault credentials file" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['secrets'] }}/vault.yml" + register: _vault_credentials_file + delegate_to: localhost + + - name: "Make sure credentials file exists" + ansible.builtin.assert: + that: + - _credentials_file.stat.exists + fail_msg: >- + Credentials file {{ _credentials_file.stat.path }} was not found, cannot continue without it. + delegate_to: localhost + + - name: "Load credentials variables" + ansible.builtin.include_vars: + dir: "{{ sub_configuration_directories['secrets'] }}" + files_matching: "{{ configuration_credentials_vars_file }}" + depth: 1 + name: _credentials + delegate_to: localhost + + - name: "Load vault credentials if vault.yml exists" + ansible.builtin.include_vars: + dir: "{{ sub_configuration_directories['secrets'] }}" + files_matching: "vault.yml" + depth: 1 + name: _vault_credentials + when: _vault_credentials_file.stat.exists + delegate_to: localhost + + - name: "Merge vault credentials into _credentials" + vars: + _config_to_merge: + vault: "{{ _vault_credentials }}" + ansible.builtin.set_fact: + _credentials: "{{ _credentials | combine(_vault_credentials, recursive=true) }}" + when: _vault_credentials_file.stat.exists + delegate_to: localhost + +- name: "Load group specific variables" + block: + - name: "Stat group specific config file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ group_name }}/{{ configuration_global_vars_file }}" + register: _group_config_file + loop: "{{ group_names }}" + loop_control: + loop_var: group_name + + - name: Load group specific variables + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}/{{ item.group_name }}" + files_matching: "{{ configuration_global_vars_file }}" + depth: 1 + loop: "{{ _group_config_file.results }}" + when: item.stat.exists + and item.group_name in group_names + loop_control: + loop_var: item + delegate_to: localhost + +- name: "Load host specific variables" + block: + - name: "Stat host specific config file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ group_name }}/{{ inventory_hostname }}/{{ configuration_global_vars_file }}" + register: _host_config_file + loop: "{{ group_names }}" + loop_control: + loop_var: group_name + delegate_to: localhost + + - name: Load host specific variables + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}/{{ item.group_name }}/{{ inventory_hostname }}" + files_matching: "{{ configuration_global_vars_file }}" + loop: "{{ _host_config_file.results }}" + when: item.stat.exists + loop_control: + loop_var: item + delegate_to: localhost + +- name: "Ensure remote directories exists" + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: 0755 + recurse: yes + loop: + - "{{ hashistack_remote_config_dir }}" + - "{{ hashistack_remote_data_dir }}" + +- name: "Load custom CA certificates" + block: + - name: "Check if CA directory exists" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['certificates'] }}/ca" + register: _hashistack_ca_directory + delegate_to: localhost + + - name: "Find custom ca certificates to copy" + ansible.builtin.find: + paths: "{{ sub_configuration_directories['certificates'] }}/ca" + patterns: "*.crt" + register: _hashistack_cacert_files + delegate_to: localhost + when: _hashistack_ca_directory.stat.exists and _hashistack_ca_directory.stat.isdir + + - ansible.builtin.debug: + msg: "{{ _hashistack_cacert_files }}" + + - name: "Ensure remote ca directory exists" + ansible.builtin.file: + path: "{{ hashistack_remote_config_dir }}/ca" + state: directory + owner: root + group: root + mode: 0755 + + - name: "Copy custom ca certificates" + ansible.builtin.copy: + src: "{{ item.path }}" + dest: "{{ hashistack_remote_config_dir }}/ca/{{ item.path | basename }}" + owner: root + group: root + mode: 0644 + loop: "{{ _hashistack_cacert_files.files }}" + register: _hashistack_copied_ca + + - name: "Copy and update trust store" + block: + - name: "Copy ca certificates to /usr/loca/share/ca-certificates" + ansible.builtin.file: + state: link + src: "{{ item.dest }}" + dest: "/usr/local/share/ca-certificates/hashistack-customca-{{ item.dest | basename }}" + owner: root + group: root + loop: "{{ _hashistack_copied_ca.results }}" + register: _hashistack_usr_local_share_ca_certificates + + - name: "Update the trust store" + ansible.builtin.command: update-ca-certificates + changed_when: false + when: _hashistack_usr_local_share_ca_certificates.changed + + # - name: "Initialize list of CA certificates" + # ansible.builtin.set_fact: + # hashistack_cacert_extra_files: [] + # delegate_to: localhost + + # - name: "Add custom CA to list of extra certificates" + # ansible.builtin.set_fact: + # hashistack_cacert_extra_files: "{{ + # hashistack_cacert_extra_files | default([]) + # + [{'src': item.path, 'dest': '/etc/ssl/certs/hashistack-custom-' + item.path | basename}] }}" + # loop: "{{ _hashistack_cacert_files.files }}" + # delegate_to: localhost + # when: _hashistack_cacert_files.matched > 0 + +- name: "Merge consul configurations" + ansible.builtin.import_tasks: + file: "consul/consul_vars.yml" + when: + - enable_consul | bool + - "('consul_servers' in group_names) or ('consul_agents' in group_names)" + +- name: "Merge vault configurations" + ansible.builtin.import_tasks: + file: "vault/vault_vars.yml" + when: + - enable_vault | bool + - "'vault_servers' in group_names" + +- debug: + msg: "{{ deploy_haproxy_frontends }}" + +- debug: + msg: "{{ deploy_haproxy_backends }}" +# - fail: diff --git a/playbooks/tasks/misc/load_ca_certificates.yml b/playbooks/tasks/misc/load_ca_certificates.yml new file mode 100644 index 0000000..5999284 --- /dev/null +++ b/playbooks/tasks/misc/load_ca_certificates.yml @@ -0,0 +1,52 @@ +--- +- name: "Check if CA directory exists" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['certificates'] }}/ca" + register: _hashistack_ca_directory + delegate_to: localhost + +- name: "Find custom ca certificates to copy" + ansible.builtin.find: + paths: "{{ sub_configuration_directories['certificates'] }}/ca" + patterns: "*.crt" + register: _hashistack_cacert_files + delegate_to: localhost + when: _hashistack_ca_directory.stat.exists and _hashistack_ca_directory.stat.isdir + +- ansible.builtin.debug: + msg: "{{ _hashistack_cacert_files }}" + +- name: "Ensure remote ca directory exists" + ansible.builtin.file: + path: "{{ hashistack_remote_config_dir }}/ca" + state: directory + owner: root + group: root + mode: 0755 + +- name: "Copy custom ca certificates" + ansible.builtin.copy: + src: "{{ item.path }}" + dest: "{{ hashistack_remote_config_dir }}/ca/{{ item.path | basename }}" + owner: root + group: root + mode: 0644 + loop: "{{ _hashistack_cacert_files.files }}" + register: _hashistack_copied_ca + +- name: "Copy and update trust store" + block: + - name: "Copy ca certificates to /usr/loca/share/ca-certificates" + ansible.builtin.file: + state: link + src: "{{ item.dest }}" + dest: "/usr/local/share/ca-certificates/hashistack-customca-{{ item.dest | basename }}" + owner: root + group: root + loop: "{{ _hashistack_copied_ca.results }}" + register: _hashistack_usr_local_share_ca_certificates + + - name: "Update the trust store" + ansible.builtin.command: update-ca-certificates + changed_when: false + when: _hashistack_usr_local_share_ca_certificates.changed diff --git a/playbooks/tasks/misc/load_credentials_vars.yml b/playbooks/tasks/misc/load_credentials_vars.yml new file mode 100644 index 0000000..d448f78 --- /dev/null +++ b/playbooks/tasks/misc/load_credentials_vars.yml @@ -0,0 +1,50 @@ +--- +- name: "Stat credentials file" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['secrets'] }}/{{ configuration_credentials_vars_file }}" + register: _credentials_file + delegate_to: localhost + +- name: "Stat vault credentials file" + ansible.builtin.stat: + path: "{{ sub_configuration_directories['secrets'] }}/vault.yml" + register: _vault_credentials_file + delegate_to: localhost + +- name: "Make sure credentials file exists" + ansible.builtin.assert: + that: + - _credentials_file.stat.exists + fail_msg: >- + Credentials file {{ _credentials_file.stat.path }} was not found, cannot continue without it. + delegate_to: localhost + +- name: "Load credentials variables" + ansible.builtin.include_vars: + dir: "{{ sub_configuration_directories['secrets'] }}" + files_matching: "{{ configuration_credentials_vars_file }}" + depth: 1 + name: _credentials + delegate_to: localhost + +- name: "Load vault credentials if vault.yml exists" + ansible.builtin.include_vars: + dir: "{{ sub_configuration_directories['secrets'] }}" + files_matching: "vault.yml" + depth: 1 + name: _vault_credentials + when: _vault_credentials_file.stat.exists + delegate_to: localhost + +- name: "Merge vault credentials into _credentials" + vars: + _config_to_merge: + vault: "{{ _vault_credentials }}" + ansible.builtin.set_fact: + _credentials: "{{ _credentials | combine(_config_to_merge, recursive=true) }}" + when: _vault_credentials_file.stat.exists + delegate_to: localhost + +- name: "Debug _credentials" + ansible.builtin.debug: + msg: "{{ _credentials }}" diff --git a/playbooks/tasks/misc/load_global_vars.yml b/playbooks/tasks/misc/load_global_vars.yml new file mode 100644 index 0000000..e162ee9 --- /dev/null +++ b/playbooks/tasks/misc/load_global_vars.yml @@ -0,0 +1,21 @@ +--- +- name: "Stat global configuration file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ configuration_global_vars_file }}" + register: _global_config_file + delegate_to: localhost + +- name: "Make sure global configuration file exists" + ansible.builtin.assert: + that: + - _global_config_file.stat.exists + fail_msg: >- + Main configuration file {{ _global_config_file.stat.path }} was not found, cannot continue without it. + delegate_to: localhost + +- name: "Load global variables" + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}" + files_matching: "{{ configuration_global_vars_file }}" + depth: 1 + delegate_to: localhost diff --git a/playbooks/tasks/misc/load_group_vars.yml b/playbooks/tasks/misc/load_group_vars.yml new file mode 100644 index 0000000..d21a475 --- /dev/null +++ b/playbooks/tasks/misc/load_group_vars.yml @@ -0,0 +1,20 @@ +--- +- name: "Stat group specific config file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ group_name }}/{{ configuration_global_vars_file }}" + register: _group_config_file + loop: "{{ group_names }}" + loop_control: + loop_var: group_name + +- name: Load group specific variables + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}/{{ item.group_name }}" + files_matching: "{{ configuration_global_vars_file }}" + depth: 1 + loop: "{{ _group_config_file.results }}" + when: item.stat.exists + and item.group_name in group_names + loop_control: + loop_var: item + delegate_to: localhost diff --git a/playbooks/tasks/misc/load_host_vars.yml b/playbooks/tasks/misc/load_host_vars.yml new file mode 100644 index 0000000..c95c2b7 --- /dev/null +++ b/playbooks/tasks/misc/load_host_vars.yml @@ -0,0 +1,19 @@ +--- +- name: "Stat host specific config file" + ansible.builtin.stat: + path: "{{ configuration_directory }}/{{ group_name }}/{{ inventory_hostname }}/{{ configuration_global_vars_file }}" + register: _host_config_file + loop: "{{ group_names }}" + loop_control: + loop_var: group_name + delegate_to: localhost + +- name: Load host specific variables + ansible.builtin.include_vars: + dir: "{{ configuration_directory }}/{{ item.group_name }}/{{ inventory_hostname }}" + files_matching: "{{ configuration_global_vars_file }}" + loop: "{{ _host_config_file.results }}" + when: item.stat.exists + loop_control: + loop_var: item + delegate_to: localhost diff --git a/playbooks/tasks/vault/vault_deploy.yml b/playbooks/tasks/vault/vault_deploy.yml index ade6fc2..3d2de38 100644 --- a/playbooks/tasks/vault/vault_deploy.yml +++ b/playbooks/tasks/vault/vault_deploy.yml @@ -20,8 +20,8 @@ - name: "Write vault configuration to file" # noqa: run-once[task] no-handler ansible.builtin.copy: - content: "{{ _vault_init_secret.state | to_nice_yaml}}" - dest: "{{ sub_configuration_directories.vault_servers }}/vault_config.yml" + content: "{{ _vault_init_secret.state | to_nice_yaml(indent=2) }}" + dest: "{{ sub_configuration_directories.secrets }}/vault.yml" owner: "{{ lookup('env', 'USER') }}" group: "{{ lookup('env', 'USER') }}" mode: "0644" @@ -29,16 +29,20 @@ run_once: true delegate_to: localhost + # - name: "Load vault cluster variables necessary for unseal operation" + # ansible.builtin.include_vars: + # file: "{{ sub_configuration_directories.vault_servers }}/vault_config.yml" + # name: _vault_cluster_config + - name: "Load vault cluster variables necessary for unseal operation" - ansible.builtin.include_vars: - file: "{{ sub_configuration_directories.vault_servers }}/vault_config.yml" - name: _vault_cluster_config + ansible.builtin.import_tasks: + file: ../misc/load_credentials_vars.yml - name: "Unseal the bootstrap node" # noqa: run-once[task] no-handler ednz_cloud.hashistack.vault_unseal: api_url: "{{ hashi_vault_configuration['api_addr'] }}" tls_verify: "{{ vault_tls_verify }}" - key_shares: "{{ _vault_cluster_config['keys'] }}" + key_shares: "{{ _credentials.vault['keys'] }}" run_once: true delegate_to: "{{ groups['vault_servers'] | first }}" when: _vault_init_secret.changed @@ -48,7 +52,7 @@ ednz_cloud.hashistack.vault_unseal: api_url: "{{ hashi_vault_configuration['api_addr'] }}" tls_verify: "{{ vault_tls_verify }}" - key_shares: "{{ _vault_cluster_config['keys'] }}" + key_shares: "{{ _credentials.vault['keys'] }}" retries: 5 delay: 5 until: _unseal_status.changed or not _unseal_status.failed diff --git a/playbooks/templates/credentials.yml.j2 b/playbooks/templates/credentials.yml.j2 new file mode 100644 index 0000000..662a7bc --- /dev/null +++ b/playbooks/templates/credentials.yml.j2 @@ -0,0 +1,8 @@ +--- +consul: + root_token: + secret_id: "{{ _consul_root_token }}" + tokens: + agent: "{{ _consul_agents_token }}" +nomad: + root_token: "{{ _nomad_root_token }}"