eigenstate-ipa

IdM Vault Plugin

Related docs:

  IDM VAULT CAPABILITIES     INVENTORY PLUGIN     AAP INTEGRATION     DOCS MAP  

Purpose

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.

Contents

Retrieval Model

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.

Authentication Model

The lookup always operates with a Kerberos credential cache.

It can get there in three ways:

[!IMPORTANT] The lookup plugin is more sensitive to missing local dependencies than the inventory plugin. It requires python3-ipalib and python3-ipaclient, and often also krb5-workstation when a ticket must be acquired dynamically. When local secret material is read from kerberos_keytab, vault_password_file, or private_key_file, the plugin now warns if the file permissions are broader than 0600.

TLS behavior:

That keeps the vault plugin aligned with the inventory plugin while still respecting ipalib’s own controller-side defaults.

Ownership Scope

Select exactly one vault scope:

If none is selected, the plugin uses the default scope behavior of the IdM API for the authenticated principal.

In practice:

Operations

The lookup supports three operations:

retrieve and show expect one or more vault names. find uses the selected scope and an optional criteria string.

Vault Types

Standard Vaults

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.

Symmetric Vaults

These require one of:

The 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.

Asymmetric Vaults

These require:

The 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.

Return Encoding

The lookup returns one list element per requested vault name.

Encoding modes:

If you need a file on disk from binary content, use encoding='base64' and decode it in the consuming task.

Return Shapes And Normalization

If you need a structured result instead of a plain value, use result_format: record. Each lookup result then becomes a dictionary with:

That is the safer shape when the caller needs to keep track of which vault each payload came from.

Additional container shapes are also available:

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':

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:

That 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.

Brokered Artifact Delivery

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.

Minimal Examples

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') }}"

Failure Boundaries

Common failure classes are:

[!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, and shared first.

When To Read The Scenario Guide

Use IDM VAULT CAPABILITIES when you need operator patterns rather than option-by-option reference: