For local playbooks using vaults, I tend to store the vault password in keepassxc. You can use the following method to retrieve the vault password directly from ansible
In ~/bin/get_keepass_password.py
: add the script to get the password from keepassxc:
from pathlib import Path
class IncorrectPassword(Exception):
pass
def get_keepass_password(keepass_database_path: Path, keepass_entry_name: str):
import os
# ---
# KEEPASS PASSWORD
try:
keepass_password = os.environ['KEEPASS_PASSWORD']
password_provided_by_environment = True
except KeyError:
keepass_password = input(f'Keepass password for file {keepass_database_path.name}: ')
print('To keep password in cache, use the following (prefixed with a password to avoid storing it in bash history)')
print(f' export KEEPASS_PASSWORD="{keepass_password}"')
password_provided_by_environment = False
# ---
# Make sure database exist
if not keepass_database_path.exists():
raise ValueError(f"{keepass_database_path.name} doesn't exist, absolute path: {keepass_database_path}")
# ---
# Retrieve password from keepass database
import subprocess
echo_process = subprocess.Popen(['echo', '-n', keepass_password], stdout = subprocess.PIPE, text = True)
command = ['keepassxc-cli', 'show', '--quiet' , str(keepass_database_path), keepass_entry_name, '-a', 'Password']
keepass_cli_process = subprocess.Popen(command, stdin = echo_process.stdout, stdout = subprocess.PIPE, text = True)
output, error = keepass_cli_process.communicate()
password = output.strip()
# ---
# Handle incorrect password
if password == '':
error_message = f'/!\ WARNING: Incorrect password for keepass database `{keepass_database_path.name}`'
if password_provided_by_environment:
error_message += '\nPassword was provided through environment variable, use `unset KEEPASS_PASSWORD`'
raise IncorrectPassword(error_message)
return password
In ~/bin/get_ansible_vault_password_from_keepass.py
, add the script to get the password from keepassxc for a specific vault :
from pathlib import Path
from get_keepass_password import get_keepass_password, IncorrectPassword
def get_ansible_vault_password_from_keepass(ansible_vault_path: str, keepass_database_path: str):
# Use vault file name as keepass entry
keepass_entry_name = Path(ansible_vault_path)
while keepass_entry_name.suffix in {'.yml', '.yaml', '.vault'}:
keepass_entry_name = keepass_entry_name.with_suffix('')
keepass_entry_name = keepass_entry_name.name
keepass_entry_name = f'{keepass_entry_name}-ansible-vault'
# Expand ~ if needed
ansible_vault_path = Path(ansible_vault_path).expanduser()
keepass_database_path = Path(keepass_database_path).expanduser()
try:
vault_password = get_keepass_password(keepass_database_path, keepass_entry_name)
return vault_password
except IncorrectPassword as error:
raise IncorrectPassword(error)
def get_ansible_vault_password_from_keepass_for_ansible(ansible_vault_path: str, keepass_database_path: str):
import sys
from contextlib import redirect_stdout
try:
with redirect_stdout(sys.stderr):
# Because ansible vault_file_script use stdout as the vault password, only stderr is displayed
# So we redirect stdout (from print or echo statements) to stderr to display them
vault_password = get_ansible_vault_password_from_keepass(ansible_vault_path, keepass_database_path)
print(vault_password) # Prints to stdout to be consummed by ansible
except IncorrectPassword as error:
exit(error)
In the file get_vault_password.py
, next to your vault, add the following script, specifying <vault_file>
and <keepass_file>
:
#! /usr/bin/env python
# ---
# Import standard modules
import os, sys
from pathlib import Path
# ---
# Configure files path
SCRIPT_DIR = os.path.realpath(__file__)
vault_file = Path(SCRIPT_DIR, '<vault_file>')
keepass_database_path = "<keepass_file>" # The custom module supports expanduser
custom_module_folder = str(Path('~/bin').expanduser())
# ---
# Get password through custom module
sys.path.append(custom_module_folder)
from get_ansible_vault_password_from_keepass import get_ansible_vault_password_from_keepass_for_ansible
vault_password = get_ansible_vault_password_from_keepass_for_ansible(vault_file, keepass_database_path)
Change the permission to allow executing this script: chmod u+x ./inventory/vaults/get-vault-password.py
In ansible.cfg
, set:
vault_password_file = ./inventory/vaults/get-vault-password.py