Using Hashicorp Vault with Ansible Jinja2 Templates

In this tutorial, we are going to learn how to integrate Hashicorp Vault into our Ansible templates for better, more secure secrets management. While we could use the built-in, native vaulting tool to protect our secrets in a local file encrypted using AES256, placing your secrets in a secure vault off host is a better solution.

The problem with keeping your encrypted file locally you need a mechanism to share those secrets. Storing your data in a Git repository to more easily share it could mean giving an attacker access to the file. Having access to the file means it can be brute-forced.

Now, according to the cryptographic specs of an AES256 encrypted file, it would take eons to brute-force with today’s hardware. So then, why isn’t it safe to store these files publicly? Vulnerabilities in the implementation of said cryptography could mean rather than eons to crack it, it could possibly be forced open within hours.

Storing our secrets in an off-host vault, completely separate from our code and scripts, provides better protection for our sensitive data from being leaked. Hashicorp vault is a free, open-source project to provides with a way to store our secrets safely.

You won’t have to remember to URI to request your secrets, as Ansible does how some support built it. You will, however, be required to install two Python dependencies on the machine running your playbooks — not the targeted hosts the tasks are being played against.

Dependencies

Before you will begin you will need the following installed on your local desktop. If you are running OSX or Linux you can pip install them.

  • hvac
  • hvac[parser]

Register Secrets

For this tutorial, we are going to register three secrets into our Hashicorp Vault —- username, password, and host. These will be the credentials and host of our application’s production database.

vault write secret/serverlab/production_db username=appuser password=password123 host=my.database.server

 

Creating the Ansible Playbook

We’re going to create a new playbook for accessing our secrets from Vault. By using Ansible’s lookup module, we query Vault for our secrets and store them in a variable as a dictionary.

The dictionary can then be used by a Jinja2 template to populate the necessary settings.

——
- hosts: all
  vars:
    prod_db: “{{ lookup(‘hashi_vault’, ‘secret=serverlab/production/db token={{ vault_token }} url={{ vault_url }}”
  tasks:
    - name: Configure app
      template:
        src: config.json.j2
        dest: /srv/myapp/config.json
        owner: appuser 
        group: appuser 
        mode: 0644
      with_dict: 
        - "{{ prod_db }}"
      tags:
        - app_config
        - app_deploy

Jinja2 Vault Template

Our configuration file will be JSON based. Since we are working with a dictionary, we can specify the key to we want the value for. In the example below, we are populating the configuration file with our database host and our credentials.

 

{
  “database”: {
    “host”: “{{ prod_db.host }}”,
    “username”: “{{ prod_db.username }}”,
    “password”: “{{ prod_db.password }}”
  }
}

Now run the playbook against your application server. The host you are running the playbook on will contact the Vault server to grab the specified secrets. That information will then be registered as a variable, accessible to the template on the remote host we are configuring.

PLAY [all] ******************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************
ok: [192.168.57.102]

TASK [Expose the secrets!] **************************************************************************************************************************************************************************
changed: [192.168.57.102] => (item={'value': u'appuser', 'key': u'username'})
ok: [192.168.57.102] => (item={'value': u'prod-db.server.intra', 'key': u'host'})
ok: [192.168.57.102] => (item={'value': u'password123', 'key': u'password'})

PLAY RECAP ******************************************************************************************************************************************************************************************
192.168.57.102             : ok=2    changed=1    unreachable=0    failed=0   

And that’s all there is to it. You now are able to retrieve secrets from Hashicorp vault and populate your sensitive information. We’ve just improved how you store your sensitive information, better protecting you against accidental data sharing and leaks.