DEV Community

Spacelift team for Spacelift

Posted on • Originally published at spacelift.io

How to Keep Your Playbooks Secure Using Ansible Vault

This blog post will explore Ansible Vault as a mechanism for keeping your sensitive values and secrets secure in your playbooks and other Ansible files. We will investigate 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 helpful.

What is Ansible Vault?

Ansible Vault is an Ansible feature that provides a native way to handle sensitive information. It allows users to encrypt secrets and other sensitive data, such as API keys, passwords, and other credentials, to protect them at rest. Ansible Vault is designed to work with YAML files, but it can encrypt any type of text-based file.

Instead of storing secrets in plaintext, Ansible Vault provides a secure, native, and low-effort option for managing sensitive information by leveraging encryption. Encrypted content can be stored in playbooks, variable files, and roles, persisted under source control, and shared without exposure risks. 

Ansible Vault protects sensitive content only at rest. Users are responsible for not exposing decrypted content in the console or in any other way. If necessary, check out the no_log option for tasks to hide their output.

Ansible Vault password management

Passwords are required to encrypt and decrypt sensitive data with Ansible Vault. They 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. There is a password management process for each of these cases. 

Password management for simple cases

For simple cases, small teams, and a few encrypted values, you might leverage the same password for all your encrypted content. This approach simplifies your password management process because you only have to deal with a single password. You should store and handle this password and other sensitive data in your secret management system. 

Password management for more complex systems

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. 

In such cases, you can specify a dedicated vault ID for every password. 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 explore more examples of leveraging vault IDs in the section on how to encrypt sensitive values. 

Where to store your Ansible Vault passwords?

As discussed previously, storing passwords in a local file is a simple but not very secure option. If you decide to use this option, 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 is 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. 

Check out the official documentation's section on storing passwords in third-party tools with Vault password client scripts for details on how to create and use such scripts.

💡 You might also like:

How to use ansible-vault command to encrypt sensitive data

Ansible Vault can help users encrypt mainly two types of data - variables and files. This means we can encrypt either whole files or only specific values stored in encrypted variables. 

Encrypting specific variables means content will be decrypted on demand only when needed. This option allows us to mix encrypted and plaintext content as required 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 cumbersome because there is no command to support this.  

On the other hand, encrypting whole files allows us to encrypt other content (tasks, for example) apart from variables, with decryption happening when the file is referenced. We can easily use the rekey command to change or rotate the password used for file encryption. In general, file-level encryption is easier to use and manage.

A disadvantage of this approach is that encrypting the whole content of the files reduces readability and accessibility because it's difficult to read the file and understand its contents. 

One way to bypass this issue is to keep the names or references of your encrypted content in a separate, non-encrypted file. For more information on the topic, see Keep vaulted variables safely visible

Let's look at some examples. We will start by encrypting a variable.

1. Encrypting Ansible variables

To encrypt a string to use in an Ansible variable, you can leverage the ansible-vault encrypt_string command. The syntax is:

ansible-vault encrypt_string 'your_secret_value' --name 'your_variable_name'
Enter fullscreen mode Exit fullscreen mode

Let's 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 encrypted content produced 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'
Enter fullscreen mode Exit fullscreen mode

You can find more command options by using the --help flag.

ansible-vault encrypt_string --help
Enter fullscreen mode Exit fullscreen mode

2. 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 encryptable files 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 with Ansible Vault, use:

ansible-vault create <file_name>
Enter fullscreen mode Exit fullscreen mode

Enter a password when prompted, add your content in the editor, save, and exit. The file will be encrypted automatically.

For example, let's 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
Enter fullscreen mode Exit fullscreen mode

This will open your configured editor (by default, vi) to provide the content to be encrypted. The considerations for storing and using Ansible Vault passwords discussed earlier also apply here.

After you provide your plain text content to the file and save and exit from it, you will only see the encrypted version when you try to view the content. You will need to decrypt it to view it in plain text again.

Encrypting an existing file

To encrypt an existing file with Ansible Vault, use:

ansible-vault encrypt <file_name>
Enter fullscreen mode Exit fullscreen mode

This will prompt you to set a password for encryption. Once completed, the file will be encrypted and its contents secured.

Before encrypting this example 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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

You will be prompted for a password, which is 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

Enter fullscreen mode Exit fullscreen mode

Using Ansible Vault to work with encrypted content

In the previous section, we explained the process and reviewed 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 user operations is 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"
}
Enter fullscreen mode Exit fullscreen mode

1. Viewing encrypted files

Viewing the contents of encrypted files without decrypting them permanently is quite simple with the ansible-vault view command:

ansible-vault view encrypted_file.yml
Enter fullscreen mode Exit fullscreen mode

2. 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
Enter fullscreen mode Exit fullscreen mode

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.

3. Decrypting encrypted files

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

Note: After running the ansible-vault decrypt command, the file will be permanently decrypted. If you want to temporarily view or use the contents, consider using ansible-vault view instead. Make sure you handle decrypted files securely to prevent accidental exposure of sensitive information.

4. Changing the password for encrypted files

Another common operation is to rotate or change the password used for encryption. As discussed briefly 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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

If 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.

Using environment variable for Ansible Vault passwords

Ansible Vault supports using an environment variable to specify the password for encrypting and decrypting Vault files. This helps avoid passing the password directly as a command-line argument or typing it manually, making it useful for automation in CI/CD pipelines.

The environment variable used by Ansible Vault is ANSIBLE_VAULT_PASSWORD_FILE.

Let's see an example. 

First, create a file containing your Vault password.

echo "my_vault_password" > ~/.vault_pass
chmod 600 ~/.vault_pass
Enter fullscreen mode Exit fullscreen mode

Set the ANSIBLE_VAULT_PASSWORD_FILE environment variable to point to your password file:

export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
Enter fullscreen mode Exit fullscreen mode

With the environment variable set, Ansible Vault automatically uses the password from the specified file, so you don't need to provide it interactively or via the --vault-password-file option.

Encrypt a file:

ansible-vault encrypt vars.yml
Enter fullscreen mode Exit fullscreen mode

Run a playbook that uses Vault-encrypted files:

ansible-playbook playbook.yml
Enter fullscreen mode Exit fullscreen mode

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: 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 only authorized people have access to Vault files and passwords.
  • Integrate with secret management Tools: If you require advanced features and integrations, Integrate with external secret management tools such as HashiCorp Vault or AWS Secrets Manager.

How Spacelift can help you with Ansible projects

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.

Our latest Ansible enhancements solve three of the biggest challenges engineers face when they are using Ansible:

  • Having a centralized place in which you can run your playbooks
  • Combining IaC with configuration management to create a single workflow
  • Getting insights into what ran and where

Provisioning, configuring, governing, and even orchestrating your containers can be performed with a single workflow, separating the elements into smaller chunks to identify issues more easily.

If you want to learn more about using Spacelift with Ansible, check our documentation, read our Ansible guide, or book a demo with one of our engineers.

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 reviewed examples and use cases of using encrypted content.

Written by Ioannis Moustakis and Flavius Dinu

Top comments (0)