From fcea07bbef71683362c4761cade109f5ffe2f7a3 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 7 Oct 2022 10:05:46 -0400 Subject: [PATCH] Custom salt for ansible-vault encrypt (#79063) * Custom salt for ansible-vault encrypt add VAULT_ENCRYPT_SALT config add salt testing Co-authored-by: Abhijeet Kasurde Co-authored-by: Piotr Stawarski --- .../71424-deterministic-vault-encode.yml | 2 ++ lib/ansible/config/base.yml | 8 ++++++++ lib/ansible/parsing/vault/__init__.py | 9 ++++++++- .../targets/ansible-vault/runme.sh | 20 +++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/71424-deterministic-vault-encode.yml diff --git a/changelogs/fragments/71424-deterministic-vault-encode.yml b/changelogs/fragments/71424-deterministic-vault-encode.yml new file mode 100644 index 00000000000..39a4afc6375 --- /dev/null +++ b/changelogs/fragments/71424-deterministic-vault-encode.yml @@ -0,0 +1,2 @@ +minor_changes: + - Add support for custom salt for vault encoding to make it deterministic (https://github.com/ansible/ansible/issues/35480). diff --git a/lib/ansible/config/base.yml b/lib/ansible/config/base.yml index 1901accf282..80619558b73 100644 --- a/lib/ansible/config/base.yml +++ b/lib/ansible/config/base.yml @@ -1147,6 +1147,14 @@ DEFAULT_VAULT_IDENTITY: ini: - {key: vault_identity, section: defaults} yaml: {key: defaults.vault_identity} +VAULT_ENCRYPT_SALT: + name: Vault salt to use for encryption + default: ~ + description: 'The salt to use for the vault encryption. If it is not provided, a random salt will be used.' + env: [{name: ANSIBLE_VAULT_ENCRYPT_SALT}] + ini: + - {key: vault_encrypt_salt, section: defaults} + version_added: '2.15' DEFAULT_VAULT_ENCRYPT_IDENTITY: name: Vault id to use for encryption description: 'The vault_id to use for encrypting by default. If multiple vault_ids are provided, this specifies which to use for encryption. The --encrypt-vault-id cli option overrides the configured value.' diff --git a/lib/ansible/parsing/vault/__init__.py b/lib/ansible/parsing/vault/__init__.py index 5a06c63625a..9e5afd00cdd 100644 --- a/lib/ansible/parsing/vault/__init__.py +++ b/lib/ansible/parsing/vault/__init__.py @@ -1195,6 +1195,13 @@ class VaultAES256: return to_bytes(hexlify(b_hmac), errors='surrogate_or_strict'), hexlify(b_ciphertext) + @classmethod + def _get_salt(cls): + custom_salt = C.config.get_config_value('VAULT_ENCRYPT_SALT') + if not custom_salt: + custom_salt = os.urandom(32) + return to_bytes(custom_salt) + @classmethod def encrypt(cls, b_plaintext, secret, salt=None): @@ -1202,7 +1209,7 @@ class VaultAES256: raise AnsibleVaultError('The secret passed to encrypt() was None') if salt is None: - b_salt = os.urandom(32) + b_salt = cls._get_salt() elif not salt: raise AnsibleVaultError('Empty or invalid salt passed to encrypt()') else: diff --git a/test/integration/targets/ansible-vault/runme.sh b/test/integration/targets/ansible-vault/runme.sh index 50720ea9f90..94b80078263 100755 --- a/test/integration/targets/ansible-vault/runme.sh +++ b/test/integration/targets/ansible-vault/runme.sh @@ -574,3 +574,23 @@ ansible-playbook realpath.yml "$@" --vault-password-file symlink/get-password-sy # using symlink ansible-playbook symlink.yml "$@" --vault-password-file script/vault-secret.sh 2>&1 |grep "${ER}" + +### SALT TESTING ### +# prep files for encryption +for salted in test1 test2 test3 +do + echo 'this is salty' > "salted_${salted}" +done + +# encrypt files +ANSIBLE_VAULT_ENCRYPT_SALT=salty ansible-vault encrypt salted_test1 --vault-password-file example1_password "$@" +ANSIBLE_VAULT_ENCRYPT_SALT=salty ansible-vault encrypt salted_test2 --vault-password-file example1_password "$@" +ansible-vault encrypt salted_test3 --vault-password-file example1_password "$@" + +# should be the same +out=$(diff salted_test1 salted_test2) +[ "${out}" == "" ] + +# shoudl be diff +out=$(diff salted_test1 salted_test3 || true) +[ "${out}" != "" ]