How to decrypt string with ansible-vault 2.3.0

2020-05-24 18:56发布

问题:

I have been waiting for ansible 2.3 as it was going to introduce encrypt_string feature.

Unfortuately I'm not sure how can I read the encrypted string.

I did try decrypt_string, decrypt (the file), view (the file) and nothing works.

cat test.yml 
---
test: !vault |
     $ANSIBLE_VAULT;1.1;AES256
     37366638363362303836383335623066343562666662386233306537333232396637346463376430
     3664323265333036663736383837326263376637616466610a383430623562633235616531303861
     66313432303063343230613665323930386138613334303839626131373033656463303736366166
     6635346135636437360a313031376566303238303835353364313434363163343066363932346165
     6136

The error I'm geeting is ERROR! input is not vault encrypted data for test.yml

How can I decrypt the string so I know what it's value without the need to run the play?

回答1:

Did you try setting the encrypted string as a variable and then using -debug to get its decrypted output?

i.e.

Define your encrypted string as a variable test in your playbook and then do:

-debug: msg="My Secret value is {{test | replace('\n', '')}}"

in your playbook and then run the playbook:

$ ansible-playbook -i localhost YourPlaybook.yml --vault-password-file path/to/your/secret_key_file


回答2:

You can also do with plain ansible command for respective host/group/inventory combination, e.g.:

$ ansible my_server -m debug -a 'var=my_secret'
my_server | SUCCESS => {
    "my_secret": "373861663362363036363361663037373661353137303762"
}


回答3:

You can pipe the input then tell ansible-vault to output to stderr and then redirect the stdout to /dev/null since the tool prints Decryption successful.

Something like:

echo 'YOUR_SECRET_VALUE' | ansible-vault decrypt /dev/stdin --output=/dev/stderr > /dev/null

Here is a example:

echo '$ANSIBLE_VAULT;1.1;AES256
30636561663762383436386639353737363431353033326634623639666132623738643764366530
6332363635613832396361333634303135663735356134350a383265333537383739353864663136
30393363653361373738656361613435626237643633383261663138653466393332333036353737
3335396631613239380a616531626235346361333737353831376633633264326566623339663463
6235' | ansible-vault decrypt /dev/stdin --output=/dev/stderr > /dev/null

I hope they implement a simpler way of doing this.

Edit: Environment Variables as Input:

To have a similar behaviour with multi-line environment variables on bash use printf instead of echo

Example (password: 123):

export chiphertext='$ANSIBLE_VAULT;1.1;AES256
65333363656231663530393762613031336662613262326666386233643763636339366235626334
3236636366366131383962323463633861653061346538360a386566363337383133613761313566
31623761656437393862643936373564313565663633636366396231653131386364336534626338
3430343561626237660a333562616537623035396539343634656439356439616439376630396438
3730'

printf "%s\n" $chiphertext | ansible-vault decrypt /dev/stdin --output=/dev/stderr > /dev/null


回答4:

since whole vault files do not play well with git histories, using vault strings within the variable files is the way to go, it also makes grepping out variables by name much clearer.

Here is a simple worked example:

I want to put fredsSecretString: value into vars.yml , (its value is fastfredfedfourfrankfurters but hush, don't let people know !!)

$ ansible-vault encrypt_string 'fastfredfedfourfrankfurters' -n fredsSecretString >> vars.yml
New Vault password: fred
Confirm New Vault password: fred
$ cat vars.yml
fredsSecretString: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          36643662303931336362356361373334663632343139383832626130636237333134373034326565
          3736626632306265393565653338356138626433333339310a323832663233316666353764373733
          30613239313731653932323536303537623362653464376365383963373366336335656635666637
          3238313530643164320a336337303734303930303163326235623834383337343363326461653162
          33353861663464313866353330376566346636303334353732383564633263373862

To decrypt the value feed the encrypted string back into ansible-vault as follows:

    $ echo '$ANSIBLE_VAULT;1.1;AES256
    36643662303931336362356361373334663632343139383832626130636237333134373034326565
    3736626632306265393565653338356138626433333339310a323832663233316666353764373733
    30613239313731653932323536303537623362653464376365383963373366336335656635666637
    3238313530643164320a336337303734303930303163326235623834383337343363326461653162
    33353861663464313866353330376566346636303334353732383564633263373862' |
 ansible-vault decrypt && echo
    Vault password: fred
    Decryption successful
    fastfredfedfourfrankfurters
    $


回答5:

Here is what works for me, similar to what Scudelletti does but passing in the vault pass i.e.

echo '$ANSIBLE_VAULT;1.1;AES256
31363861346536343331393539323936346464386534346337306565626466393764666366363637
6533373165656431393662653463646430663933363431380a336130363131373238326330393931
39343533396161323834613030383339653633393133393932613562396630303530393030396335
3630656237663038630a363032373633363161633464653431386237333262343231313830363965
31393930343532323133386536376637373463396534623631633234393565373337613530643031
38393862616635326339373731353465303364303365336132613566396666626536636533303839
393465653830393231636638643735313666' | ansible-vault decrypt --vault-password-file /path/to/your/.vault_pass.txt /dev/stdin --output=/dev/stderr > /dev/null && echo

The output will be on its own line for convenience, thanks to the trailing && echo. The permission of my vault pass is 644 if you run into any permission errors.

Hope it helps!



回答6:

yq extracts the encrypted var value, then will create a temporary file and use it with ansible-vault:

cat ansible_file.yml | yq -r ".variable_name" > tmp_file.txt

# you can also use 'ansible-vault decrypt'
ansible-vault view --ask-vault-pass tmp_file.txt


回答7:

Here's another way to decrypt strings

$ ansible localhost \
       -m debug \
       -a "var=mysecret" \
       -e "@inventory/group_vars/master"
localhost | SUCCESS => {
"mysecret": "somesecret\n"
}

The trick here is we're passing a file with an Ansible vaulted secret, mysecret within it too ansible and it's able to decrypt it.

NOTE: If you do not have your password to decrypt the Ansible vaulted encrypted secret you can pass that in as well:

$ ansible localhost --vault-password-file=~/.vault_pass.txt \
       -m debug \
       -a "var=mysecret" \
       -e "@inventory/group_vars/master"
localhost | SUCCESS => {
"mysecret": "somesecret\n"
}


回答8:

Although, there is no problems showing encrypted string values with ansible debug messages or using ansible cli, there is one more solution that may be convenient for automation needs. You can utilize python libs from ansible and use them in your code (basically, all this located in ansible.parsing.*)

1) Provide vault password and generate "vault" with secrets.

