Securely Accessing Ansible Vault in Development

Guideline for securely accessing Ansible Vault during development without storing passwords in plain files, using environment variables and scripts.

Projects: c2platform/phx/ansible, c2platform.core


Problem

When developing and testing Ansible playbooks that use Ansible Vault, running ansible-playbook can be cumbersome. You must repeatedly enter the vault password each time. Using a vault password file is an option, but it is not secure and is considered poor practice, as it risks exposing sensitive information.

Context

In Ansible engineering work on projects that use an Ansible Inventory Project which includes a vault managed with Ansible Vault, you must provide the vault passphrase to avoid provisioning failures. You can do this with the --ask-vault-pass flag:

ansible-playbook site.yml --ask-vault-pass

Alternatively, use --vault-password-file to specify a password file. For more details, see the Ansible documentation  .

If using a password file, ensure its permissions prevent unauthorized access, and never commit it to source control. However, storing vault passwords in files is not ideal—it increases security risks, as mistakes can easily lead to leaks.

Solution

A more secure alternative, especially in high-security environments where storing secrets in files is unacceptable, is to use an environment variable to hold the password in memory. Then, set the Ansible environment variable ANSIBLE_VAULT_PASSWORD_FILE to a script that echoes this variable. Note that ANSIBLE_VAULT_PASSWORD_FILE serves as an alternative to --vault-password-file. Importantly, the “password file” can be either a plain text file or an executable script (e.g., Bash or Python) that outputs the password.

The password resides in memory only for the duration of the shell session, which is acceptable for most environments1.

Examples and implementation

The Ansible inventory project c2platform/phx/ansible includes an Ansible Vault-based vault (see folder secret_vars).

This vault is included via include_vars in the Ansible Secrets role c2platform.core.secrets  .

roles/secrets/tasks/main.yml

20    - name: Include secrets
21      ansible.builtin.include_vars:
22        dir: "{{ secrets_dir_item['secrets_dir_item'] }}"
23      loop: >-
24        {{ secrets_dirs_stats['results']
25        | selectattr('stat.exists', 'equalto', True) }}        
26      loop_control:
27        label: "{{ secrets_dir_item['secrets_dir_item'] }}"
28        loop_var: secrets_dir_item
29      when: secrets_dir_item.stat.exists

The Ansible Secrets role allows flexible configuration of vault locations using a variable secrets_dirs.

group_vars/all/secrets.yml

---
secrets_dirs:
  - "{{ inventory_dir }}/secret_vars/development"
  - "/runner/project/secret_vars/{{ px_env }}"  #  awx / aap

On the Ubuntu-based desktop pxd-ubuntu-devtop, Ansible creates a script /usr/local/bin/vault-client.sh, see Setting Up an Ansible Development Desktop for more information. The configuration responsible for creating this file is in group_vars/ubuntu_devtop/main.yml

group_vars/ubuntu_devtop/main.yml

16    - name: /usr/local/bin/vault-client.sh
17      type: copy
18      dest: /usr/local/bin/vault-client.sh
19      content: |
20        #!/bin/bash
21
22        # vault-client.sh
23        # This script is intended to be used as ANSIBLE_VAULT_PASSWORD_FILE.
24        # It checks if the environment variable PX_ANSIBLE_VAULT_PASSWORD is set.
25        # If set, it echoes the value (returns it).
26        # If not set, it outputs an error to stderr and exits with status 1.
27        # Use the set_vault_password function in your shell (e.g., from .bash_aliases.sh)
28        # to set the variable before running ansible-playbook.
29
30        if [ -z "${PX_ANSIBLE_VAULT_PASSWORD}" ]; then
31            echo "Error: PX_ANSIBLE_VAULT_PASSWORD is not set. Please set it using 'set_vault_password' in your shell session." >&2
32            exit 1
33        fi
34
35        echo "${PX_ANSIBLE_VAULT_PASSWORD}"        
36      mode: "0755"

