Ansible

How to Use Ansible Vault to Keep Your Playbooks Secure

How to Keep Your Playbooks Secure With Ansible Vault

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. 

What is Ansible Vault

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.

Ansible Vault Passwords Management

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.

Encrypting Sensitive Data with Ansible Vault

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:

ansible vault encrypt_this_string_please

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.

ansible vault vault ID

You can also select the password source. For example, let’s use a file named password_file as our password source.

ansible vault password_file

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

Working with Encrypted Content

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:

ansible vault pass the password via the prompt

Next, we store this variable in a file named file_with_stored_encrypted_variable.yml.

ansible vault store variable in a file

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.

Ansible Vault Best Practices

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.

Key Points

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. 

You can also explore how 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.

Thank you for reading and I hope you enjoyed this as much as I did!

Automation and Collaboration Layer for Infrastructure as Code

Spacelift is a flexible orchestration solution for IaC development. It delivers enhanced collaboration, automation and controls to simplify and accelerate the provisioning of cloud based infrastructures.

Start free trial