Audit Logger
Use audit-logger when you want the evaluated policy results to record that an
audit marker was present in the active chain. The current evaluator is
allow-only: it does not create storage, set retention, make records immutable,
or guarantee delivery to the control plane.
Outcome
When the entry runs, it contributes this policy result:
| Field | Value |
|---|---|
policy_kind | audit-logger |
phase | preflight |
verdict | allow |
reason_code | audit_logger.logged |
details | omitted |
Because allow-only policy results do not replace the overall decision reason,
an otherwise clean chain still finishes with final verdict allow and final
reason code ok.
Prerequisites
- Add
audit-loggerto the applicable global or route policy chain. - Use a connected gateway if you expect runtime decision events to reach the control plane.
- Configure Trail, event retention, exports, and integrity controls through their owning platform workflows. They are not configured by this policy.
Configuration
Use an empty policy block to make the current behavior explicit:
pack:
name: audit-logger-example
version: 1.0.0
enabled: true
policies:
chain:
- audit-logger
policy:
audit-logger: {}
The chain entry is what makes the policy run. A policy.audit-logger block
without a matching chain entry is configuration only.
Accepted fields versus enforced behavior
The declarative schema accepts these fields, but the current evaluator ignores all of them:
| Field | Schema default | Current policy behavior |
|---|---|---|
immutable | true | Accepted, not enforced by audit-logger. |
retention_days | 365 | Accepted, does not configure event or Trail retention. |
hipaa_audit_controls | false | Accepted, does not add HIPAA metadata or certify controls. |
log_all_access | true | Accepted, does not change which requests are delivered or retained. |
Prefer {} until the runtime implements policy-local behavior. A config that
passes schema validation with these keys is not evidence that their described
storage controls are active.
Chain-order implications
Policy evaluation stops at the first block or escalate in a stage. If
audit-logger appears after a blocking request policy, its marker result is not
added for that request.
Place it before blocking controls when you need the marker on both allowed and blocked input decisions:
policies:
chain:
- audit-logger
- prompt-injection
- pii-detector
This placement changes marker visibility, not event persistence. A standalone gateway without an event sink can still evaluate the marker without creating a control-plane event.
Test the marker
Create tests/audit-marker.json:
{
"name": "records-audit-marker",
"input": {
"messages": [
{
"role": "user",
"content": "Summarize the release notes."
}
]
},
"expected": {
"verdict": "allow",
"reason_code": "ok"
}
}
Then run:
kt policy lint --file policy-config.yaml
kt policy test --json
In JSON output, verify:
- final
verdictisallow; - final
reason_codeisok; and details.policy_results[]containsaudit_logger.logged.
Do not set the golden expectation to audit_logger.logged; that is the nested
policy-result reason, not the final allow decision reason.
Roll out and verify
-
Lint and test the exact pack version.
-
Run it locally or deploy it to the intended gateway.
-
Send one allowed request and one request blocked by a later policy.
-
Query recent runtime decisions with:
kt events tail --since 10m --json -
Confirm the applied configuration version and the nested
audit-loggerresult where the marker was expected. -
Verify retention, integrity, and evidence export separately in Trail or the applicable operator workflow.
Event delivery is asynchronous and can be unavailable on an unconnected runtime. An absent control-plane event is not proof that the evaluator did not run; check gateway connectivity and the local decision path as well.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
No audit-logger result | The kind is absent from the effective chain, skipped by targeting/conditions, or placed after an earlier stop verdict. | Inspect the active route chain and move the marker earlier if required. |
Golden test expects audit_logger.logged but fails with ok | The fixture is asserting the final decision reason. | Expect allow/ok, then inspect nested policy_results. |
retention_days has no observable effect | The evaluator ignores policy-local retention fields. | Configure retention in the owning event/Trail workflow. |
| No event appears after a connected request | Delivery, query window, gateway identity, or event sink may be wrong. | Confirm the gateway is connected, query the correct organization and time window, and correlate by request ID. |
| Trail does not show every runtime request | Trail and runtime Events are different evidence surfaces. | Use runtime Events for request-policy outcomes and Trail for control-plane audit chronology. |
Next steps
- Trail and Audit Evidence — understand storage, integrity, and export evidence
- kt events — inspect runtime decision events
- Config Testing — keep marker coverage in the pack
- Conditional Chains — understand why a chain entry may be skipped
- Export Evidence for a Review — prepare a bounded evidence handoff