Using Ansible Vault

Using Ansible Vault

The purpose of this lab is to show how to use Ansible Vault to protect sensitive data, like passwords, when working with Ansible.

vTeam Specialization Program

Pure Storage nominated me recently to join the Pure Storage vTeam Specialization program for New Stack. The idea behind the program is, to create an active community within Pure Storage. Allowing Puritans to learn and develop their skills and grow into a subject matter experts.

The program consists of training and lab exercises that are focussed on developing experience in the New Stack space (Kubernetes, Ansible, Open Stack and more).

Since I think there are more people out there how want to learn more about New Stack, I will blog my progress in a series of lab exercises.

Lab instructions

The purpose of this lab is to use of Ansible Vault to protect sensitive data in Ansible. This can for example be used to protect the API tokens used to access FlashBlade and FlashArray.

Name:Ansible Vault
Description:Create a role to manage a FA or FB using Vault
Objective:Be able to use vault to hide API tokens
Task #1:Create a vault
Task #2:Create a password file
Task #3:Enter an API token into the vault
Task #4:Use the encrypted vault key in a simple playbook
Task #5:Run playbook to get info from the array
Lab goals and tasks

Intro to Ansible Vault

Ansible Vault is designed to protect sensitive data against exposure. So basically encrypting usernames, passwords and other sensitive data. It uses Vaults for that. Within a Vault you can store the same content as a regular yaml file.

To use Ansible Vault in a playbook there is a Best Practice from Ansible that suggests to use host_vars and group_vars. So before we dive into using Ansible Vault, lets first quickly explore host_vars and group_vars.

Using host_vars and group_vars

As we have seen in an earlier blog, we can use inventories to define our hosts and groups to use in our playbook. Once these hosts and/or groups have been defined, you can automatically load variables when you target a specific host or group.

To do this, create a directory host_vars or group_vars in the directory where your playbook is located. Now in these directories you can create files with the same names as the hosts or groups.

In my case I’ll be running a playbook against localhost to run the purefa_info module. So I create a file called host_vars/localhost and add the following content (I’ve obfuscated the API token for obvious reasons):

---
fa1_url: 192.168.10.12
fa1_api_token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
fa2_url: 192.168.10.15
fa2_api_token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Reference our host_vars from a playbook

Next I create a simple playbook containing the following:

- name: Ansible test script
  hosts: localhost
  gather_facts: true
  collections:
    - purestorage.flasharray
  tasks:
    - name: Get info
      purefa_info:
        gather_subset:
          - minimum
        fa_url: "{{ fa1_url }}"
        api_token: "{{ fa1_api_token }}"
      register: array_info
    - name: Show info
      debug:
        msg: "{{ array_info }}"

A simple playbook that runs two tasks, the purefa_info module to collect data from FlashArray and the debug module to show me the data that was collected. However you’ll notice that I have not defined any variables, but I do reference the fa1_url and fa1_api_token variables in the playbook. These variables get loaded automatically from the host_vars that I’ve defined.

If you run the playbook, you’ll that it executes just fine. So that is the preferred way to access variables in Ansible, if not located in the playbook itself.

Now that we’ve seen how to use variables the correct way, let’s go ahead an put them into a Vault!

Creating a Vault

The first step in using Ansible Vault is to create an actual Vault. Which raises the question what a Vault is? Basically a Vault is a file or variable that has been encrypted by Ansible Vault. Any Vault is encrypted and decrypted as a whole so you generally will have multiple Vaults for multiple hosts, groups or environments.

For this lab we’ll be creating a Vault that will store our FlashBlade and FlashArray IP addresses and API tokens for our localhost. For this we’ll remove the existing localhost file and recreate it using the following commands:

rm host_vars/localhost
ansible-vault create host_vars/localhost

The command will prompt for a password to be entered twice, which is used to encrypt our Vault. Once we’ve entered the password, an editor is opened, so that we can add content to our new Vault.

For this lab we will use the exact same text that we did earlier to create our host_vars/localhost file. Now save the file.

If we open the file with a regular file editor, we’ll see the first line as $ANSIBLE_VAULT;1.1;AES256 and after that a random sequence of numbers, which if the encrypted data.

The data in the Vault is now no longer visible to users who do not have the password. To modify the contents of the Vault, we can use the following command:

ansible-vault edit host_vars/localhost

After we enter our password, we can change the contents using our editor.

Using our Vault in our playbook

Since we’ve used the same file name as we did before, the Vault will automatically be loaded when we run our Ansible playbook. However we need to specify a password to descrypt the Vault, so running the same command:

ansible-playbook purefa_info.yaml

Will return an error:

ERROR! Attempting to decrypt but no vault secrets found

So we need to add the parameter --ask-vault-pass as so:

ansible-playbook purefa_info.yaml --ask-vault-pass

Now when we run the playbook, Ansible will prompt us for the Vault password and once entered our playbook continues in the same way as before when we weren’t using Vault.

Showing Vault variable in vars

In some cases you’ll be combining regular variable with variables stored in the Vault. In this case it might make sense to show all the configurable variables in a single file, while the sensitive variables are stored in the Vault. For this Ansible states that the best practice is to use a slightly different setup.

First remove the Vault we’ve created before and create a directory for the host to use (in our case still localhost):

rm host_vars/localhost
mkdir -p host_vars/localhost

Now we create our Vault, where we will now only store our API tokens:

ansible-vault create host_vars/localhost/vault

And we will add the following lines (obviously you’ll want to enter the actual API tokens here). Note that we changed the variable name from fa1_api_token to vault_fa1_api_token here.

---
vault_fa1_api_token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
vault_fa2_api_token: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Next we want to create our plain text variables file:

nano host_vars/localhost/vars

And we add the following lines:

---
fa1_url: 10.225.112.80
fa1_api_token: "{{ vault_fa1_api_token }}"       
fa2_url: 10.225.112.180
fa2_api_token: "{{ vault_fa2_api_token }}"

The fa1_url and fa2_url are just regular variables that are visible to anyone with access to the playbook. However the fa1_api_token point to the vault_fa1_api_token using Jinja2. This way the variable will resolve by looking up the variable that is stored in the Vault.

We can test our playbook using the exact same command as before:

ansible-playbook purefa_info.yaml --ask-vault-pass

The advantage of this approach that anyone can see the variables that have been defined for the playbook. However to actually access the sensitive information (in this case the API tokens), you’ll need to access the Ansible Vault using the password.

Using a Vault password file

In addition to the --ask-vault-pass parameter that we’ve seen so far, Ansible also allows us to store out Vault password in a file.

To use a password file, just create a file and put the password in the file in plain text. I will use ~/vault-passwd. Now we can use:

ansible-playbook purefa_info.yaml --vault-password-file ~/vault-passwd

While this method saves you from having to enter your password everytime you run Ansible, you need to make sure that the password is kept very secure, since it’s stored in plain text in the password file.

I would suggest to use strict permissions, in the same sense as used for you SSH private key, so:

chmod 600 ~/vault-passwd

Which will only allows your user access to the password file.

Conclusion

This concludes this lab, where we’ve gone through a first introduction into Ansible Vault.

Leave a Reply

Your email address will not be published.