How to Keep Your Playbooks Secure With Ansible Vault

8 min read

Introduction

Configuration management combined with secrets management is very powerful. To configure your infrastructure, you might need all kinds of secrets, including API keys, SSH keys, passwords, and so on. Implementing these secrets securely is an essential requirement. You wouldn’t want these secrets to leak.

Secrets management should be simple. If it’s too difficult, people are tempted to bypass basic security measures. Ansible Vault provides a simple way of managing secrets. In this post, we’ll show you how to quickly get started using Ansible Vault.

Getting Started

Once you have Ansible installed, it’s easy to get started. First, you’ll need to create a Vault file.

Creating a Vault File

Creating from Scratch

To create a Vault file from scratch, you can use the ansible-vault create vault.yml command. It will prompt you for a password. After you’ve entered the Vault password, the file is created.

Converting a Variable File

If you have a variable file you want to convert into a Vault file, you can use the ansible-vault encrypt vars.yml command.

Editing a Vault File

Decrypting a File

Depending on your development environment, editing a Vault file by first decrypting it might be helpful, especially when you have long and multi-line values. To do so, first run the command ansible-vault decrypt vault.yml. You can then edit the file just as you would any other file. After that, simply run ansible-vault encrypt vault.yml again. 

Some disadvantages of this are that you’ll have to type your password both on decrypt and on encrypt. You will also need to make sure not to put the decrypted file in source control.

Editing in Place

For quick and smaller edits, it’s more convenient to edit in place. That’s why ansible-vault provides the “edit” command: ansible-vault edit vault.yml. This will open your default editor, which is usually vi. (If you want to change your default editor—to nano, for example—add export EDITOR=nano at the end of your ~/.bashrc.) When you save and close it, it’s automatically encrypted again.

Changing the Password

To change the password of the Vault file, you can decrypt it and encrypt it again, but Ansible Vault provides an easier way: ansible-vault rekey vault.yml. You’ll be prompted to enter the old password, and then prompted to create a new password. After you have provided both, you can only read the Vault file using the new password.

Using a Vault File

Basic Usage

There are many ways to use a Vault file. An easy and explicit way is to load it directly as extra variables using the command ansible-playbook test.yml -e @vault.yml. The -e flag takes variables directly, as well as a variable file or Vault file. 

You can use Vault files interchangeably with variable files, so if you place the Vault file at group_vars/all/vault.yml, for example, it will load automatically. Or, if you want to create role-specific Vault files, you’d be able to place a Vault file in the roles/rolename/vars/main.yml location. 

However, what’s possible is not always what’s recommended. It gets more challenging to manage the Vault files if you have multiple files and if they are scattered.

Optimizing Local Usage

Storing the Password in a File

If you run your playbooks often, you probably don’t want to type your password every time. To simplify this, Ansible Vault can make use of a password file. This is a file that contains the plain-text password of the Vault file(s). Be careful with that file, and make sure that if it lives inside the project, it never gets into source control. 

To tell Ansible where to find this password file, include it in the command, like so: ansible-playbook site.yml --vault-password-file ~/.vault_pass. You can also set an environment variable to let Ansible know where to find the password, like so: ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.

Dynamically Retrieving the Password 

It’s sensible not to have plain-text passwords living in files. That’s why we are using the Ansible Vault to begin with, right? Fortunately, Ansible Vault also supports scripts or applications to provide the password dynamically. This can be as simple as a bash script, or a Go application, as long as it provides the password in stdout. Make sure the file is executable, to prevent Vault from mistaking the content from the file for the password itself.

Using Environment Variables

If you want to provide the Vault password every time you run the playbook, you can set the ANSIBLE_ASK_VAULT_PASS environment variable to true, to ensure it always requires you to provide the password.

Using the Vault File in CI Systems

When using Ansible to do configuration management—like provisioning or configuring infrastructure—from a CI system, you need to ensure it runs completely non-interactive. Most, if not all, CI systems provide a way to use “secret variables”—variables that get injected into CI jobs as environment variables. 

Let’s say we configure a secret variable with the name ANSIBLE_VAULT_PASSWORD to be the Vault password we want to use. We can then put this into a file and use it non-interactively, like so:

export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
echo "${ANSIBLE_VAULT_PASSWORD}" > "${ANSIBLE_VAULT_PASSWORD_FILE}"
ansible-playbook site.yml

Beyond the Basics

Encrypting Regular Files

What if you want to encrypt other files? That’s also possible. Let’s say you want to encrypt a configuration file for the webserver, which lives in roles/webserver/files/nginx.conf. To do so, run the following command: ansible-vault encrypt roles/webserver/files/nginx.conf. If you then use the copy module below, copying the encrypted configuration file to the destination will decrypt it.

