From 08bd6815bdf58e384b29c38d4a256439a36f3571 Mon Sep 17 00:00:00 2001 From: Scott Solkhon Date: Fri, 2 Sep 2022 15:45:18 +0100 Subject: [PATCH] Add Hashi Vault support for Kolla passwords This commit adds the necessary changes needed to support reading and writing Kolla passwords to a Hashicorp Vault server using Kolla-Ansible commands `kolla-readpwd` and `kolla-writepwd`. This follows the support that was added into Kolla-Ansible in the Change-Id Icf0eaf7544fcbdf7b83f697cc711446f47118a4d. Change-Id: I732988e6160cc64d663d6ef8179f04d3e1226537 --- ansible/inventory/group_vars/all/kolla | 10 ++ ansible/roles/kolla-ansible/defaults/main.yml | 10 ++ .../kolla-ansible/library/kolla_passwords.py | 93 +++++++++++++++++++ ansible/roles/kolla-ansible/tasks/config.yml | 8 ++ etc/kayobe/kolla.yml | 13 +++ ...ault-kolla-passwords-c4584aeeecd36e80.yaml | 5 + requirements.txt | 1 + 7 files changed, 140 insertions(+) create mode 100644 releasenotes/notes/hashi-vault-kolla-passwords-c4584aeeecd36e80.yaml diff --git a/ansible/inventory/group_vars/all/kolla b/ansible/inventory/group_vars/all/kolla index daf4fa799..8df525403 100644 --- a/ansible/inventory/group_vars/all/kolla +++ b/ansible/inventory/group_vars/all/kolla @@ -456,6 +456,16 @@ kolla_ansible_target_venv: "{{ virtualenv_path ~ '/kolla-ansible' }}" # Password to use to encrypt the kolla-ansible passwords.yml file. kolla_ansible_vault_password: "{{ lookup('env', 'KAYOBE_VAULT_PASSWORD') | default }}" +# Hashi Vault +kolla_ansible_vault_addr: "{{ lookup('env', 'KAYOBE_VAULT_ADDR') | default }}" +kolla_ansible_vault_mount_point: "{{ lookup('env', 'KAYOBE_VAULT_MOUNT_POINT') | default }}" +kolla_ansible_vault_kv_path: "{{ lookup('env', 'KAYOBE_VAULT_KV_PATH') | default }}" +kolla_ansible_vault_namespace: "{{ lookup('env', 'KAYOBE_VAULT_NAMESPACE') | default }}" +kolla_ansible_vault_role_id: "{{ lookup('env', 'KAYOBE_VAULT_ROLE_ID') | default }}" +kolla_ansible_vault_secret_id: "{{ lookup('env', 'KAYOBE_VAULT_SECRET_ID') | default }}" +kolla_ansible_vault_token: "{{ lookup('env', 'KAYOBE_VAULT_TOKEN') | default }}" +kolla_ansible_vault_cacert: "{{ lookup('env', 'KAYOBE_VAULT_CACERT') | default }}" + # Whether TLS is enabled for the external API endpoints. kolla_enable_tls_external: "{{ kolla_enable_tls_internal if public_net_name == internal_net_name else 'no' }}" diff --git a/ansible/roles/kolla-ansible/defaults/main.yml b/ansible/roles/kolla-ansible/defaults/main.yml index 3cee9c96c..82458f77f 100644 --- a/ansible/roles/kolla-ansible/defaults/main.yml +++ b/ansible/roles/kolla-ansible/defaults/main.yml @@ -43,6 +43,16 @@ kolla_ansible_install_epel: false # Password to use to encrypt the passwords.yml file. kolla_ansible_vault_password: +# Hashi Vault +kolla_ansible_vault_addr: +kolla_ansible_vault_mount_point: +kolla_ansible_vault_kv_path: +kolla_ansible_vault_namespace: +kolla_ansible_vault_role_id: +kolla_ansible_vault_secret_id: +kolla_ansible_vault_token: +kolla_ansible_vault_cacert: + # Directory where Kolla config files will be installed. kolla_config_path: diff --git a/ansible/roles/kolla-ansible/library/kolla_passwords.py b/ansible/roles/kolla-ansible/library/kolla_passwords.py index 049f2b09f..4c728f75f 100644 --- a/ansible/roles/kolla-ansible/library/kolla_passwords.py +++ b/ansible/roles/kolla-ansible/library/kolla_passwords.py @@ -51,6 +51,49 @@ def kolla_mergepwd(module, old_path, new_path, final_path): module.run_command(cmd, check_rc=True, path_prefix=virtualenv_path_prefix(module)) +def kolla_readpwd(module, file_path, vault_addr="", vault_mount_point="", vault_kv_path="", + vault_namespace="", vault_role_id=None, vault_secret_id=None, + vault_token=None, vault_cacert=""): + """Run the kolla-readpwd command.""" + + if vault_role_id and vault_secret_id: + vault_auth = ["--vault-role-id", vault_role_id, + "--vault-secret-id", vault_secret_id] + else: + vault_auth = ["--vault-token", vault_token] + + cmd = ["kolla-readpwd", + "--passwords", file_path, + "--vault-addr", vault_addr, + "--vault-mount-point", vault_mount_point, + "--vault-kv-path", vault_kv_path, + "--vault-namespace", vault_namespace, + "--vault-cacert", vault_cacert] + vault_auth + + module.run_command(cmd, check_rc=True, + path_prefix=virtualenv_path_prefix(module)) + +def kolla_writepwd(module, file_path, vault_addr="", vault_mount_point="", vault_kv_path="", + vault_namespace="", vault_role_id=None, vault_secret_id=None, + vault_token=None, vault_cacert=""): + """Run the kolla-writepwd command.""" + + if vault_role_id and vault_secret_id: + vault_auth = ["--vault-role-id", vault_role_id, + "--vault-secret-id", vault_secret_id, ] + else: + vault_auth = ["--vault-token", vault_token, ] + cmd = ["kolla-writepwd", + "--passwords", file_path, + "--vault-addr", vault_addr, + "--vault-mount-point", vault_mount_point, + "--vault-kv-path", vault_kv_path, + "--vault-namespace", vault_namespace, + "--vault-cacert", vault_cacert] + vault_auth + + module.run_command(cmd, check_rc=True, + path_prefix=virtualenv_path_prefix(module)) + def create_vault_password_file(module): """Create a vault password file.""" @@ -128,6 +171,33 @@ def kolla_passwords(module): finally: os.unlink(src_path) + if module.params['vault_addr']: + src_path = create_named_tempfile() + try: + shutil.copyfile(module.params['src'], src_path) + kolla_readpwd(module, src_path, + module.params['vault_addr'], + module.params['vault_mount_point'], + module.params['vault_kv_path'], + module.params['vault_namespace'], + module.params['vault_role_id'], + module.params['vault_secret_id'], + module.params['vault_token'], + module.params['vault_cacert']) + kolla_mergepwd(module, src_path, temp_file_path, temp_file_path) + kolla_genpwd(module, temp_file_path) + kolla_writepwd(module, temp_file_path, + module.params['vault_addr'], + module.params['vault_mount_point'], + module.params['vault_kv_path'], + module.params['vault_namespace'], + module.params['vault_role_id'], + module.params['vault_secret_id'], + module.params['vault_token'], + module.params['vault_cacert']) + finally: + os.unlink(src_path) + # Merge in overrides. if module.params['overrides']: with tempfile.NamedTemporaryFile(delete=False) as f: @@ -137,6 +207,16 @@ def kolla_passwords(module): overrides_path = f.name try: kolla_mergepwd(module, overrides_path, temp_file_path, temp_file_path) + if module.params['vault_addr']: + kolla_writepwd(module, temp_file_path, + module.params['vault_addr'], + module.params['vault_mount_point'], + module.params['vault_kv_path'], + module.params['vault_namespace'], + module.params['vault_role_id'], + module.params['vault_secret_id'], + module.params['vault_token'], + module.params['vault_cacert']) finally: os.unlink(overrides_path) @@ -189,10 +269,23 @@ def main(): sample=dict(default='/usr/share/kolla-ansible/etc_examples/kolla/passwords.yml', type='str'), src=dict(default='/etc/kolla/passwords.yml', type='str'), vault_password=dict(type='str', no_log=True), + vault_addr=dict(type='str', no_log=False), + vault_mount_point=dict(type='str', no_log=False), + vault_kv_path=dict(type='str', no_log=False), + vault_namespace=dict(type='str', no_log=False), + vault_role_id=dict(type='str', no_log=True), + vault_secret_id=dict(type='str', no_log=True), + vault_token=dict(type='str', no_log=True), + vault_cacert=dict(type='str', no_log=False), virtualenv=dict(type='str'), ), add_file_common_args=True, supports_check_mode=True, + required_together=[['vault_mount_point', 'vault_addr'], + ['vault_role_id', 'vault_secret_id'], + ['vault_mount_point','vault_kv_path']], + mutually_exclusive=[['vault_token', 'vault_role_id'], + ['vault_token', 'vault_secret_id']] ) if IMPORT_ERRORS: diff --git a/ansible/roles/kolla-ansible/tasks/config.yml b/ansible/roles/kolla-ansible/tasks/config.yml index 8f4ad0a23..917e996a7 100644 --- a/ansible/roles/kolla-ansible/tasks/config.yml +++ b/ansible/roles/kolla-ansible/tasks/config.yml @@ -98,6 +98,14 @@ sample: "{{ kolla_ansible_install_dir }}/etc_examples/kolla/passwords.yml" overrides: "{{ kolla_ansible_custom_passwords }}" vault_password: "{{ kolla_ansible_vault_password }}" + vault_addr: "{{ kolla_ansible_vault_addr }}" + vault_mount_point: "{{ kolla_ansible_vault_mount_point }}" + vault_kv_path: "{{ kolla_ansible_vault_kv_path }}" + vault_namespace: "{{ kolla_ansible_vault_namespace }}" + vault_role_id: "{{ kolla_ansible_vault_role_id or omit }}" + vault_secret_id: "{{ kolla_ansible_vault_secret_id or omit }}" + vault_token: "{{ kolla_ansible_vault_token or omit }}" + vault_cacert: "{{ kolla_ansible_vault_cacert }}" virtualenv: "{{ kolla_ansible_venv or omit }}" - name: Ensure the Kolla passwords file is copied into place diff --git a/etc/kayobe/kolla.yml b/etc/kayobe/kolla.yml index 2d975b260..dfacff22f 100644 --- a/etc/kayobe/kolla.yml +++ b/etc/kayobe/kolla.yml @@ -235,6 +235,19 @@ # remotely on the target nodes. If None, no virtualenv will be used. #kolla_ansible_target_venv: +# Password to use to encrypt the kolla-ansible passwords.yml file. +#kolla_ansible_vault_password: + +# Hashi Vault +#kolla_ansible_vault_addr: +#kolla_ansible_vault_mount_point: +#kolla_ansible_vault_kv_path: +#kolla_ansible_vault_namespace: +#kolla_ansible_vault_role_id: +#kolla_ansible_vault_secret_id: +#kolla_ansible_vault_token: +#kolla_ansible_vault_cacert: + # Whether TLS is enabled for the external API endpoints. Default is 'no'. #kolla_enable_tls_external: diff --git a/releasenotes/notes/hashi-vault-kolla-passwords-c4584aeeecd36e80.yaml b/releasenotes/notes/hashi-vault-kolla-passwords-c4584aeeecd36e80.yaml new file mode 100644 index 000000000..ad7ed7a6b --- /dev/null +++ b/releasenotes/notes/hashi-vault-kolla-passwords-c4584aeeecd36e80.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds functionality into the kolla_passwords module to allow passwords that + are generated for Kolla Ansible to be stored in Hashicorp Vault. diff --git a/requirements.txt b/requirements.txt index 2f4e5b8f7..19decf8ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ selinux # MIT oslo.config>=5.2.0 # Apache-2.0 paramiko # LGPL jsonschema<5 # MIT +hvac>=0.10.1