You are reading our blog series: Pure Ansible Infrastructure
- Toward infrastructure simplicity
- Drumkit and other plumbing
- Dynamic inventory
- Variables and Vault (You are here)
- Soon: Playbooks and support infrastructure
- Soon: Building Ansible Collections
- Soon: Putting it together: make targets, Droplets, and Aegir3
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!