3.7 KiB

role_include_vault-check

An include-only Ansible role to check if HashiCorp Vault variables truly exist

Import

Whenever you work with HashiCorp Vault data stored in a kv secrets engine you may want to import this role into whatever playbook you're running.

Given a role directory create a meta subdirectory underneath it with a file named requirements.yml.

role
├── meta                   <--- Create this
│   └── requirements.yml   <--- Create this
└── tasks
    └── main.yml

In requirements.yml add:

- src: "https://quico.space/quico-ansible/role_include_vault-check.git"
  version: "master"

Now whenver you import role for example via ansible-galaxy install ... you'll automatically get this one downloaded as well. You can optionally leave out version: "master" since this is the default version anyways, meaning the role_include_vault-check newest master commit. The version: attribute helps you pin a version, for example as version: "v1.0.0" which will instead pull role_include_vault-check Git tag v1.0.0. Side note, this role follows the Semantic Versioning standard. A Git tag name v1.0.0 refers to Semantic Version 1.0.0.

Use it

Generic setup

From your role call this one like so:

- name: "If a secret is missing: Fail progress"
  import_role:
    name: "role_include_vault-check"
  vars:
    - vault_check_base_path: "{{ vault_check_base_path }}"
    - vault_check_inc_vault_data: "{{ vault_check_vault_data }}"
    - vault_check_fail_check:
      - "password"
      - "password_salt"

This role_include_vault-check expects two variables in your import_role task for example via the vars statement:

  1. vault_check_base_path: The path in HashiCorp Vault's kv secrets engine where secrets are located. Has cosmetic purpose only to inform the user where a key-value check succeeded or failed.

  2. vault_check_fail_check: A list of keys located at vault_check_base_path for which you want to confirm that they are non-empty.

    Can either be defined in place like so:

    - vault_check_fail_check:
      - "password"
      - "password_salt"
    

    Or can use a list variable defined elsewhere:

    - vault_check_fail_check: "{{ some_list }}"
    

In context

In a real-world use case you'll likely first query HashiCorp Vault for key-value pairs for example like so:

- name: "Get secrets"
  no_log: "true"
  loop_control:
    loop_var: "server"
  with_community.hashi_vault.vault_kv2_get:
    - "some/vault/kv/path/password"
    - "some/vault/kv/path/password_salt"
  ansible.builtin.set_fact:
    vault_data: "{{ vault_data | default({}) | combine (server.secret) }}"

The vault_kv2_get lookup plug-in (see vault_kv2_get lookup documentation) iterates over variables you want loaded from Vault. For each iteration it stores the iteration's output in loop_var: "server". From that output we only really care about the server.secret dictionary. We append that to a vault_data dictionary which is first initialized as an empty dictionary and then expanded per iteration. When done vault_data contains key-values pair for all Vault variables.

The next step can be this role_include_vault-check to hard-fail in case a key turned out to have an empty value.

- name: "If a secret is missing: Fail progress"
  import_role:
    name: "role_include_vault-check"
  vars:
    - vault_check_base_path: "{{ vault_check_base_path }}"
    - vault_check_inc_vault_data: "{{ vault_data }}"
    - vault_check_fail_check:
      - "password"
      - "password_salt"

Output