- name: Configure Nginx
  copy:
    src: nginx.conf
    dest: /etc/nginx.conf

Copying decrypts the file transparently. If you want the file encrypted, there are other options.

Using Multiple Vault Files

In most cases, a single Vault file is enough, or if using more encrypted files, a single password suffices. But there are situations in which you want to use multiple Vault files with different passwords (e.g., when you have different Vaults per environment that have different passwords). That’s where Vault Identities come in.

Let’s say you need two passwords, one for your “dev” and one for your “prod” environment. To place these Vault files in their respective locations, run the command: environments/<env>/group_vars/all/vault.yml, and then use a .vault_pass_dev and a .vault_pass_prod password file in the home directory.

To distinguish between the two password files, use Vault Identities to separate them and the vaults. To make this work, add the necessary vault-id and encrypt-vault-id flags to the ansible-vault commands. Assuming you already have a variable file ready to convert to a Vault file, run the following commands to encrypt them:

ansible-vault encrypt environments/dev/group_vars/all/vault.yml --vault-id dev@~/.vault_pass_dev --encrypt-vault-id dev
ansible-vault encrypt environments/dev/group_vars/all/vault.yml --vault-id prod@~/.vault_pass_prod --encrypt-vault-id prod

The encrypt-vault-id flag points to the vault ID you want to use to encrypt the file, while the vault-id flag provides what the identity means. This identity follows the label@file format, where the label serves both as a tag and a reminder of the Vault Identity used to encrypt a file. You can add it to the header like so:

$ANSIBLE_VAULT;1.2;AES256;dev

This is just a plain-text reminder and in no way serves any functional purpose. For example, it doesn’t block you from running ansible-vault decrypt environments/dev/group_vars/all/vault.yml and simply typing the password yourself. On the other hand, to keep things consistent, you are free to use the following command to decrypt:

ansible-vault decrypt environments/dev/group_vars/all/vault.yml --vault-id dev@~/.vault_pass_dev

To simplify using Vault Identities, you can predefine them in the ansible.cfg, like so:

[defaults]
vault_identity_list = dev@~/.vault_pass_dev, prod@~/.vault_pass_prod

This ensures you can do the same thing with less typing, as you won’t need to provide the Vault Identity definition using the vault-id flag. Using the encrypt-vault-id flag suffices.

Encrypting Single Variables

If encrypting a whole file is overkill for your use case, or you want to see which variables are present in a vault, you can choose to encrypt single variables instead of the whole file. This has both benefits and downsides.

Say you have the following file:

username: admin
password: Pa55w0rD

…and you only want the password field to be encrypted. You would need to run the following command:

$ ansible-vault encrypt_string --vault-password-file .vault_pass 'Pa55w0rD' --name 'password'
password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          62326663616638376162646634343238393530363266343333633635613364636237633932336233
          3134646332393839396662643462363064313739373063630a343765383764303131323365633635
          32363737326632326365663334616439303936363664636439653132623761633035336363646136
          3966636430653632630a663139633934626266363937323262363934366266343131306536666332
          3363
Encryption successful

This will return what you need to place inside the variable file to make this work. Of course, if you want to use this inline encrypted variable inside a playbook, that would work just the same. The result should look like this:

username: admin
password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          62326663616638376162646634343238393530363266343333633635613364636237633932336233
          3134646332393839396662643462363064313739373063630a343765383764303131323365633635
          32363737326632326365663334616439303936363664636439653132623761633035336363646136
          3966636430653632630a663139633934626266363937323262363934366266343131306536666332
          3363

With inline encrypted variables, you can also use Vault Identities. In that case, you’d replace the vault-password-file flag with vault-id as we’ve seen before: ansible-vault encrypt_string --vault-id dev@~/.vault_pass_dev 'Pa55w0rD' --name 'password'

Conclusion

There are no good reasons to keep plain-text passwords lying around in your project, especially not in source control. Ansible Vault makes it simple to manage secrets in both small projects and large multi-team enterprise projects. This is where combining configuration management and secrets management becomes a potent mix. 

With great power comes great responsibility—and many other challenges, to be frank. That’s where CloudBees can come in, as they know how to keep things simple when facing the most complex enterprise environments. If you find yourself in an environment where you could use some help to tame complexity, consider getting in contact. Where complexity and simplicity come together: that’s where the real magic can happen.

This post was written by Ruben Jongejan. Automation is Ruben’s thing. He likes to be on the cutting edge—the place where infrastructure, automation, and application development intersect. That's why he spends most of his days in the cloud.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.