I use Ansible Vault to securely store the project's secrets (e.g. API keys, default passwords, private keys, etc.) in the git repository for many of my infrastructure projects. I also like to make sure I cover everything possible in automated tests/CI, using either Jenkins or Travis CI (usually).

But this presents a conundrum: if some of your variables are encrypted with an Ansible Vault secret/passphrase, and that secret should be itself store securely... how can you avoid storing it in your CI system, where you might not be able to guarantee it's security?

The method I usually use for this case is including the Vault-encrypted vars at playbook runtime, using include_vars :

- name: Include private key from Ansible Vault encrypted file.

include_vars: vars/private_key.yml

when: not test_mode

That way, in my CI environment, I can make sure the test_mode variable is set to True , and it won't include the encrypted variable. Great! But there's still one more issue. Even though you're not using the included variable file, if you have a vault_password_file defined in your project ansible.cfg , then Ansible will always look for that file prior to beginning playbook execution (since the include_vars will be dynamically performed later in the execution, and Ansible needs to load in the password at the beginning).

So, in a CI environment, you can do something like:

mkdir -p ~/.ansible && touch ~/.ansible/vault-password.txt

So, what happens if you run ansible-playbook in CI now?

[WARNING]: Error in vault password file loading (default): Invalid vault

password was provided from file (/root/.ansible/vault-password.txt)

D'oh! Not quite what we were expecting. This used to work, but in Ansible 2.3.2+, a check was added to verify the vault_password_file is not empty. So, we have to make sure the file is not empty. Change the earlier command to:

mkdir -p ~/.ansible && echo "test-password" > ~/.ansible/J2-vault-password.txt"

Ahh... now ansible-playbook will execute and skip decrypting any included vars files that you put the test_mode conditional on!

For completeness, here's an example Travis CI .travis.yml file that will test a playbook in a Docker container running Ubuntu 16.04:

---

services: docker



script:

- container_id=test

- set -e

# Start a Docker container.

- 'docker run --detach --volume=${PWD}:/etc/ansible/playbook:rw --name ${container_id} --privileged --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro geerlingguy/docker-ubuntu1604-ansible:latest /lib/systemd/systemd'



# Prep the container.

- 'docker exec --tty ${container_id} env TERM=xterm bash -c "mkdir -p ~/.ansible && echo "test-password" > ~/.ansible/vault-password.txt"'



# Install dependencies.

- 'docker exec --tty ${container_id} env TERM=xterm bash -c "cd /etc/ansible/playbook; ansible-galaxy install -r requirements.yml"'



# Run Ansible playbook (first with a syntax check, then for real).

- 'docker exec --tty ${container_id} env TERM=xterm bash -c "cd /etc/ansible/playbook; ansible-playbook -i inventory/travis main.yml --syntax-check"'

- 'docker exec --tty ${container_id} env TERM=xterm bash -c "cd /etc/ansible/playbook; ansible-playbook -i inventory/travis main.yml --extra-vars "{test_mode: True}""'

If you liked this post, you'll love my book on Ansible, Ansible for DevOps!