Keeping Ansible secrets in the Hashicorp Vault

Hashicorp Vault is an open source secret management tool. Vault is written in Go and distributed as a binary.

When used in conjunction with Ansible, secrets are stored in Vault in key-value form.

Preparing the Vault

We print the storage

$ vault operator unseal

Log in

$ vault login
Token (will be hidden):

Turn on the key-volume version 1 secrets store

$ vault secrets enable -tls-skip-verify -path=ansible kv

We write data in the honeymoon

$ vault kv put -tls-skip-verify ansible/serverlab/production/db 

Run the following command to check

$ vault kv get ansible/serverlab/production/db
======= Data =======
Key           Value
---           -----
dbhost        vault.exampe.local
dbname        blog
dbpassword    passwd123
dbusername    wp_user

Making a read-only policy

Let’s create an ansible.hcl file

$ nano ansible.hcl
path "ansible/*" {
  capabilities = [ "read", "list" ]

Writing the “ansible” policy

$ vault policy write ansible ansible.hcl
Success! Uploaded policy: ansible

Let’s create a token so that we can authenticate

$ vault token create -policy="ansible"
Key                  Value
---                  -----
token                s.7JjtwBWjKrtNsP2pYbwNv9er
token_accessor       JpMeUksuVRuRq0lSW07KRmLi
token_duration       10h
token_renewable      true
token_policies       ["ansible" "default"]
identity_policies    []
policies             ["ansible" "default"]

Preparing Ansible

Install ansible and the hashi_vault plugin

$ sudo dnf install ansible
$ sudo pip3 install hvac

Create a directory for a local playbook and go to it

$ mkdir ansible-test && cd ansible-test

Create a file with our local host

$ nano hosts
vault.example.local ansible_ssh_host=

Create a playbook

$ nano playbook.yml
- hosts: all
  connection: local
    vault_token: s.7JjtwBWjKrtNsP2pYbwNv9er
    vault_secret: ansible/serverlab/production/db
    serverlab_db: "{{ lookup('hashi_vault', 'secret={{ vault_secret }} token={{ vault_token }} url={{ vault_url }}') }}"
    - wordpress
$ mkdir -p roles/wordpress/{tasks,templates}
$ nano roles/wordpress/tasks/main.yml
- name: Configure WordPress
    src: wp-config.php.j2
    dest: /tmp/wp-config.php
    - "{{ serverlab_db }}"
    - update_wp_config

- name: Return all secrets from a path
    msg: "{{ lookup('hashi_vault', 'secret={{ vault_secret }} token={{ vault_token }} url={{ vault_url }} validate_certs=False') }}"
    - test
$ nano roles/wordpress/templates/wp-config.php.j2
define('DB_NAME', '{{ serverlab_db.dbname }}');
define('DB_USER', '{{ serverlab_db.dbusername }}');
define('DB_PASSWORD', '{{ serverlab_db.dbpassword }}');
define('DB_HOST', '{{ serverlab_db.dbhost }}');

Launching the playbook

$ ansible-playbook -i hosts -l servers playbook.yml --tags "test"
$ ansible-playbook -i hosts -l servers playbook.yml --tags "update_wp_config"

The first command will print the result to the console. The second command will pull data from Vault and save it to file


$ cat /tmp/wp-config.php
define('DB_NAME', 'blog');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'passwd123');
define('DB_HOST', 'vault.exampe.local');