9 min read

In this In this article by Jesse Keating, author of the book Mastering Ansible, we will see how to how to encrypt data at rest using Ansible. Secrets are meant to stay secret. Whether they are login credentials to a cloud service or passwords to database resources, they are secret for a reason. Should they fall into the wrong hands, they can be used to discover trade secrets and private customer data, create infrastructure for nefarious purposes, or worse. All of which could cost you or your organization a lot of time and money and cause headache! In this article, we cover how to keep your secrets safe with Ansible.

  • Encrypting data at rest
  • Protecting secrets while operating

(For more resources related to this topic, see here.)

Encrypting data at rest

As a configuration management system or an orchestration engine, Ansible has great power. In order to wield that power, it is necessary to entrust secret data to Ansible. An automated system that prompts the operator for passwords all the time is not very efficient. To maximize the power of Ansible, secret data has to be written to a file that Ansible can read and utilize the data from within.

This creates a risk though! Your secrets are sitting there on your filesystem in plain text. This is a physical and digital risk. Physically, the computer could be taken from you and pawed through for secret data. Digitally, any malicious software that can break the boundaries set upon it could read any data your user account has access to. If you utilize a source control system, the infrastructure that houses the repository is just as much at risk.

Thankfully, Ansible provides a facility to protect your data at rest. That facility is Vault, which allows for encrypting text files so that they are stored “at rest” in encrypted format. Without the key or a significant amount of computing power, the data is indecipherable.

The key lessons to learn while dealing with encrypting data at rest are:

  • Valid encryption targets
  • Creating new encrypted files
  • Encrypting existing unencrypted files
  • Editing encrypted files
  • Changing the encryption password on files
  • Decrypting encrypted files
  • Running the ansible-playbook command to reference encrypted files

Things Vault can encrypt

Vault can be used to encrypt any structured data file used by Ansible. This is essentially any YAML (or JSON) file that Ansible uses during its operation. This can include:

  • group_vars/ files
  • host_vars/ files
  • include_vars targets
  • vars_files targets
  • –extra-vars targets
  • role variables
  • Role defaults
  • Task files
  • Handler files

If the file can be expressed in YAML and read by Ansible, it is a valid file to encrypt with Vault. Because the entire file will be unreadable at rest, care should be taken to not be overzealous in picking which files to encrypt. Any source control operations with the files will be done with the encrypted content, making it very difficult to peer review. As a best practice, the smallest amount of data possible should be encrypted; this may even mean moving some variables into a file all by themselves.

Creating new encrypted files

To create new files, Ansible provides a new program, ansible-vault. This program is used to create and interact with Vault encrypted files. The subroutine to create encrypted files is the create subroutine. Lets have a look at the following screenshot:

To create a new file, you’ll need to know two things ahead of time. The first is the password Vault should use to encrypt the file, and the second is the file name. Once provided with this information, ansible-vault will launch a text editor, whichever editor is defined in the environment variable EDITOR. Once you save the file and exit the editor, ansible-vault will use the supplied password as a key to encrypt the file with the AES256 cipher.

All Vault encrypted files referenced by a playbook need to be encrypted with the same key or ansible-playbook will be unable to read them.

The ansible-vault program will prompt for a password unless the path to a file is provided as an argument. The password file can either be a plain text file with the password stored as a single line, or it can be an executable file that outputs the password as a single line to standard out.

Let’s walk through a few examples of creating encrypted files. First, we’ll create one and be prompted for a password; then we will provide a password file; and finally we’ll create an executable to deliver the password.

The password prompt

On opening the editor asks for the passphrase, as shown in the following screenshot:

Once the passphrase is confirmed, our editor opens and we’re able to put content into the file:

On my system, the configured editor is vim. Your system may be different, and you may need to set your preferred editor as the value for the EDITOR environment variable.

Now we save the file. If we try to read the contents, we’ll see that they are in fact encrypted, with a small header hint for Ansible to use later:

The password file

In order to use ansible-vault with a password file, we first need to create the password file. Simply echoing a password in a file can do this. Then we can reference this file while calling ansible-vault to create another encrypted file:

Just as with being prompted for a password, the editor will open and we can write out our data.

