Friday, December 30, 2016

Ansible and Vault

Let's start with a cliché. Everyone agrees that security is important, right? We work on deployment process and we need to get secrets into the system securely. Secrets can be passwords and private keys, for instance.

We use Ansible for configuration management so we started with ansible-vault. It has some drawbacks so we found a compelling contender - Vault made by Hashicorp. I would like to describe how we made Ansible work with Vault.

Ansible

Ansible (https://www.ansible.com) - automation for everyone. Dubbed as the most developer friendly automation tool it sports easy syntax, it is simple to translate from what devs are usually most acquiented - Bash - and it runs masterless so one does not need a special master node to handle updates like in cases of Chef and Puppet. The learning curve is favorable.

Vault

Vault (https://www.vaultproject.io) - a server application for storing securely secrets and to allow access to them via remote API. It supports host of features like access tokens, fine-grained access rights, auditing, revoking only secrets which were compromised, certificates provisioning on demand and more.

Running Vault

We use Vault in development configuration since setting up production Vault is more complicated and hard to automate by nature. Development configuration suffice to get you started.

We will provision it locally with Ansible and we will directly set it up with some access policy, enter secrets and get a token which will give us read-only access to some of the secrets.

The structure will be following:

A simple playbook that invokes the vault role.
vault.yml:

It can be invoked with ansible-playbook vault.yml.

We leverage that we are working with Docker (v1.12.5) and we use Ansible Docker integration (available in Ansible v2.2). We deploy official Vault image on Docker first and then perform operations on it.
The steps are:

  • Run the image with Docker.
  • Get the image logs.
  • Grep them for the root token.
  • Run the setup-vault.sh.
  • The script outputs an access token for the specified read policy and we save it to ~/.vault-token file where the Ansible Vault lookup plugin expects it.
The setup-vault.sh script:

The setup creates the access policy, enters two secrets and creates a token which has the aforementioned policy so one can only read these secrets with the token.

The read-policy.json:

You can check the setup works by running:

  • export VAULT_TOKEN=$(cat ~/.vault-token) - to export the file content to env variable.
  • curl -H "X-Vault-Token: $VAULT_TOKEN" localhost:8200/v1/secret/app/test/ldap-pwd. - to hit the Vault API.

Ansible with Vault

Now that we have Vault up and running let's get secrets into Ansible. It is surprisingly easy thanks to the good work of Johan Haals on his ansible-vault lookup plugin (https://github.com/jhaals/ansible-vault). I would say that the name is confusing (being the same with ansible-vault tool) but other than that the plugin works very well. I also read that the chances are the plugin will make it into Ansible so you wouldn't have to install it manually.

ansible-vault installation

Let's say we stick with default Ansible plugins' location as outlined in the configuration.

  • sudo mkdir /usr/share/ansible/plugins/lookup
  • sudo vim /etc/ansible/ansible.cfg and uncomment the line lookup_plugins = /usr/share/ansible/plugins/lookup.
  • sudo git clone https://github.com/jhaals/ansible-vault.git /usr/share/ansible/plugins/lookup/ansible-vault
Well, you're done!

Retrieving Secrets

In our case we have configuration templates and we want to replace hard-coded secrets with lookup. A typical template in our case is an XML file or a properties file. It may look like this:

We put the password in Vault and modify the template:

Ansible template_module uses Jinja2. We wrap variables in {{ }}. We put in the lookup call where we invoke our freshly installed vault lookup plugin.
We can also see how to use variable within Ansible lookup. Simply put it without any quotation. In case you need some literals around it like we do, concatenate it with +.

The last step is to use to invoke the template module from a playbook:

And the role:

The source application.properties can be found in the /files.

That's it! Personally, I struggled a bit with Vault setup, its API calls syntax. But the documentation was helpful and once I had that running making Ansible use Vault was very smooth.

No comments:

Post a Comment