How to encrypt Bash shell variables with Ansible Vault

Photo by Markus Spiske on Unsplash
Ansible is a great tool to automate mundane or complex tasks. It also allows code reuse by passing variables to roles or collections. This is important when sharing code across a large base of users.
However, sometimes those variables are credentials that are specific to a user's access or password rather than a service account credential like you might use in Ansible Automation Platform. You wouldn't want to share sensitive credentials with your team, let alone place them into a Git repo for the world to see. Sometimes these variables are derived from an environment file, such as your .bashrc
. And they could be things you need to access from the shell, not only in an Ansible playbook.
This is where Ansible Vault comes into play. Ansible Vault is a command-line tool that allows you to encrypt and decrypt any structured data file. In this article, I'll show you how to protect your shell environment variables while making them available for your typical Bash commands and your Ansible playbooks, roles, and collections.
[ Download now: A sysadmin's guide to Bash scripting. ]
Use encrypted environment variables with Ansible
First, create a .bash_vault
file in your home directory:
$ touch ~/.bash_vault
Next, append the following code to your .bashrc
file:
export EDITOR=vi
BASH_VAULT=${HOME}/.bash_vault
function bash_vault.load(){
echo "Loading bash vault..."
source <(ansible-vault view ${BASH_VAULT})
}
function bash_vault.edit(){
ansible-vault edit ${BASH_VAULT}
}
function bash_vault.reload(){
echo "Reloading bash vault..."
source <(ansible-vault view ${BASH_VAULT})
}
After updating your .bashrc
, create your secrets in the .bash_vault
file. In this example, you want to keep your usernames, passwords, and destinations secret from prying eyes:
APP1_API_USERNAME='mike.wazowski'
APP1_API_PASSWORD='Ey3b4LL!'
APP1_API_URL='www.foo.com'
APP2_API_USERNAME='james.sullivan'
APP2_API_PASSWORD='H41rB4ll!'
APP2_API_URL='www.bar.com'
APP3_API_USERNAME='randall.boggs'
APP3_API_PASSWORD='Ch4m3l0N!'
APP3_API_URL='www.foobar.com'
export APP1_API_USERNAME APP1_API_PASSWORD APP1_API_URL APP2_API_USERNAME APP2_API_PASSWORD APP2_API_URL APP3_API_USERNAME APP3_API_PASSWORD APP3_API_URL
After updating your .bash_vault
file, you must encrypt it using ansible-vault
:
$ ansible-vault encrypt .bash_vault
New Vault password: ****
Confirm New Vault password: ****
Encryption successful
Now, validate you've encrypted the environment variables:
$ cat .bash_vault
$ANSIBLE_VAULT;1.1;AES256
66623436333962663336333666306230366230336465333865326363666232383365326233333836
6630393461333137633865303134616262353230636163330a386338366663633230343537303335
3635...shortened for brevity....
Reload your .bashrc
file and reload the encrypted shell variables stored in .bash_vault
using the functions available in your .bashrc
file. You will be prompted for your Ansible Vault password:
$ source .bashrc
$ bash_vault.load
Loading bash vault...
Vault password: ****
Write a playbook showcasing how Ansible can access these variables:
- name: Example playbook to show vaulted shell variables
hosts: localhost
gather_facts: false
become: false
tasks:
- name: Debug app1 shell variables
ansible.builtin.debug:
msg:
- "{{ lookup('env','APP1_API_USERNAME') }}"
- "{{ lookup('env','APP1_API_PASSWORD') }}"
- "{{ lookup('env','APP1_API_URL') }}"
- name: Debug app2 shell variables
ansible.builtin.debug:
msg:
- "{{ lookup('env','APP2_API_USERNAME') }}"
- "{{ lookup('env','APP2_API_PASSWORD') }}"
- "{{ lookup('env','APP2_API_URL') }}"
- name: Debug app3 shell variables
ansible.builtin.debug:
msg:
- "{{ lookup('env','APP3_API_USERNAME') }}"
- "{{ lookup('env','APP3_API_PASSWORD') }}"
- "{{ lookup('env','APP3_API_URL') }}"
[ Write your first playbook in this hands-on interactive lab. ]
Finally, run the playbook to showcase the results:
$ ansible-playbook -i localhost, bash_vault_example.yml
PLAY [Example playbook to show vaulted shell variables] ************************
TASK [Debug app1 shell variables] **********************************************
ok: [localhost] => {
"msg": [
"mike.wazowski",
"Ey3b4LL!",
"www.foo.com"
]
}
TASK [Debug app2 shell variables] **********************************************
ok: [localhost] => {
"msg": [
"james.sullivan",
"H41rB4ll!",
"www.bar.com"
]
}
TASK [Debug app3 shell variables] **********************************************
ok: [localhost] => {
"msg": [
"randall.boggs",
"Ch4m3l30N!",
"www.foobar.com"
]
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Use variables on the command line
But wait, these are shell environment variables, so you can also access them using the command line outside of Ansible.
Typically when users run commands, Bash stores them in command history. You can override this using set +o history
or clear it using history -c
, but sometimes you need the history to recall previously executed long commands more easily.
By using Ansible Vault-created environment variables, the history shows the variable name but not the variable value. To test this, first execute a command that uses one of the variables:
# Run a curl command with our encrypted shell variables
$ curl -o /dev/null -s -w "%{http_code}\n" ${APP1_API_URL}
# CURL RESULTS
200
Then review the history to check that it shows the variable name and not the variable value:
# Run the history command to check our shell variables
$ history|tail -2|grep -v history
# HISTORY RESULTS
1034 curl -o /dev/null -s -w "%{http_code}\n" ${APP1_API_URL}
Change the vaulted variables
If you need to add, delete, modify, or review your Ansible Vault-created environment variables, call the bash_vault.edit
function:
$ bash_vault.edit
Once you've completed the updates, reload the shell variables using the bash_vault.reload
function:
$ bash_vault.reload
Finally, when you're done, you can just log out and know that your sensitive shell variables are safe from prying eyes. This is possible because your variables are encrypted at rest.
[ Get started with automation controller in this hands-on interactive lab. ]
Words of caution
Your variables are only as secure as your security practices, so keep the following in mind:
- Avoid logging your sensitive shell variables.
- Avoid writing the environment variables to your logs when running tasks.
- Use
no_log=true
in your Ansible tasks - Avoid using redirects to a log like
>
or|tee -a somelog
Here's an example of usingno_log=true
to protect your sensitive information:
- Use
# Protect your creds using no_log
- name: Debug keep passwords private shell variables using nolog
ansible.builtin.uri:
url: "{{ destination_url }}"
user: "{{ lookup('env','APP1_API_USERNAME') }}"
password: "{{ lookup('env','APP1_API_PASSWORD') }}"
no_log: true
- Never reveal your environment variable to stdout.
- Avoid printing your environment variables to stdout using the
env
command orecho
commands. This is especially important, when:- Using a shared resource like Ansible Automation Platform
- Using a shared system where others have admin access
- A tool like tlog has been implemented for terminal session logging
# AVOID DOING THIS
$ env|grep APP
APP3_API_USERNAME=randall.boggs
APP1_API_PASSWORD=Ey3b4LL!
APP3_API_URL=www.foobar.com
APP3_API_PASSWORD=Ch4m3l30N!
APP2_API_PASSWORD=H41rB4ll!
APP1_API_URL=www.foo.com
APP2_API_URL=www.bar.com
APP2_API_USERNAME=james.sullivan
APP1_API_USERNAME=mike.wazowski
# AVOID DOING THIS
$ echo $APP1_API_PASSWORD
Ey3b4LL!
Wrap up
Keeping your personal data, such as web tokens, passphrases, and passwords, safe from prying eyes is imperative. In this article, you learned how to encrypt Bash shell variables with Ansible Vault for use inside and outside of Ansible playbooks. This article provides a straightforward solution for keeping your personal credentials and data private using Ansible Vault.



Randy Romero
Randy Romero is a Senior Ansible Consultant and Red Hat Certified Architect at Red Hat where he specializes in IT automation with Ansible and Ansible Automation Platform. He has experience in the cable, insurance, and loyalty-marketing industries, having performed multiple roles starting with ju More about me