03_policies.ymlΒΆ

---
- name: "πŸ—„ Ensure the KV v2 secrets engine is mounted at '{{ OPENBAO_KV_MOUNT }}'"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container exec {{ OPENBAO_LOCAL_CID | quote }}
    sh -c 'bao secrets list -format=json | grep -q "\"{{ OPENBAO_KV_MOUNT }}/\"" ||
    { bao secrets enable -path={{ OPENBAO_KV_MOUNT | quote }} -version=2 kv && echo OPENBAO_CHANGED; }'
  register: openbao_kv_mount
  changed_when: "'OPENBAO_CHANGED' in openbao_kv_mount.stdout"

- name: "πŸ“œ Write the human RBAC policies"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container exec {{ OPENBAO_LOCAL_CID | quote }}
    sh -c 'set -e; before=$(bao policy read {{ item | quote }} 2>/dev/null || true);
    bao policy write {{ item | quote }} {{ OPENBAO_POLICY_DIR_DOCKER }}/{{ item }}.hcl >/dev/null;
    after=$(bao policy read {{ item | quote }});
    [ "$before" = "$after" ] || echo OPENBAO_CHANGED'
  loop: "{{ OPENBAO_RBAC_ROLES }}"
  register: openbao_policy_write
  changed_when: "'OPENBAO_CHANGED' in openbao_policy_write.stdout"

- name: "πŸ“œ Refresh the ansible-admin policy"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container exec {{ OPENBAO_LOCAL_CID | quote }}
    sh -c 'set -e; before=$(bao policy read ansible-admin 2>/dev/null || true);
    bao policy write ansible-admin {{ OPENBAO_POLICY_DIR_DOCKER }}/ansible-admin.hcl >/dev/null;
    after=$(bao policy read ansible-admin);
    [ "$before" = "$after" ] || echo OPENBAO_CHANGED'
  register: openbao_admin_policy_write
  changed_when: "'OPENBAO_CHANGED' in openbao_admin_policy_write.stdout"

- name: "πŸ“ Fail unless the declared stdout audit device is active"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container exec {{ OPENBAO_LOCAL_CID | quote }}
    bao audit list -format=json
  register: openbao_audit_devices
  changed_when: false
  failed_when: >-
    openbao_audit_devices.rc != 0
    or (openbao_audit_devices.stdout | from_json).get(OPENBAO_AUDIT_PATH ~ '/', {}).get('type') != 'file'

- name: "πŸ”Ž Read the audit probe secret through the AppRole session"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container exec {{ OPENBAO_LOCAL_CID | quote }}
    sh -c 'bao kv get -mount={{ OPENBAO_KV_MOUNT | quote }} -field=value {{ OPENBAO_AUDIT_PROBE | quote }} 2>/dev/null ||
    { bao kv put -mount={{ OPENBAO_KV_MOUNT | quote }} {{ OPENBAO_AUDIT_PROBE | quote }} value="probe-$(date +%s)-$$" >/dev/null &&
    bao kv get -mount={{ OPENBAO_KV_MOUNT | quote }} -field=value {{ OPENBAO_AUDIT_PROBE | quote }}; }'
  register: openbao_audit_probe
  changed_when: false

- name: "🧾 Fail unless the audit log recorded the probe read with identity and time"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container logs --since 10m {{ OPENBAO_LOCAL_CID | quote }} 2>&1
    | grep -F '"type":"response"'
    | grep -F '"path":"{{ OPENBAO_KV_MOUNT }}/data/{{ OPENBAO_AUDIT_PROBE }}"'
    | grep -F '"operation":"read"'
    | grep -F '"display_name":'
    | grep -cF '"time":'
  register: openbao_audit_entries
  changed_when: false
  failed_when: openbao_audit_entries.stdout | trim | int < 1

- name: "πŸ™ˆ Fail if the audit log holds the probe secret in plaintext"
  ansible.builtin.shell: > # nocheck: container-exec-resolver  runtime-resolved CID, delegated to the hosting node
    container logs --since 10m {{ OPENBAO_LOCAL_CID | quote }} 2>&1
    | grep -cF {{ openbao_audit_probe.stdout | trim | quote }}
  register: openbao_audit_leak
  changed_when: false
  failed_when: openbao_audit_leak.stdout | trim | int > 0