We like using ansible for our automation because it has minimum requirements for the target machines and all around infrastructure. You need nothing more than ssh and python with some libraries. In contrast to alternatives like puppet and chef you do not need special server and client programs running all the time and communicating with each other.
The problem
When setting up remote machines and deploying software systems for your customers you will often have to use sensitive data like private keys, passwords and maybe machine or account names. On the one hand you want to put your automation scripts and their data under version control and use them from your continuous integration infrastructure. On the other hand you do not want to spread the secrets of your customers all around your infrastructure and definately never ever in your source code repository.
The solution
Ansible supports encrypting sensitive data and using them in playbooks with the concept of vaults and the accompanying commands. Setting it up requires some work but then usage is straight forward and works seamlessly.
The high-level conversion process is the following:
- create a directory for the data to substitute on a host or group basis
- extract all sensitive variables into vars.yml
- copy vars.yml to vault.yml
- prefix variables in vault.yml with vault_
- use vault variables in vars.yml
Then you can encrypt vault.yml using the ansible-vault command providing a password.
All you have to do subsequently is to provide the vault password along with your usual playbook commands. Decryption for playbook execution is done transparently on-the-fly for you, so you do not need to care about decryption and encryption of your vault unless you need to update the data in there.
The step-by-step guide
Suppose we want work on a target machine run by your customer but providing you access via ssh. You do not want to store your ssh user name and password in your repository but want to be able to run the automation scripts unattended, e.g. from a jenkins job. Let us call the target machine ceres.
So first you setup the directory structure by creating a directory for the target machine called $ansible_script_root$/host_vars/ceres
.
To log into the machine we need two sensitive variables: ansible_user and ansible_ssh_pass. We put them into a file called $ansible_script_root$/host_vars/ceres/vars.yml
:
ansible_user: our_customer_ssh_account ansible_ssh_pass: our_target_machine_pwd
Then we copy vars.yml to vault.yml and prefix the variables with vault_ resulting in $ansible_script_root$/host_vars/ceres/vault.yml
with content of:
vault_ansible_user: our_customer_ssh_account vault_ansible_ssh_pass: our_target_machine_pwd
Now we use these new variables in our vars.xml
like this:
ansible_user: "{{ vault_ansible_user }}" ansible_ssh_pass: "{{ vault_ansible_ssh_pass }}"
Now it is time to encrypt the vault using the command
ANSIBLE_VAULT_PASS="ourpwd" ansible-vault encrypt host_vars/ceres/vault.yml
resulting a encrypted vault that can be put in source control. It looks something like
$ANSIBLE_VAULT;1.1;AES256 35323233613539343135363737353931636263653063666535643766326566623461636166343963 3834323363633837373437626532366166366338653963320a663732633361323264316339356435 33633861316565653461666230386663323536616535363639383666613431663765643639383666 3739356261353566650a383035656266303135656233343437373835313639613865636436343865 63353631313766633535646263613564333965343163343434343530626361663430613264336130 63383862316361363237373039663131363231616338646365316236336362376566376236323339 30376166623739643261306363643962353534376232663631663033323163386135326463656530 33316561376363303339383365333235353931623837356362393961356433313739653232326638 3036
Using your playbook looks similar to before, you just need to provide the vault password using one of several options like specifying a password file, environment variable or interactive input. In our example we just use the environment variable inline:
ANSIBLE_VAULT_PASS="ourpwd" ansible-playbook -i inventory work-on-customer-machines.yml
After setting up your environment appropriately with a password file and the ANSIBLE_VAULT_PASSWORD_FILE
environment variable your playbook commands are exactly the same like without using a vault.
Conclusion
The ansible vault feature allows you to safely store and use sensitive data in your infrastructure without changing too much using your automation scripts.