The password script

This last example uses a password script. This is useful for designing a system in which a password can be stored in a central system for storing credentials and shared with contributors to the playbook tree. Each contributor could have their own password to the shared credentials store, from where the Vault password can be retrieved. Our example will be far simpler: just simple output to standard out with a password. This file will be saved as password.sh. The file needs to be marked as an executable for Ansible to treat it as such. Lets have a look at the following screenshot:

Encrypting existing files

The previous examples all dealt with creating new encrypted files using the create subroutine. But what if we want to take an established file and encrypt it? A subroutine exists for this as well. It is named encrypt and is outlined in the following screenshot:

As with create, encrypt expects a password (or password file) and the path to a file. In this case, however, the file must already exist. Let’s demonstrate this by encrypting an existing file, a_vars_file.yaml:

We can see the file contents before and after the call to encrypt. After the call, the contents are indeed encrypted. Unlike the create subroutine, encrypt can operate on multiple files, making it easy to protect all the important data in one action. Simply list all the files to be encrypted, separated by spaces.

Attempting to encrypt already encrypted files will result in an error.

Editing encrypted files

Once a file has been encrypted with ansible-vault, it cannot be edited directly. Opening the file in an editor would result in the encrypted data being shown. Making any changes to the file would damage the file and Ansible would be unable to read the contents correctly. We need a subroutine that will first decrypt the contents of the file, allow us to edit these contents, and then encrypt the new contents before saving it back to the file. Such a subroutine exists and is called edit. Here is a screenshot showing the available switches:

All our familiar options are back, an optional password file/script and the file to edit. If we edit the file we just encrypted, we’ll notice that ansible-vault opens our editor with a temporary file as the file path:

The editor will save this and ansible-vault will then encrypt it and move it to replace the original file as shown in the following screenshot:

Password rotation for encrypted files

Over time, as contributors come and go, it is a good idea to rotate the password used to encrypt your secrets. Encryption is only as good as the other layers of protection of the password. ansible-vault provides a subroutine, named rekey, that allows us to change the password as shown here:

The rekey subroutine operates much like the edit subroutine. It takes in an optional password file/script and one or more files to rekey. Note that while you can supply a file/script for decryption of the existing files, you cannot supply one for the new passphrase. You will be prompted to input the new passphrase. Let’s rekey our even_more_secrets.yaml file:

Remember that all the encrypted files need to have a matching key. Be sure to re-key all the files at the same time.

Decrypting encrypted files

If, at some point, the need to encrypt data files goes away, ansible-vault provides a subroutine that can be used to remove encryption for one or more encrypted files. This subroutine is (unsurprisingly) named decrypt as shown here:

Once again, we have an optional argument for a password file/script and then one or more file paths to decrypt. Let’s decrypt the file we created earlier using our password file:

Executing ansible-playbook with Vault-encrypted files

To make use of our encrypted content, we need to be able to inform ansible-playbook how to access any encrypted data it might encounter. Unlike ansible-vault, which exists solely to deal with file encryption/decryption, ansible-playbook is more general purpose and will not assume it is dealing with encrypted data by default. There are two ways to indicate that encrypted data may be encountered. The first is the argument –ask-vault-pass, which will prompt for the vault password required to unlock any encountered encrypted files at the very beginning of a playbook execution. Ansible will hold this provided password in memory for the duration of the playbook execution. The second method is to reference a password file or script via the familiar –vault-password-file argument.

Let’s create a simple playbook named show_me.yaml that will print out the value of the variable inside of a_vars_file.yaml, which we encrypted in a previous example:

---
- name: show me an encrypted var
hosts: localhost
gather_facts: false

vars_files:
   - a_vars_file.yaml

tasks:
   - name: print the variable
     debug:
       var: something

The output is as follows:

Summary

In this article we learnt that Ansible can deal with sensitive data. It is important to understand how this data is stored at rest and how this data is treated when utilized. With a little care and attention, Ansible can keep your secrets secret. Encrypting secrets with ansible-vault can protect them while dormant on your filesystem or in a shared source control repository. Preventing Ansible from logging task data can protect against leaking data to remote log files or on-screen displays.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here