ANSIBLE TUTORIALS #5: VAULT
As developers, it’s important to know how to encrypt sensitive data using Ansible Vault. This is because we often store our code on public platforms like GitHub, which means that anyone can access it.
Throughout this tutorial series, we have generated various files, some of which hold confidential information, such as our user password. Despite having already uploaded these files to my GitHub repository, I have not taken any steps to encrypt them since they are purely for educational purposes. However, in a professional setting where you may be employed as a system administrator or DevOps engineer, it is crucial to ensure that files containing sensitive access keys or passwords are securely encrypted and not publicly accessible. Thus, I believe this tutorial will be immensely beneficial to you.
What you will learn
In this tutorial, we will learn how to create secure passwords with a password manager and use the ansible-vault commands to
- create encrypted files
- encrypt and decrypt files,
- view or edit encrypted files,
- change your vault passwords,
- encrypt a specific content such as a password within a file,
- run the ansible-playbook command with encrypted files and/or files with encrypted content, and so much more.
If you have Ansible installed, then you also have Ansible Vault. To confirm this, run the command below on your Ansible control machine:
$ which ansible-vault
You should get an output that returns the ansible-vault command’s full path, “/usr/bin/ansible-vault” or something similar.
Creating a Secure Vault Password
Ansible Vault uses the password created by a user to authorize the encryption or decryption of a file or contents within a file. Therefore, we need to create a secure password saved in a file within our local machine. You definitely want to keep this file -
- as hidden as possible, and
- strictly local to your PC and never pushed to any public git repository.
To get a strong password, we could use a password manager — I use KeePassXC, but you can use any password manager of your choice.
OR
You can simply generate a random password from the command line using a package specially built for encrypting passwords. Simply run:
$ mkpasswd -m sha-512 | tail -c 30
This will create an SHA-512 hash password with the text we are going to pass in after this runs successfully. Here we have passed the mkpasswd command into the tail -c 30 command to shorten the generated password to 30 characters only.
You may need to install the whois package to run this command successfully. You can do this with your distribution’s package manager. For example, on Ubuntu run:
$ sudo apt install -y whois
On CentOS, replace apt with yum. After this runs successfully, execute the previous mkpasswd command again, and this time you should get a prompt on your terminal asking you to enter the password you wish to encrypt. You may enter a simple password (every character will appear invisible as you type) and when you hit enter, a random set of alpha-numeric password with special characters will be generated.
There are several other packages for doing this, and some of them are pwgen, makepasswd, basez, etc.
After copying your newly generated password, create a hidden file in your home directory — I am going to name mine, “.vault_pass”. The dot at the file name’s beginning keeps it hidden from the “ls” (list storage) command. Paste your password here, save it, and exit your text editor.
The next important thing to do here is to give our vault password file a modification that prevents other users from accessing it. So, run the command below:
$ sudo chmod 0600 /home/vagrant/.vault_pass
The 0600 mode gives the file owner read and write permissions only, and everyone else is completely restricted. However, if you choose to use a Python script that would automatically generate your password, then you need to make your vault password file also executable by using mode 0700 instead.
Creating Newly Encrypted Files
With the vault password file we have created above we can create new files in an encrypted state using the command format below:
$ ansible-vault create new/file --vault-password-file password/file
For example, to create an encrypted new file named classified.txt, run the command below as a sudo user:
$ ansible-vault create classified.txt --vault-password-file /home/vagrant/.vault_pass
Encrypting and Decrypting Files with Ansible Vault
Assuming we want to encrypt our ansible.cfg file, run the command below:
vagrant@ubuntu-control:~$ cd ansible_tasks3
vagrant@ubuntu-control:~/ansible_tasks3$ sudo ansible-vault encrypt ansible.cfg --vault-password-file /home/vagrant/.vault_pass
Now when you try to view the ansible.cfg file using the cat command, your terminal would return an encrypted output as shown below:
vagrant@ubuntu-control:~/ansible_tasks3$ sudo cat ansible.cfg
$ANSIBLE_VAULT;1.1;AES256
34363834646538643062336462393335623431336335633730316636353062373435653536373433
3236656466623462316439353962333332363066393466310a663462386536636262636438366237
62353262376132353165303930646239323431646265303066623362333536633239343730353334
3862383464343464610a633861366639333234343265376431326665363235316134366631353361
34383435393432333363663433613564303438363739383631303361346238386631333030623566
66356338633937386662613233316337633738636661353336333235326530666665663162613730
36333834626530633638333437303463616636386134656439353361633263656639363663643439
63363735373463306634616636346136653165646539653330656135626135613662633230646535
30346665346166303932383934636165316334623164353363656364343336303165616262356436
36343236393635333166363537633438653462643638346137336564366631393131363439323631
36613638373966613731306364353332626130303930653234333062303539386537626464356333
35383738393162376638666365306462646666623263623262363634616530653435656333373138
62313337656332333830633966333663643461373830653263663865633161333964633862313431
3936663530643934666165306263376335636530663838613235
This also occurs when we try to edit an ansible-vault-encrypted file. Ansible Vault creates UTF-8 encoded text files when it executes encryption. The “AES256” seen at the top represents the algorithm used by Ansible Vault to provide symmetric encryption. To decrypt this file, we use the ansible-vault decrypt command.
vagrant@ubuntu-control:~/ansible_tasks3$ sudo ansible-vault decrypt ansible.cfg --vault-password-file /home/vagrant/.vault_pass
This may throw an error:
vagrant@ubuntu-control:~/ansible_tasks3$ sudo ansible-vault decrypt ansible.cfg --vault-id /home/vagrant/.vault_pass
ERROR: Error reading config file (/home/vagrant/ansible_tasks3/ansible.cfg): File contains no section headers.
file: '<string>', line: 1
'$ANSIBLE_VAULT;1.1;AES256\n'
Step out of your present working directory to your home directory and run the command again:
vagrant@ubuntu-control:~$ sudo ansible-vault decrypt ansible_task3/ansible.cfg --vault-id .vault_pass
“Decryption successful”, right? Could it be because Ansible Vault can decrypt the ansible.cfg file as a regular file from outside the playbook’s working directory, however within the working directory, it has to initially read it as a configuration file, therefore Ansible returns an error before attempting to decrypt it? Or could it be also because Ansible Vault cannot effectively decrypt non-YAML files on runtime? Please share your thoughts with me on this one.
Now you can view or edit the decrypted file with your preferred text editor. However, if we want to keep a file encrypted, there is no need to decrypt it to enable us to view or edit it. Let us see how we can do this.
Viewing and Editing Encrypted Files
Let us re-encrypt our ansible.cfg file, and try to view it using the command line below:
vagrant@ubuntu-control:~$ sudo ansible-vault view ansible_tasks3/ansible.cfg --vault-password-file .vault_pass
Then to edit, simply change the view command to edit.
vagrant@ubuntu-control:~$ sudo ansible-vault edit ansible_tasks3/ansible.cfg --vault-password-file .vault_pass
Great! We can now view or edit our encrypted file without having to first decrypt it. Sometimes, there might be a situation where our vault password is compromised. In such a situation, how do we change our Vault password?
Changing the Ansible Vault Password
If we simply go to our .vault_pass file and change its content, this file will not work successfully when we try to decrypt files that were previously encrypted with the previous vault password. Therefore, we need to “rekey” the files that were previously encrypted with the old password to sort of delist the old key and integrate the new one into the system.
Ansible Vault cannot decrypt a file with a Vault password different from the one used to encrypt it.
First, we copy a stronger password from our password manager, and create a new password file with it in the home directory; I will name mine “.vault_key”. Save and exit your text editor. Give the new file the 0600 file modification:
$ sudo chmod 0600 /home/vagrant/.vault_key
Now that we have successfully created a new vault password file, we need to first run the ansible-vault rekey command with the old vault password file:
...:~$ sudo ansible-vault rekey ansible_tasks3/ansible.cfg --vault-password-file ./.vault_pass
Then at the prompt, enter and confirm the new password you copied from your password manager (the same password you pasted in the .vault_key file). You would be greeted with, “Rekey successful.” You have successfully changed your Ansible Vault password and can now edit, view or decrypt your encrypted files with your new password file. You may delete the old password file, .vault_pass if you want, because we would no longer need it.
So far, we have seen how to encrypt an entire file. What if we only want to encrypt specific content, say a password within a file, and not the entire file? Next…
Encrypting a Specific Content within a File
Recall that in our previous tutorial on Ansible Roles, we created a new user with a hashed password. We still have that password sitting in our hosts’ variables’ files unencrypted. Now we could simply delete that password from our host_var files since we no longer need it there, but we do not want to lose track of things, and as we proceed in our work we just might need to recall our password. So let us go ahead and encrypt it. To do this, we use the “ansible-vault encrypt_string” command which follows the format below:
$ sudo ansible-vault encrypt_string 'variableToEncrypt' --vault-id label@password_file --name 'variable_name'
So run the command below,
$ sudo ansible-vault encrypt_string 'ansible3' --vault-id ansible-demo@/home/vagrant/.vault_key --name 'password'
Our password here is ansible3, and the label (optional) is ansible-demo. When you hit Enter, you would get a similar output to this:
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;ansible-demo
66656235326631313933346132643732343630623062623035343339656137623064353731386239
6663383030626334356661313339623161363066653062350a373963663337656261613139343238
30393138306566653432613736653339383437376635383631666666373737346564646561646534
3464336332396662310a666335333236396430623338343938343366316665653931373364626138
6536
Encryption successful
Copy the output and paste it on your host_var files to conceal the value of the password variable. For example, this would be our centos-node-1.yml file:
ansible_host: 192.168.53.61
password: !vault |
$ANSIBLE_VAULT;1.2;AES256;ansible-demo
66656235326631313933346132643732343630623062623035343339656137623064353731386239
6663383030626334356661313339623161363066653062350a373963663337656261613139343238
30393138306566653432613736653339383437376635383631666666373737346564646561646534
3464336332396662310a666335333236396430623338343938343366316665653931373364626138
6536
apache: httpd
php: php
sudo_group: wheel
Whenever you need to view the value of this encrypted variable, run the command below in the same directory where our host_var directory is:
vagrant@ubuntu-control:~/ansible_tasks3$ sudo ansible localhost -m ansible.builtin.debug -a var="password" -e "@host_vars/centos-node-1.yml" --vault-id ansible-dem
o@/home/vagrant/.vault_key
localhost | SUCCESS => {
"password": "ansible3"
}
⚠️You cannot create a hashed password for a new user (like we did in the tutorial on Ansible Roles) with an encrypted password variable. However, you can do this with an encrypted variable file where you have saved your password.
Executing the ansible-playbook Command with Vault Encrypted Files
To run a playbook with a set of Ansible files that have vault encryption one way or another (entire file or variable), you would have to run the ansible-playbook command with the vault password file or vault ID flag to indicate your Vault password. For example, to execute our playbook, simply run
$ ansible-playbook playbook.yml --vault-id /home/vagrant/.vault_key
Ansible can decrypt your files on runtime as long as you specify the right vault password file.
To avoid repeatedly using the vault password file or vault ID flag to declare your vault password file on the command line, specify your vault password file in your ansible.cfg file as follows:
[defaults]
...
vault_password_file=/home/vagrant/.vault_key
...
⚠️Do not save your vault password file in a git directory to avoid the mistake of committing it to your git repository where it may be exposed to the public.
Conclusion
In this section, we have learned a lot about Ansible Vault to confidently use it in keeping our work’s sensitive data more secure. Visit Ansible’s documentation on Ansible Vault to learn more about this immensely useful tool. I will see you in my next article.