5 minute read Published: Author: Derek Laventure
Cloud , Infrastructure , Ansible , Vault


You are reading our blog series: Pure Ansible Infrastructure


So far in this series, we’ve covered most of the foundational pieces of our pure ansible infrastructure project. We’ve got Drumkit installed, and configured our dynamic inventory. The last piece we need is a way to configure the fine-grained details of the Ansible playbooks and roles we’ll be running. We also need a secure way to store variables with sensitive data, in such a way that Ansible can access them as needed.

The simplicity of Ansible’s approach to these questions is very powerful.

Everything is variable

The variables system in Ansible integrates with the inventory of hosts and groups, as discussed in the previous post. Variables can be used for just about any value, and are typically represented in YAML files. In our example project, we have 3 key sets of variables:

The host_vars/localhost variables are very minimal in this example, essentially setting the state of the various infrastructure components, as referenced in the playbooks responsible for bringing up the Project, VPC, and Firewall resources, all of which use localhost as the inventory target to run against. These could be more elaborate if needed, but again: for the simplicity of the project, this is enough.

The group_vars/all variables are basically globals, and also fairly minimal. They define things like the name of the infrastructure Project, VPC and Firewall resources. These are used by the infra playbooks as well, but also referenced in the role that creates our Droplet, to associate the resources correctly.

Finally, the droplet-specific variables that live in the host playbook are essentially setting the parameters needed by our consensus.infra.droplet role. Here we set the hostname, domain, size, tags, and so on. We also pass credentials to DigitalOcean and Gandi, since the role will need to speak to both of them.

Note that the pattern of including the variables directly in the playbook is not best practice, but because the playbook targets localhost, there is no obvious place to create a vars.yml file for it. We could place them in either host_vars/localhost or group_vars/all, but this would break until we have more than one droplet. What we probably need is a structured variable that lists each droplet and this set of parameters (hostname, domain, size, etc) for each. Once again: beyond a handful of hosts, we really need a manifest of some description.

Can you keep a secret?

Ansible Vault is a purpose-built symmetric encryption tool that integrates seamlessly with Ansible’s native variables system, and makes it possible to store your credentials (think: API tokens, passphrases, etc) within your codebase securely. You can then share a single vault password amongst the team working on the project, and this unlocks everything else they need.

This means it’s trivial to store our project-specific secrets and credentials within the project itself. Our example has 2 vault files set up:

As you can see, these files are encrypted, so looking at them directly won’t help. Instead, we need to run ansible-vault to create, view, or edit them. For example:

 $ ansible-vault view inventory/group_vars/all/vault.yml
 ---
 vaulted_tailscale_authkey: "tskey-auth-kjQ4qQ2r4111CNTRL-Z1fYkxcST5HhQCcsKxcm4HS4CGh834jD"
 vaulted_gandi_access_token: 0c04345ab02f1484d080fd3ae925f2e2a10d80d0
 vaulted_outgoing_smtp_password: "some very good password or passphrase to go with the org_technical_contact_email address used for outbound email from this server."
 vaulted_mysql_root_password: "really_not_a_secure_mysql_password_please_change"

The group_vars/all folder contains most of the secrets for this project, and the host_vars/localhost one only the oauth_token for DigitalOcean. Technically these could all live in one place, but the DO token seems more logically associated with our API access to the infrastructure, whereas the other credentials are more from the perspective of inside the infrastructure (they get used on the droplets themselves). We can of course also create other vault files for host or group-specific credentials as needed.

Each of these “vaulted” variables will be avaiable to playbooks just the same as regular variables, so we see this pattern frequently in playbooks:

- vars:
    gandi_token: "{{ vaulted_gandi_access_token }}"

This will pass the sensitive value to the play or role as the variable gandi_token, which it can use as needed.

None shall .vault_pass

Of course, all of this hinges on a password for the vault files themselves. We typically use a single password for all the vaults in a given project, but it’s possible to set them individually if needed. We set the vault password when we create it:

$ ansible-vault create inventory/group_vars/all/new-vault.yml
New Vault password:

By default, whenever we run a playbook, Ansible will prompt us for the vault password(s) to unlock those it finds in the project. However, if we configure our ansible.cfg with a simple line like:

[defaults]
vault_password_file = .vault_pass

Then we paste our vault password into a file named .vault_pass in the same place as our ansible.cfg, and it will no longer prompt us. Our example repository even has a handy make .vault_pass target to create this file for us, by simply prompting for the password and writing it to the correct file.

In our example project, we have ansible.cfg set to point to an insecure vault password file called dot_vault_pass. If you intend to use this project for your own purposes, you are strongly advised to either remove the two vault files and recreate them with a strong and private vault password, or re-key the existing ones (see notes in the README for details.

We have come a long way! Having put Drumkit and our dynamic inventory in place, and now setting up variables and vault files, we are ready to start building the Ansible playbooks that comprise our pure ansible infrastructure project. In the next post, we’ll look at how we’ve structured these playbooks within the project, and then go on to review the playbooks and roles that provision the cloud resources and ultimately the Droplet and Aegir3 software.


The article Variables and Vault first appeared on the Consensus Enterprises blog.

We've disabled blog comments to prevent spam, but if you have questions or comments about this post, get in touch!