This blog post will dive deep into Ansible Vault as a mechanism for keeping your sensitive values and secrets secure in your playbooks and other Ansible files. We will explore different options for working with encrypted content and password management options.
If you are new to Ansible or interested in other Ansible concepts, these Ansible tutorials on Spacelift’s blog might be handy.
Ansible Vault is a feature that provides a native way to handle sensitive information. Ansible Vault allows users to encrypt secrets and other sensitive data such as API keys, passwords, and other credentials to protect them at rest.
Instead of storing secrets in plaintext, Ansible Vault gives you a secure, native, and low-effort option to manage sensitive information by leveraging encryption. Using Ansible Vault, encrypted content can be stored in playbooks, variable files, and roles, persisted under source control, and shared without exposure risks.
Ansible Vault protects your sensitive content only at rest. Users are responsible for not exposing decrypted content in the console or any other way. Check out the no_log option for tasks to hide their output if necessary.
We must use passwords to encrypt and decrypt sensitive data with Ansible Vault. The passwords are used to create encrypted variables or files, decrypt, and view or edit the encrypted content.
To supply the password for these operations, you can either leverage the ansible-vault
command and get prompted for it, set up a location of a password file in your main configuration definition, ansible.cfg
, or integrate with an external secret store solution that holds your passwords.
As you can imagine, since you have to keep track of your vault passwords, there is a process involved around password management in any of these cases. You might leverage the same password for all your encrypted content for simple cases, small teams, and a few encrypted values. This approach simplifies your password management process since you only have to deal with a single password. Store and handle this password and other sensitive data in your secret management system.
You might have to create and manage more vault passwords for complex systems and different access levels for different teams and people. For example, you might use a different password per team, per environment, per ansible role, application, directory, or any other pattern that fits your needs.
You can specify a dedicated vault id for every password in such cases. Whenever you generate newly encrypted content, you can pass the dedicated id with the flag --vault-id
. Store this id along with the password and pass it with the password during decryption.
We will look into more examples of leveraging vault IDs in the next section on how to encrypt sensitive values.
As discussed previously, a simple but not really secure option would be to store passwords in a local file. If you decide to go that way, make sure the file has the correct permissions, store the password as a string in a single line, and don’t persist it in any code repositories.
A more secure and scalable way would be to use an external secret store for storing passwords and fetch them dynamically with the help of a vault password client script. A vault password client script is responsible for connecting to the remote secret store, fetching the secret, and printing the password to standard output. Look at the Storing passwords in third-party tools with vault password client scripts section of the official documentation for details on how to create and use such scripts.
Ansible Vault can assist users with encrypting mainly two types of data, variables and files. This means we can encrypt either whole files or only specific values stored in encrypted variables.
By encrypting specific variables, our content will be decrypted on demand only when needed. This option allows us to mix encrypted and plaintext content according to our needs inside playbooks and roles. One drawback of this approach is that it works only with variables and that changing or rotating the password might be a bit cumbersome since there isn’t a command that supports this.
On the other hand, encrypting whole files allows us to encrypt other content (for example, tasks) apart from variables, and then decryption happens when the file is referenced. We can easily use the rekey
command to change or rotate the password used for encryption on files, and in general file-level encryption is easier to use and manage.
A disadvantage of this approach is that since we are encrypting the whole content of the files, we are trading away readability and accessibility since we can’t read the file without effort and get an understanding of its contents. One way to bypass this issue could be to keep the names or references of your encrypted content in a separate non-encrypted file. Look at Keep vaulted variables safely visible for more information on the topic.
Let’s look at some examples next. We will start by encrypting a variable.
Encrypting Ansible Variables
To encrypt a string to use in a variable, you can leverage the ansible-vault encrypt_string
command.
To encrypt the string encrypt_this_string_please
named encrypted_string
and provide the password via the command line:
Notice that the produced encrypted content starts with the !vault
tag, which indicates to Ansible that this value is encrypted and needs decryption to use. After this tag, Ansible adds a header before the encrypted content that includes the format ID, the vault format version, and the cipher algorithm used for encryption.
If you create the encrypted variable with a vault ID, this is also included in the generated content. If you are interested in more information, check out the format of files created with Ansible Vault section of the official docs.
You can also select the password source. For example, let’s use a file named password_file
as our password source.
To avoid persisting the secret value in your shell history, don’t pass directly with the command, but opt to be prompted for a string to encrypt like this:
ansible-vault encrypt_string --vault-id dev@password_file --stdin-name 'encrypted_string'
You can find more command options by using the --help
flag.
ansible-vault encrypt_string --help
Encrypting Ansible Files
To encrypt whole files that include structured data, you can leverage the ansible-vault create
or the ansible-vault encrypt
commands. Different files that can be encrypted include group, host, defaults, roles, and other custom variable files, tasks files, handlers files, binary, or other arbitrary files.
Creating a New Encrypted File
To create a new encrypted file, encrypted_file.yml
, with vault ID dev, and get prompted for the password, use this command:
ansible-vault create --vault-id dev@prompt encrypted_file.yml
This will open your configured editor (by default it would be vi) to provide the content to be encrypted. The same considerations discussed earlier for storing and using Ansible Vault passwords apply here.
After you provide your plain text content to the file and save and exit from it, you will only see the encrypted one when you try to view the content. To view it in plain text again, you will need to decrypt it.
Encrypting an Existing File
Before encrypting an existing file, let’s take a look at its content:
cat file_to_be_encrypted.yml
---
- name: Install htop
hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install htop
apt:
name: htop
state: present
Next, let’s encrypt it. This operation is as simple as running this command:
ansible-vault encrypt file_to_be_encrypted.yml
New Vault password:
Confirm New Vault password:
Encryption successful
You will be prompted for a password, so ensure you will remember it, as it will be required for the decrypt operation.
Now if we want to check the content of the file, this is what we will see:
cat file_to_be_encrypted.yml
$ANSIBLE_VAULT;1.1;AES256
35303362626338626165386633633863326432346539306162393065636236353238636435623033
6466383631393263373538343533346165316462643431660a373437393463616539303830386162
65653831663562333439663235373732383830323761383935643330316637616433396531626632
3137313134333263350a313965313832383533396135623761616234366134316530313964313361
39346433346462383130393163646465346534616661373766316163333161636331393436313435
62623736623539613831353838383961316566393530323837363138616232626565633063653163
64646464663663643362623234356332376465326631373934383133613839633138623939343832
31636261633237303462666231626166386435656266333865666130656562366336636232623164
34663565303634613837303738633135653739386465303530636534343337616166373836633461
64396236393838336266623635323031336465626262383031356362346232636166323365376661
38393931363964663462656537306231633561373038363963616631366165626432646364343431
62353935323338303632323934643831633534386365613163646630333436616438623436366365
36366632383265323833336638356436393537313066616466386666356239633365363137353335
6337313962336661643238363535633263333364326136343365
In the previous section, we explained the process and went over several options for encrypting different content with Ansible Vault. Now, let’s look at how we can utilize and work with encrypted content.
One of the most common operations for a user is to be able to view the encrypted content if necessary. You can leverage the debug
module to view the plaintext value of encrypted content.
Let’s create a simple encrypted variable and pass the password via the prompt:
Next, we store this variable in a file named file_with_stored_encrypted_variable.yml
.
To view the encrypted value, use the debug
module and pass the location of the password as we have seen earlier:
ansible localhost -m ansible.builtin.debug -a var="encrypted_variable" -e "@file_with_stored_encrypted_variable.yml" --vault-password-file password_file
localhost | SUCCESS => {
"changed": false,
"encrypted_variable": "encrypt_this"
}
Viewing Encrypted Files
Viewing the contents of encrypted files is quite simple with the ansible-vault view
command:
ansible-vault view encrypted_file.yml
Editing Encrypted Files
Another handy option when working with encrypted files is the ability to edit the encrypted content with the ansible-vault edit
command:
ansible-vault edit encrypted_file.yml
This command prompts the user for the password, decrypts the content to a temporary file, allows the user to edit the encrypted content with the configured editor, and finally saves and re-encrypts the file.
Decrypting Encrypted File
To permanently decrypt an encrypted file, use the ansible-vault decrypt
command. You will need to provide the encryption password:
ansible-vault decrypt file_to_be_encrypted.yml
Vault password:
Decryption successful
Now if we go back and check the content of that file, it will be human-readable again:
cat file_to_be_encrypted.yml
---
- name: Install htop
hosts: all
become: yes
tasks:
- name: Update apt cache
apt:
update_cache: yes
- name: Install htop
apt:
name: htop
state: present
Changing the Password for Encrypted Files
Another common operation is to rotate or change the password used for encryption. As briefly discussed in the previous section, this can be achieved with the ansible-vault rekey
command.
To change the password for an encrypted file, use the command below, and pass the current and the new password when prompted:
ansible-vault rekey file_to_be_encrypted.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful
You will need to provide the old password and then provide a new password and confirm it for this to work.
When you need to decrypt content from a playbook with encrypted variables that have been created with different passwords and vault IDs, pass multiple --vault-id
flags when executing the playbook. For example:
ansible-playbook --vault-id prod@prod_password_file --vault-id dev@dev_password_file --test@test_password_file playbook.yml
In case you use a specific vault ID or a password source more frequently than others, you can define default options and avoid passing them every time. Leverage DEFAULT_VAULT_DENY_LIST and DEFAULT_VAULT_PASSWORD_FILE to set this up.
Here are best practices to consider when you are using Ansible Vault:
- Use strong passwords for encryptions – You should avoid easily guessed passwords, and ensure your passwords are strong and complex.
- Avoid storing Vault passwords in VCS – It goes without saying that you should never commit Vault passwords to a git repository because this will result in instant password breaches
- Rotate secrets regularly – Regularly rotate secrets stored in Ansible Vault to reduce the risk of unauthorized access in case of a breach.
- Audit and Review access – Ensure that only authorized people have access to Vault files and passwords.
- Integrate with Secret Management tools – Integrate with external secret management tools such as HashiCorp Vault or AWS Secrets Manager if you require advanced features and integrations.
Spacelift’s vibrant ecosystem and excellent GitOps flow can greatly assist you in managing and orchestrating Ansible. By introducing Spacelift on top of Ansible, you can then easily create custom workflows based on pull requests and apply any necessary compliance checks for your organization. Another great advantage of using Spacelift is that you can manage different infrastructure tools like Ansible, Terraform, Pulumi, AWS CloudFormation, and even Kubernetes from the same place and combine their Stacks with building workflows across tools.
If you want to learn more about Spacelift working with Ansible, check our documentation, read our Ansible guide or book a demo with one of our engineers.
In this blog post, we explored different options for encrypting sensitive information by leveraging Ansible Vault. We explained Ansible Vault’s main functionality and discussed various options for handling sensitive content, passwords, and files. Lastly, we went over examples and use cases of using encrypted content.
Thank you for reading and I hope you enjoyed this as much as I did!
Manage Ansible Better with Spacelift
Spacelift helps you manage the complexities and compliance challenges of using Ansible. It brings with it a GitOps flow, so your infrastructure repository is synced with your Ansible Stacks, and pull requests show you a preview of what they’re planning to change. It also has an extensive selection of policies, which lets you automate compliance checks and build complex multi-stack workflows.