Configure declarative audit devices

Use this how-to to configure OpenBao audit devices from server configuration. This profile gives you repeatable audit devices for HA OpenBao deployments and keeps audit changes under normal configuration review.

Before you begin

  • Run OpenBao outside development mode.
  • Get access to the OpenBao server configuration for every node.
  • Choose the audit storage path and retention policy with your security team.
  • Confirm that the OpenBao process can write to the audit path.
  • Confirm that your log collector can read the audit path without broadening access to other OpenBao files.

[!WARNING] Audit logs are security evidence. Do not configure log_raw = "true" for this reference profile. Raw audit logging can expose sensitive values that OpenBao normally HMACs.

Choose the audit profile

ProfileUse whenAudit deviceCollector pathCaveat
Local demoYou run the Docker Compose stack or a disposable test cluster.File audit device on local storage or stdout.Alloy or container logs.Not a compliance archive.
Kubernetes baselineYou run OpenBao on Kubernetes and need a repeatable audit stream.File audit device on a mounted audit volume.Restricted Alloy file tail or security collector.Requires PVC, file permission, and retention planning.
Production KubernetesYou need audit resilience and separate retention.At least two audit devices, usually local file plus an independent path.Restricted collector plus archive or SIEM path.Test blocking and sink-failure behavior before rollout.
VM/systemdYou run OpenBao on hosts.File audit device under /var/log/openbao.Alloy file source, journald-adjacent collector, or security shipper.Configure log rotation and send SIGHUP after rotation.

Use declarative audit configuration as the baseline. OpenBao creates and removes declarative audit devices on the active node during restart and SIGHUP handling, and the same configuration should exist on every server.

Configure a file audit device

  1. Add a file audit stanza to each OpenBao server configuration.

    audit "file" "audit-file" {
      description = "Baseline audit file."
    
      options {
        file_path     = "/openbao/audit/audit.log"
        mode          = "0600"
        format        = "json"
        hmac_accessor = "true"
        log_raw       = "false"
      }
    }
    
  2. Use the same audit path and stanza name on every OpenBao server.

  3. Mount the audit path on dedicated storage when the deployment runs on Kubernetes.

  4. Restrict file permissions so the OpenBao process can write the file and only the approved collector can read it.

  5. Reload or restart OpenBao through your normal change process.

Configure production redundancy

  1. Keep a local file audit device as the primary path.

    audit "file" "primary-file" {
      description = "Primary local audit file."
    
      options {
        file_path     = "/openbao/audit/audit.log"
        mode          = "0600"
        format        = "json"
        hmac_accessor = "true"
        log_raw       = "false"
      }
    }
    
  2. Add a second audit path only after you test its failure behavior.

    audit "file" "secondary-stdout" {
      description = "Secondary audit stream for independent collection."
    
      options {
        file_path     = "stdout"
        format        = "json"
        hmac_accessor = "true"
        log_raw       = "false"
      }
    }
    
  3. Send one audit stream to a restricted exploration backend, such as Loki.

  4. Send the production archive stream to your approved SIEM, object store, or immutable archive path.

Loki is useful for short-term exploration and dashboard correlation. Do not treat Loki as the compliance archive unless your organization has explicitly approved that design.

Collect audit logs

  1. Configure the collector to read only the audit file path.

  2. Label the stream as log_stream="openbao.audit".

  3. Keep request identifiers, paths, entity IDs, token accessors, policies, and client addresses out of Loki labels. Parse those fields at query time.

  4. Restrict the Grafana folder, Loki tenant, or equivalent backend access for audit dashboards.

  5. Keep a separate archive path for long-term retention when your compliance requirements need it.

The Docker Compose stack in this repository demonstrates this pattern by writing audit JSON lines to each OpenBao node and tailing them with Alloy under the openbao.audit log stream.

Configure an audit canary

  1. Create a non-sensitive canary secret.

    bao kv put secret/observability/audit-canary status=ok purpose=audit-canary
    
  2. Create a canary policy that can read only the canary path.

    path "secret/data/observability/audit-canary" {
      capabilities = ["read"]
    }
    
  3. Create a token for the canary scheduler with only the canary policy.

    bao token create -policy=audit-canary -no-default-policy
    
  4. Run the canary request on a schedule that is shorter than the alert window.

    BAO_TOKEN=<audit_canary_token> bao read secret/data/observability/audit-canary
    
  5. Alert on the absence of that specific audited path instead of treating every quiet audit stream as a critical incident.

    absent_over_time({log_stream="openbao.audit"} | json request_path="request.path" | request_path="secret/data/observability/audit-canary" [15m])
    

Configure log rotation on hosts

  1. Rotate file audit logs with your host log-rotation tool.

  2. Send SIGHUP to OpenBao after each rotation so OpenBao closes and reopens the file.

    /var/log/openbao/audit.log {
      rotate 30
      daily
      missingok
      notifempty
      compress
      create 0600 openbao openbao
      postrotate
        /bin/kill -HUP $(cat /run/openbao/openbao.pid)
      endscript
    }
    
  3. Confirm that the collector follows the rotated file behavior you use.

Verify the result

  1. List audit devices.

    bao audit list -detailed -address=<openbao_address>
    
  2. Confirm that the expected file audit device exists.

  3. Run a permitted request against an approved audited path.

    bao read -address=<openbao_address> <approved_audited_path>
    
  4. Confirm that the audit file receives request and response entries.

    stat /openbao/audit/audit.log
    
  5. Confirm that the collector sends the stream to Loki.

    count_over_time({log_stream="openbao.audit"}[5m])
    
  6. Confirm that OpenBao does not report audit write failures.

    sum(increase(${p}_audit_log_request_failure[5m]))
    sum(increase(${p}_audit_log_response_failure[5m]))
    
    • ${p}: Metric prefix for your deployment. Use vault for the OpenBao default prefix or openbao when you configured metrics_prefix = "openbao".

Troubleshooting

The audit device disappears after restart

Check that the same declarative audit stanza exists on every OpenBao server. Also check that the stanza path does not duplicate an API-created audit device.

The audit file stays empty

Check the audit path, file ownership, directory permissions, and mounted volume. Then run a permitted audited request. Some health, seal, and leader paths are not audit paths, so do not use them as the only verification signal.

Requests hang after an audit change

Treat the change as an audit sink incident. Restore a known-good audit path before removing or replacing a failing path, and get security approval before you disable or move an audit device.

Loki has no audit stream

Check the collector file target, read permissions, positions file, and labels. The reference dashboards and alerts expect log_stream="openbao.audit".

What’s next

Source: OpenBao documents configuration-managed audit devices in the OpenBao declarative audit documentation . OpenBao documents file audit behavior, log rotation, stdout, mode, and API creation caveats in the OpenBao file audit device documentation .