Skip to main content

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:

FieldValue
policy_kindaudit-logger
phasepreflight
verdictallow
reason_codeaudit_logger.logged
detailsomitted

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-logger to 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:

FieldSchema defaultCurrent policy behavior
immutabletrueAccepted, not enforced by audit-logger.
retention_days365Accepted, does not configure event or Trail retention.
hipaa_audit_controlsfalseAccepted, does not add HIPAA metadata or certify controls.
log_all_accesstrueAccepted, 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 verdict is allow;
  • final reason_code is ok; and
  • details.policy_results[] contains audit_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

  1. Lint and test the exact pack version.

  2. Run it locally or deploy it to the intended gateway.

  3. Send one allowed request and one request blocked by a later policy.

  4. Query recent runtime decisions with:

    kt events tail --since 10m --json
  5. Confirm the applied configuration version and the nested audit-logger result where the marker was expected.

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

SymptomLikely causeWhat to check
No audit-logger resultThe 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 okThe fixture is asserting the final decision reason.Expect allow/ok, then inspect nested policy_results.
retention_days has no observable effectThe evaluator ignores policy-local retention fields.Configure retention in the owning event/Trail workflow.
No event appears after a connected requestDelivery, 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 requestTrail and runtime Events are different evidence surfaces.Use runtime Events for request-policy outcomes and Trail for control-plane audit chronology.

Next steps