The intersection of configuration management and secure credential storage is a critical juncture for any DevOps pipeline. Integrating KeePass—a robust, open-source password manager—into Ansible allows engineers to transition away from insecure plain-text files or overly rigid vault structures toward a dynamic, database-driven secret retrieval system. This integration is primarily achieved through specialized plugins and lookup modules, most notably the viczem.keepass.keepass collection and the ansible-keepass inventory plugin. By leveraging these tools, organizations can maintain a single source of truth for credentials in a .kdbx file while utilizing Ansible's orchestration capabilities to inject those secrets into playbooks at runtime. This architectural approach ensures that sensitive data remains encrypted at rest and is only decrypted in memory during the execution of a specific task, significantly reducing the attack surface of the management node.
The Ansible-KeePass Inventory Plugin Architecture
The ansible-keepass inventory plugin transforms a KeePass database file directly into an Ansible inventory. This allows the structure of the database—its groups and entries—to define the topology of the infrastructure being managed.
Group and Host Mapping Logic
The plugin implements a specific logic for translating KeePass entries into Ansible entities. Any entry within the database that begins with a colon (:) is interpreted as a variable. The text following the colon serves as the variable name. Because these entries are treated as containers, all associated notes or string fields are nested under that variable, effectively making the variable a dictionary.
The handling of group inheritance is a critical technical detail. While the KeePass database utilizes a single inheritance hierarchy, Ansible's inventory system allows hosts and groups to be children of multiple parent groups. To resolve this discrepancy, the plugin treats all groups with identical names across the database as a single, unified group in the Ansible inventory.
For example, consider the following database structure:
- Group Aa
- Group Bb
- Group Cc
- Group Dd
- Group Bb (Duplicate name)
- Group Ee
- Group Bb (Duplicate name)
- Group Ff
- Group Bb (Duplicate name)
In the resulting Ansible inventory, there is only one "Bb" group. This group will have "Aa" and "Ee" as parents, and "Cc" and "Ff" as children. This creates a dense web of associations that allows for complex variable inheritance. However, this introduces a risk: if two identically named groups contain hosts or variables with the same name, the "winner" is undefined. Therefore, users must ensure that host and variable names remain unique across all groups sharing the same name to prevent non-deterministic behavior in playbook execution.
Authentication and Password Retrieval
The plugin employs a tiered strategy for accessing the encrypted .kdbx file, prioritizing flexibility for different environments (local vs. CI/CD).
- Environment Variables: The plugin first checks for
KEEPASS_PWorRD_OPTION_KEEPASS_PW(the latter specifically designed for Rundeck integrations). - Vault Passwords: If no environment variables are found, it attempts to use the "default" vault ID password.
- Configuration: The list of environment variables to be attempted is configurable via the "auto" inventory plugin's YAML configuration file.
Users can provide the vault password during execution using the following commands:
- Using a prompt: ansible -i kp_file.kdbx --ask-vault-pass all -list
- Using a password file: ansible -i kp_file.kdbx --vault-password-file a_file all --list
Alternatively, utilizing environment variables:
export KEEPASS_PW=foobar
ansible -i kp_file.kdbx all --list-hosts
Database Configuration via YAML
A sophisticated feature of the plugin is the ability to embed configuration directly within the KeePass database. If the "Description" field in the Database settings begins with the three-dash YAML marker (---), the plugin parses this field as a YAML configuration block to load specific plugin options. This allows the database to carry its own operational parameters, ensuring that any administrator who opens the database with the correct password also possesses the configuration required to use it with Ansible.
Implementing the viczem.keepass Lookup Module
For users who do not need their entire inventory to be derived from KeePass, the viczem.keepass.keepass lookup plugin provides a more granular approach. This allows the developer to pull specific secrets into a playbook on an as-needed basis.
Integration and Setup
To utilize this functionality, the viczem.keepass.keepass module must be installed. A typical setup involves creating a virtual environment to isolate dependencies:
cd /path/to/til/ansible
python3 -m venv venv
source venv/bin/activate
To securely handle the KeePass password, it is recommended to use ansible-vault to encrypt the password string rather than storing it in plain text. The process for generating an encrypted password string is as follows:
read -s -p "Enter Keepasswd: " KEEPASS_PASSWD
export KEEPASS_PASSWD
ansible-vault encrypt_string --encrypt-vault-id inline "$KEEPASS_PASSWD" --name 'keepass_psw'
The resulting encrypted string (starting with keepass_psw: !vault |) should be placed in a secure variables file, such as securevars/host_vars/localhost.yml.
Data Retrieval Patterns
The lookup plugin supports various types of data extraction from the database. The syntax follows a pattern of lookup('viczem.keepass.keepass', 'path/to/entry', 'field').
| Data Type | Lookup Syntax Example | Purpose |
|---|---|---|
| Username | {{ lookup('viczem.keepass.keepass', 'path/to/entry', 'username') }} |
Retrieves the primary username field. |
| Password | {{ lookup('viczem.keepass.keepass', 'path/to/entry', 'password') }} |
Retrieves the primary password field. |
| Custom Field | {{ lookup('viczem.keepass.keepass', 'path/to/entry', 'custom_properties', 'field_name') }} |
Accesses user-defined properties. |
| Attachment | {{ lookup('viczem.keepass.keepass', 'path/to/entry', 'attachments', 'file_name') }} |
Retrieves attached files. |
Advanced Attachment Handling
Beyond simple lookups, the viczem.keepass.attachment module allows for the physical export of files stored within the KeePass database to the target filesystem. This is critical for deploying SSL certificates or SSH keys stored as attachments.
Example implementation:
- name: "Export file: attachment.txt"
viczem.keepass.attachment:
database: "{{ keepass_dbx }}"
password: "{{ keepass_psw }}"
entrypath: example/attachments
attachment: "attachment.txt"
dest: "{{ keepass_attachment_1_name }}"
Operationalizing Secrets in Production and CI/CD
Deploying KeePass-integrated Ansible in a production or Continuous Integration (CI) environment requires a shift from interactive passwords to automated socket-based or environment-based authentication.
Environment Variable Overrides
In CI environments, using Ansible variables for the database password can be cumbersome. The plugin supports a set of specific environment variables that take precedence if corresponding Ansible variables are not set:
ANSIBLE_KEEPASS_PSW: The password for the database.ANSIBLE_KEEPASS_KEY: Path to the keyfile.ANSIBLE_KEEPASS_TTL: The Socket Time-To-Live (TTL).ANSIBLE_KEEPASS_SOCKET: The path to the KeePass socket.
The Socket-Based Execution Model
To optimize performance and security, the KeePass socket can be started as a background process. This prevents the overhead of reopening and decrypting the database for every single lookup during a long-running playbook.
Implementation flow for a CI job:
export ANSIBLE_KEEPASS_PSW=mySecret
export ANSIBLE_KEEPASS_SOCKET=/home/build/.my-ansible-sock.${CI_JOB_ID}
export ANSIBLE_TTL=600
/home/build/ansible-pyenv/bin/python3 /home/build/.ansible/roles/ansible_collections/viczem/keepass/plugins/lookup/keepass.py /path-to/my-keepass.kdbx &
ansible-playbook -v playbook1.yml
This method ensures that the database is decrypted once and held in a secure socket for the duration of the job (in this example, 10 minutes), providing a significant speed increase while keeping the password out of the playbook logs.
Configuration Parameters and Tuning
The interaction between Ansible and KeePass is governed by several key parameters that dictate how the database is accessed and how long sessions remain active.
Technical Parameter Specifications
| Parameter | Type | Description | Default/Requirement |
|---|---|---|---|
keepass_dbx |
String | Path to the .kdbx database file. |
Required |
keepass_psw |
String | Password for the database. | Required (if keepass_key is absent) |
keepass_key |
String | Path to the keyfile. | Optional (Required if keepass_psw is absent) |
keepass_ttl |
Integer | Socket TTL in seconds; closes automatically when idle. | 60 seconds |
Integration with Host Variables
A common pattern for organizing these secrets is to define the database path and encrypted password within a dedicated host variable file.
Example file: securevars/host_vars/localhost.yml
keepass_ttl: 30
keepass_dbx: "securevars/files/AnsibleTil.kdbx"
keepass_psw: !vault |
$ANSIBLE_VAULT;1.2;AES256;inline
12345....
By using ansible.builtin.include_vars within a task, the playbook can load these settings before attempting any lookups. For example, a task sequence might include:
- name: get vars
ansible.builtin.include_vars: host_vars/localhost.yaml
no_log: True
The no_log: True attribute is mandatory here to prevent the decrypted password from appearing in the Ansible output.
Conclusion: Analysis of the KeePass-Ansible Ecosystem
The integration of KeePass into Ansible represents a sophisticated compromise between the need for centralized, encrypted secret storage and the requirement for automated deployment. By utilizing the viczem.keepass lookup and the ansible-keepass inventory plugin, users move away from "secret sprawl," where passwords are scattered across multiple group_vars files. Instead, they establish a centralized database that is independently manageable via standard KeePass clients.
The technical robustness of this approach is evidenced by the support for socket-based communication and environment variable overrides, which are essential for modern CI/CD pipelines. The ability to map database groups to Ansible groups—despite the differences in inheritance models—demonstrates a deep understanding of Ansible's internal inventory logic. However, the "undefined" behavior regarding duplicate host/variable names in identically named groups remains a critical caution for architects.
Ultimately, the security of this system relies on the protection of the keepass_psw. The shift toward using ansible-vault to encrypt the KeePass password itself creates a layered security model: the vault protects the key to the database, and the database protects the secrets of the infrastructure. This "double-wrap" strategy ensures that even if the filesystem is compromised, the attacker must break both the Ansible Vault encryption and the KeePass AES-256 encryption to access the actual credentials.