The how-to Set Up Ansible with Kerberos on a PHX Development Desktop simulates how an Ansible desktop is used within the PHX domain. It incorporates Kerberos and Ansible Vault in a secure manner using environment variables.

In the how-to, domain user “Tony” adds a bash function phx-vault-password to his ~/.bash_aliases and exports ANSIBLE_VAULT_PASSWORD_FILE. This setup allows Tony to access the Ansible Vault securely on the desktop pxd-ubuntu-devtop without Vagrant. It demonstrates how to do this in an air-gapped PHX domain by keeping the password in memory only, avoiding storage in plain files:

function phx-vault-password() {
    local password
    echo -n "Enter Ansible Vault passphrase: " >&2
    read -s password
    echo >&2  # Add a newline after the hidden input
    export PX_ANSIBLE_VAULT_PASSWORD="$password"
    echo "PX_ANSIBLE_VAULT_PASSWORD has been set for this shell session." >&2
}
export ANSIBLE_VAULT_PASSWORD_FILE="/usr/local/bin/vault-client.sh"

With this approach, a user can set the password in their shell session using:

phx-vault-password

And then view the vault with passphrase prompts using:

ansible-vault view secret_vars/development/main.yml
(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ phx-vault-password
Enter Ansible Vault passphrase:
PX_ANSIBLE_VAULT_PASSWORD has been set for this shell session.
(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ alias phx-vault
alias phx-vault='ansible-vault edit secret_vars/development/main.yml'
(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ phx-vault
(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ ansible-vault view secret_vars/development/main.yml
---
# ad
px_ad_admin_password: Supersecret!

# cacerts_server
px_cacerts2_ca_domain_passphrase: huhohleSh8Beis9

# vagrant ssh
px_vagrant_ssh_id_rsa: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn

If phx-vault-password is not used (and so PX_ANSIBLE_VAULT_PASSWORD is not set), this will result in an error:

(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ ansible-playbook plays/mgmt/ad.yml
[WARNING]: Error in vault password file loading (default): Vault password
client script /usr/local/bin/vault-client.sh returned non-zero (1) when getting
secret for vault-id=default: b"Error: PX_ANSIBLE_VAULT_PASSWORD is not set.
Please set it using 'set_vault_password' in your shell session.\n"
ERROR! Vault password client script /usr/local/bin/vault-client.sh returned non-zero (1) when getting secret for vault-id=default: b"Error: PX_ANSIBLE_VAULT_PASSWORD is not set. Please set it using 'set_vault_password' in your shell session.\n"
(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$

Note that if ANSIBLE_VAULT_PASSWORD_FILE is not set, this will result in a message:

(pxd) tony@pxd-ubuntu-devtop:~/git/gitlab/c2/ansible-phx$ ansible-playbook plays/mgmt/ad.yml | tee provision.log
[WARNING]: Error getting vault password file (default): The vault password file
/home/tony@c2.org/git/gitlab/c2/ansible-phx/vpass was not found
ERROR! The vault password file /home/tony@c2.org/git/gitlab/c2/ansible-phx/vpass was not found

This is because in the PHX Ansible inventory project c2platform/phx/ansible in ansible.cfg, there is a line with vault_password_file:

ansible.cfg

vault_password_file=vpass

In inventory projects consumed by Ansible Automation Platform ( AAP ) , this setting is typically not made. But in the open-source PHX development environment, which uses Vagrant, this file vpass is created by Vagrant as you can see in the Vagrantfile. As this is only an Ansible development environment, security is not a major concern; everything is open source, so the vault password is secret.

Vagrantfile

231# vpass file for Ansible vault secrets.yml
232vpass_file = File.join(File.dirname(__FILE__), 'vpass')
233File.open(vpass_file, 'w') { |f| f.write('secret') } unless File.exist? vpass_file

Additional Information


  1. This is acceptable but not ideal for highly sensitive environments. If someone compromises your session (e.g., via malware), they could dump env vars. For production/automation, consider integrating with a secret manager like HashiCorp Vault, AWS Secrets Manager, or pass instead of manual input ↩︎