How to protect sensitive data with encrypted files (or elements) in Ansible – Ansible Vault

When we automate configurations we cannot avoid providing secrets to Ansible. The last thing we want is our secret data running around in plain text files on our control node. Luckily Ansible has a tool for this.

Ansible Vault is an integrated encryption tool in Ansible to manage sensitive data like passwords, keys and certificates. As with most parts of Ansible, we can start simple, and complexity can come later on.

Creating an encrypted variables file is easy using the ansible-vault command. Let’s follow the simple directory layout suggested by the Ansible team.

We have the host_vars and group_vars directories in our Ansible project root. If they don’t exist, let’s create them!

$ mkdir {host_vars,group_vars}

Now we can create a directory under our host_vars and call it as we call our Ansible control node in the inventory. My control node is called ansible-control, so I create a directory for it.

$ mkdir host_vars/ansible-control

Our directory structure is ready and Ansible will find the variables and secrets with it.

Let’s create an encrypted file and set up a strong Vault password on it!

$ ansible-vault create host_vars/ansible-control/vault.yml
New Vault password: 
Confirm New Vault password:

After setting the password ansible-vault will open the file in our default editor. We can edit this file as an ordinary YAML variable file for Ansible.

Let’s create a test variable and save the file!

# host_vars/ansible-control/vault.yml
---
var1: secret

After closing the file we can see that it is encrypted with AES256 encryption.

$ cat host_vars/ansible-control/vault.yml
$ANSIBLE_VAULT;1.1;AES256
38306134643266623862643864666330306339613066373531383032616463333333313235626434
3064663733343439303630373263386536346436353430630a656530646237313533663436326561
31363565333939663263306262633564383461363966343439646335666339626633303264333637
3832303763323536320a613763306565346534373738393735393461313261356134663935343833
66663631613239373862343665313334636562363266306363316139653138663038

When we want to edit it we have to use the ansible-vault edit command giving it the file as a parameter. Then the command asks for the Vault password.

$ ansible-vault edit host_vars/ansible-control/vault.yml
Vault password:

Now we can use these variables in a playbook or role. When we want to use the variables encrypted by Vault we have to pass the --ask-vault-pass option to our ansible-playbook command to be able to decrypt them during the Ansible run.

Let’s create a test playbook and check it in action!

---
- name: Test playbook for playing with Ansible
  hosts: all

  tasks:
    - name: Write out our secrets
      ansible.builtin.debug:
        msg: "{{ var1 }}"

We can run it now.

$ ansible-playbook -i inventory play-test.yml --limit ansible-control --ask-vault-pass

Note the --ask-vault-pass option! The output will be something like the following.

TASK [Write out our secrets] ***********************************************************************************************************************************
ok: [ansible-control] => {
    "msg": "secret"
}

We can see that encrypting whole files is easy. The drawback is that when we store these encrypted files in source control management the whole file will change after changing a single variable. The solution will be the individual variable encryption that we will investigate later.

Another issue with secret variables that they are only encrypted in rest. When Ansible uses the secrets it may reveal them in its output or logs.

There is a solution for this! We can use the no_log: true option for a task that uses secrets to do NOT write the output to the screen or to the logs.

---
- name: Test playbook for playing with Ansible
  hosts: all

  tasks:
    - name: Write out our secrets
      ansible.builtin.debug:
        msg: "{{ var1 }}"
      no_log: true

Let’s see it in action!

$ ansible-playbook -i inventory play-test.yml --limit ansible-control --ask-vault-pass
Vault password: 

PLAY [Test playbook for playing with Ansible] ******************************************************************************************************************

TASK [Gathering Facts] *****************************************************************************************************************************************
ok: [ansible-control]

TASK [Write out our secrets] ***********************************************************************************************************************************
ok: [ansible-control]

PLAY RECAP *****************************************************************************************************************************************************
ansible-control            : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

As we can see the output does not contain the secret value anymore.

Now we can create real playbooks and roles using sensitive data without leaking it to unauthorized eyes.

If you have anything to share then please visit my Tom’s IT Cafe Discord Server!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s