# Load vault password and prepare secrets for decryption
loader = DataLoader()
secret = vault.get_file_vault_secret(filename=vault_password_file, loader=loader)
secret.load()
vault_secrets = [('default', secret)]
_vault = vault.VaultLib(vault_secrets)

2) Load yaml file with AnsibleLoader:

with codecs.open(input_file, 'r', encoding='utf-8') as f:
    loaded_yaml = AnsibleLoader(f, vault_secrets=_vault.secrets).get_single_data()

3) If you need to encrypt a new string and update your dictionary:

    new_encrypted_value = objects.AnsibleVaultEncryptedUnicode.from_plaintext(source_system_password, _vault, vault_secrets[0][1])
    loaded_yaml[target_env]['credentials'][external_system_name]['password'] = new_encrypted_variable

4) Once complete processing, write back with AnsibleDumper:

with open('new_variables.yml','w') as fd:
    yaml.dump(loaded_yaml, fd, Dumper=AnsibleDumper, encoding=None, default_flow_style=False)


回答9:

This one command extracts out just the encrypted data and passes it to decrypt. I like it a bit better, as you don't need to manually extract the data.

$ grep -v vault test.yml | awk '{$1=$1;print}' | ansible-vault decrypt


回答10:

This is how I am encrypting and decrypting strings inline, additionally for use as environment variables.

yq is especially useful here for interpreting yaml input.

In one line if I were to test encrypt and decypt a string I would do this-

echo -n "test some input that will be encrypted and decrypted" | ansible-vault encrypt_string --vault-id $vault_key --stdin-name testvar_name | yq r - "testvar_name" | ansible-vault decrypt --vault-id $vault_key

I'm guessing that those usually interested in this are interested in decrypting environment variables. This is how I implement that use case, where testvar is the encrypted environment variable, and and $vault-id is the path to the key you are using to encrypt/decrypt.

testvar=$(echo -n "test some input that will be encrypted and stored as an env var" | ansible-vault encrypt_string --vault-id $vault_key --stdin-name testvar_name | base64 -w 0)
result=$(echo $testvar | base64 -d | /var/lib/snapd/snap/bin/yq r - "testvar_name" | ansible-vault decrypt --vault-id $vault_key); echo $result


回答11:

For a file like test.yml:

---
test: !vault |
     $ANSIBLE_VAULT;1.1;AES256
     37366638363362303836383335623066343562666662386233306537333232396637346463376430
     3664323265333036663736383837326263376637616466610a383430623562633235616531303861
     66313432303063343230613665323930386138613334303839626131373033656463303736366166
     6635346135636437360a313031376566303238303835353364313434363163343066363932346165
     6136

the following crude implementation (recomended only for some quick manual action obviously):

for row in $(cat test.yml | yq -c '.[]'); do
    decrypt() {
     printf "decrypting '%s'" $row | sed -e 's/^"//' -e 's/"$//'
     echo "---"
     printf $row | sed -e 's/^"//' -e 's/"$//' | ansible-vault decrypt -
    }
   echo -e "==\n: $(decrypt '.')"
done

should work, provided that you have the key that encrypted the data.