Related docs:
IDM VAULT CAPABILITIES INVENTORY PLUGIN AAP INTEGRATION DOCS MAP
eigenstate.ipa.vault retrieves, inspects, and searches IdM vaults from
Ansible.
This reference covers:
The principal does not need to be a global IdM administrator. It only needs the rights required to retrieve the specific vaults in its jurisdiction.
flowchart LR
ans["Ansible task or template"]
lookup["eigenstate.ipa.vault"]
krb["Kerberos ticket\nexisting, password-derived,\nor keytab-derived"]
ipa["ipalib vault APIs"]
vaults["IdM vaults\nuser, service, shared"]
out["Lookup return value\nutf-8 or base64"]
ans --> lookup
lookup --> krb
krb --> ipa
ipa --> vaults
vaults --> out
The lookup uses the IdM Python client libraries directly through ipalib.
Vault retrieval is not just a REST fetch. The client stack also handles the
transport and vault-specific decryption workflow expected by IdM.
The lookup always operates with a Kerberos credential cache.
It can get there in three ways:
ipaadmin_password:
kerberos_keytab:
[!IMPORTANT] The lookup plugin is more sensitive to missing local dependencies than the inventory plugin. It requires
python3-ipalibandpython3-ipaclient, and often alsokrb5-workstationwhen a ticket must be acquired dynamically. When local secret material is read fromkerberos_keytab,vault_password_file, orprivate_key_file, the plugin now warns if the file permissions are broader than0600.
TLS behavior:
verify: /path/to/ca.crt enables explicit certificate verificationverify first tries /etc/ipa/ca.crtipalibThat keeps the vault plugin aligned with the inventory plugin while still
respecting ipalib’s own controller-side defaults.
Select exactly one vault scope:
usernameserviceshared: trueIf none is selected, the plugin uses the default scope behavior of the IdM API for the authenticated principal.
In practice:
shared: true for estate-wide automation secretsservice when a service principal owns the vaultusername for principal-scoped private vaultsThe lookup supports three operations:
retrieve:
show:
find:
retrieve and show expect one or more vault names. find uses the selected
scope and an optional criteria string.
These require no additional decryption parameters.
Use them when the secret should be retrievable directly once the principal is authorized.
If the lookup can read vault metadata first, it now rejects symmetric or asymmetric decryption inputs early for standard vaults.
These require one of:
vault_passwordvault_password_fileThe lookup reads the symmetric password and passes it to the IdM vault retrieve operation.
If the lookup can inspect the vault metadata first, it now fails early when a
symmetric vault is missing the symmetric password input or when the caller
incorrectly supplies private_key_file.
These require:
private_key_fileThe private key is read locally and passed into the IdM vault retrieve operation.
If the lookup can inspect the vault metadata first, it now fails early when an
asymmetric vault is missing private_key_file or when the caller incorrectly
supplies symmetric vault password inputs.
The lookup returns one list element per requested vault name.
Encoding modes:
utf-8:
base64:
If you need a file on disk from binary content, use encoding='base64' and
decode it in the consuming task.
If you need a structured result instead of a plain value, use
result_format: record. Each lookup result then becomes a dictionary with:
namescopeencodingvalueThat is the safer shape when the caller needs to keep track of which vault each payload came from.
Additional container shapes are also available:
result_format: map
{vault_name: value}result_format: map_record
{vault_name: {name, scope, encoding, value}}The mapping forms are useful when several vaults are retrieved in one call and the playbook should not depend on positional list ordering.
Two text-only helpers are also available for operation='retrieve':
decode_json: true
strip_trailing_newline: true
These helpers are intentionally limited to retrieved text payloads. They do not
apply to show, find, or encoding='base64'.
If you need payload plus vault context in one retrieve call, set
include_metadata: true with result_format: record or
result_format: map_record. Retrieved records then also include:
typedescriptionvault_idThat is useful when the lookup is brokering an opaque artifact to another system and the playbook should make routing decisions from vault metadata rather than from hard-coded assumptions.
For the recommended metadata convention and the full brokered handoff pattern, see the vault capabilities and use-case guides.
The lookup is still a retrieval tool, not an unsealing controller. The useful extension here is that it can now return broker-friendly records that contain both:
That is the right shape for encrypted or sealed artifacts that should move through Ansible unchanged and only be consumed or unwrapped by a downstream system.
Shared standard vault:
- ansible.builtin.debug:
msg: "{{ lookup('eigenstate.ipa.vault',
'database-password',
server='idm-01.example.com',
ipaadmin_password=lookup('env', 'IPA_ADMIN_PASSWORD'),
shared=true,
verify='/etc/ipa/ca.crt') }}"
Symmetric vault:
- ansible.builtin.set_fact:
api_key: "{{ lookup('eigenstate.ipa.vault',
'api-key',
server='idm-01.example.com',
kerberos_keytab='/runner/env/ipa/admin.keytab',
shared=true,
vault_password_file='/runner/env/ipa/vault.pass',
verify='/etc/ipa/ca.crt') }}"
Binary secret:
- ansible.builtin.copy:
content: "{{ lookup('eigenstate.ipa.vault',
'service-keytab',
server='idm-01.example.com',
ipaadmin_password=lookup('env', 'IPA_ADMIN_PASSWORD'),
shared=true,
encoding='base64') | b64decode }}"
dest: /etc/krb5.keytab
mode: "0600"
Structured JSON secret:
- ansible.builtin.set_fact:
app_config: "{{ lookup('eigenstate.ipa.vault',
'app-config',
server='idm-01.example.com',
kerberos_keytab='/runner/env/ipa/team-svc.keytab',
shared=true,
decode_json=true,
verify='/etc/ipa/ca.crt') }}"
Inspect metadata without retrieving the payload:
- ansible.builtin.set_fact:
vault_info: "{{ lookup('eigenstate.ipa.vault',
'database-password',
server='idm-01.example.com',
kerberos_keytab='/runner/env/ipa/team-svc.keytab',
shared=true,
operation='show',
result_format='record',
verify='/etc/ipa/ca.crt') }}"
Find vaults and return a named metadata map:
- ansible.builtin.set_fact:
matching_vaults: "{{ lookup('eigenstate.ipa.vault',
server='idm-01.example.com',
kerberos_keytab='/runner/env/ipa/team-svc.keytab',
shared=true,
operation='find',
criteria='database',
result_format='map_record',
verify='/etc/ipa/ca.crt') }}"
Broker an encrypted artifact to a downstream system:
- ansible.builtin.set_fact:
sealed_bundle: "{{ lookup('eigenstate.ipa.vault',
'payments-bootstrap-bundle',
server='idm-01.example.com',
kerberos_keytab='/runner/env/ipa/team-svc.keytab',
shared=true,
encoding='base64',
result_format='record',
include_metadata=true,
verify='/etc/ipa/ca.crt') }}"
Common failure classes are:
ipalib libraries on the controller or EE[!NOTE] An IdM vault lookup failure is often an ownership-scope mismatch rather than a missing object. If a vault is present in IdM but the lookup says not found, recheck
username,service, andsharedfirst.
Use IDM VAULT CAPABILITIES when you need operator patterns rather than option-by-option reference: