How to decrypt string with ansible-vault 2.3.0
AnsibleAnsible VaultAnsible Problem Overview
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?
Ansible Solutions
Solution 1 - Ansible
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"
}
Solution 2 - Ansible
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
.
The /dev/stdin/
part may not be needed in new Ansible versions.
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
Solution 3 - Ansible
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
$
Solution 4 - Ansible
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
Solution 5 - Ansible
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"
}
Solution 6 - Ansible
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
Solution 7 - Ansible
You can do it with a one-liner
ansible localhost -m debug -a var='NAME_OF_ENCRYPTED_VAR' -e "@PATH_TO_FILE_WITH_VARIABLE" --vault-id yourid@/path/to/file
or enter the password from command line
ansible localhost -m debug -a var='NAME_OF_ENCRYPTED_VAR' -e "@PATH_TO_FILE_WITH_VARIABLE" --ask-vault-pass
Solution 8 - Ansible
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!
Solution 9 - Ansible
With this you can decrypt a file containing just an ansible vault string:
cat encrypted_vault_string | ansible-vault decrypt
output:
Vault passsword: <enter password, is not echoed to you>
Decryption successful
< decrypted string here>
An ansible vault string looks like:
$ANSIBE_VAULT;1.1;AES256
123456789...
123456789...
123456789...
1234
This also works without an intermediate file
echo -e '$ANSIBLE_VAULT;1.1;AES256\n123456789...789' | ansible-vault decrypt
Solution 10 - Ansible
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.*)
-
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)
-
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()
-
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
-
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)
Solution 11 - Ansible
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
Solution 12 - Ansible
You can copy the encrypted string to a file but you need to only copy the encrypted part and not the other yml parts.
So you file need to change from:
test: !vault |
$ANSIBLE_VAULT;1.1;AES256
37366638363362303836383335623066343562666662386233306537333232396637346463376430
3664323265333036663736383837326263376637616466610a383430623562633235616531303861
66313432303063343230613665323930386138613334303839626131373033656463303736366166
6635346135636437360a313031376566303238303835353364313434363163343066363932346165
6136
to:
$ANSIBLE_VAULT;1.1;AES256
37366638363362303836383335623066343562666662386233306537333232396637346463376430
3664323265333036663736383837326263376637616466610a383430623562633235616531303861
66313432303063343230613665323930386138613334303839626131373033656463303736366166
6635346135636437360a313031376566303238303835353364313434363163343066363932346136
And you'll be able to decript or view with
ansible-vault decrypt --vault-password-file <path to passwordfile> test.yml
ansible-vault view --vault-password-file <path to passwordfile> test.yml
And perhaps drop the .yml
because that doesn't make sense anymore.
Solution 13 - Ansible
For those who want to define an alias and forget about pipes and temp files, here is a solution which you can adopt:
function decrypt_ansible_vault_string() {
export FN=$1
export KEY=$2
ansible-vault view <(yq r $FN $KEY)
}
Example usage:
$ head myrole/var/main.yml
# Variables here override defaults
website:
server: 127.0.0.1
port: 8081
session:
hash_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
33626439623630633332343836316334376637323738323061373334373733326566613262373036
6632623432373263613139646432333331313731326232390a653031366564313235323065303865
32383563393261326633306663663437386134666230373332646234656464356331646335636564
$ decrypt_ansible_vault_string myrole/vars/main.yml website.session.hash_key
This answer expands on the comment from @maricn
Note, I am using this yq, but any yaml query tool can do. It's the principle of using subshell redirect that matters here (No temp files).
Also note, you can add --ask-vault-password
. However, using a secret encrypted with GPG is much nicer, since you don't have to type your password every time and this work flow is much better for teams (YMVV and IHMO). Here is a good tutorial on how to use GPG with ansible-vault.
Stick this in your .bashrc
and enjoy it.
update
I got frustrated with ansible-vault encrypt\decrypt
workflow. So, I created a wrapper for also decrypting strings in the var files. Check it out: https://github.com/oz123/ansible-vault-string-helper
Solution 14 - Ansible
I know it's been a while, but it worked for me when I piped it through ansible-vault decrypt
without anything else, like this:
$ echo '$ANSIBLE_VAULT;1.1;AES256
38613538323065373061616466616334306237336461333935393261646131616232643238626635
3336633631366539383039343437306664336165326565650a353233303431613362653838643135
34363763366134393366356339343039313035366164636133326639376334313335316565373330
3435633463313334310a653239313039323135363865313933626464663363656164343662303763
34616663626530656630633839346531653862633332396365396432366234333861' | ansible-vault decrypt
Decryption successful
super-secret-string$
Just in case anyone is interested. I have ansible version 2.9.26
Solution 15 - Ansible
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
Solution 16 - Ansible
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.
Solution 17 - Ansible
Coming across this question and the answers here, I'd just like to add a quick bash script i cooked together that reads through an entire yaml file hunting for strings that can be decrypted dumping to screen.
It's far from perfect and I'm not the hottest at bash but, hope this helps someone who was in the same situation as me wanting to do a general dump.
To use the following script, it is necessary to have your vault password in a file (current working path) called vault_pass
, along with yq and jq
installed. The file to be parsed should be first argument. e.g. ./vault_reader.sh group_vars/production.yml
#!/bin/bash
KEY_OR_VALUE=key
for row in $(yq read -j $1 | jq); do
if [ "$KEY_OR_VALUE" == "key" ]
then
KEY_OR_VALUE="value"
echo $(sed -e "s/\"//g" -e "s/\://g" <<<$row)
else
KEY_OR_VALUE="key"
ENC_VALUE=$(sed -e "s/\"//g" -e "s/\://g" -e"s/\,//g"<<<$row)
if [[ $ENC_VALUE = '$ANSIBLE_VAULT'* ]]; then
echo -e "$ENC_VALUE" | ansible-vault decrypt --vault-password-file vault_pass
fi
echo ""
fi
done
Solution 18 - Ansible
Insane but elegant shell script to output a clean yaml file with decrypted inline vars (assumes that you have ANSIBLE_VAULT_PASSWORD_FILE set and yq v4 installed):
VARS_FILE=path/to/your/vars_file_with_encrypted_vars.yml
yq -P e "$(for v in $(grep '\!vault' $VARS_FILE | cut -d: -f1); do val=$(yq e .${v} $VARS_FILE | tr -d ' ' | ansible-vault decrypt); echo .$v = \"$val\" \|; done) null = null" $VARS_FILE
Solution 19 - Ansible
Trying to decrypt /dev/stdin
, as in ansible-vault decrypt /dev/stdin
, or using --vault-password-file=/dev/stdin
, like other commenters mention, also fails for me with errors like ERROR! [Errno 2] No such file or directory: '/proc/100/fd/pipe:[12930445]'
.
However, --vault-password-file
also takes an executable to produce the password on stdout, so you can actually use /bin/cat
to pipe in the password:
echo password | ansible-vault decrypt --output - --vault-password-file=/bin/cat ./encrypted_vault_file