Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 4515@bnt-lap001 Assistant-Session: 0bf96127-6e04-41be-bfda-d11717c3f354
6.6 KiB
KeyCape audit-core intake package
Status: proposed, 2026-10-27. Answers audit-core AUDIT-WP-0017-T04 ("common
intake package for every new sender") for KeyCape, and NetKingdom NK-WP-0055-T11.
Implementation work: workplans/KEY-WP-0044-audit-correlation-and-intake.md.
Unknowns are marked UNKNOWN. Authelia, LLDAP and privacyIDEA get their own
packages and source names; this one covers KeyCape only.
1. What KeyCape emits today (from source, 2026-10-27)
All events go through telemetry.Emitter
(src/internal/server/telemetry/). In production cmd/keycape/main.go
wires a LogEmitter: one zerolog JSON line on stdout per event. There is no
webhook, receipt store or audit-core sender.
Fields per line: event_type, client_id, endpoint, result,
environment, trace_id, timestamp, and optionally feature,
error_type, scopes, uid, assurance, grant_type. Events never carry
tokens, codes, email or OTPs (comment in events.go).
| event_type | Emitted at |
|---|---|
auth_start |
/authorize request accepted |
auth_success |
/authorize completes (with uid, assurance aal1/aal2); also /userinfo |
auth_failure |
/authorize: auth_failed, stale_upstream_authentication, mfa_check_error, mfa_failed |
token_issued |
/token authorization_code/refresh and client_credentials success |
unsupported_feature |
profile enforcement middleware |
migration_event |
migration tools only (not the server) |
Gaps against audit needs:
trace_idis never set (always empty) — fixed by KEY-WP-0044-T01.- No event on
/tokenfailures, client authentication failure, revoke or introspection; no explicit event for denied scope/tenant/principal-type preconditions — KEY-WP-0044-T02. token_issuedlacks subject and tenant;environmentis unset on several emissions; no stable event id — KEY-WP-0044-T02.
2. Source registration
| Item | Value |
|---|---|
source |
netkingdom.keycape (proposed) |
| Owning repo | key-cape (runtime package owner: UNKNOWN, the Railiance/rapp package that deploys KeyCape) |
| Namespace / pod selector | UNKNOWN — to be taken from the deploying package; KeyCape does not own its manifests |
| Emitting identity | a dedicated KeyCape audit sender credential (section 6); not a KeyCape OIDC client |
| Tenant policy | per-tenant: the event's tenant is the principal's tenant; platform-scoped events (client auth failure before a tenant is known, service clients without a tenant) use a platform tenant value — UNKNOWN, audit-core to name it |
3. Envelope mapping (audit-core docs/event-envelope.md)
| Envelope field | KeyCape value |
|---|---|
id (= Idempotency-Key) |
event_id: UUIDv7 minted once when the event is created and reused on every retry (KEY-WP-0044-T02). Not derived from request content, so two identical logins stay distinct |
type |
keycape.<action> from section 4 |
source |
netkingdom.keycape |
subject |
the principal (sub/uid) for user events; client:<client_id> for client-only events |
tenant |
principal tenant, else the platform tenant value |
correlation_id |
W3C trace-id from inbound traceparent, or a generated one (contract AC-1, AC-4) |
occurred_at |
event timestamp, RFC 3339 with offset (UTC Z) |
data |
client_id, endpoint, result, error_type, grant_type, scopes, assurance, principal_type, environment, correlation_origin (propagated/generated), optional parent_event_id |
Never in data: access/ID/refresh tokens, authorization codes, client
secrets, passwords, OTPs, email. actor is null at ingest per the envelope;
the authenticated subject lives in subject/data.
4. Scope rows (action vocabulary)
type |
Today | Meaning |
|---|---|---|
keycape.auth.start |
yes | authorize request accepted |
keycape.login.success |
yes (auth_success) |
user authenticated, with assurance |
keycape.login.failure |
yes (auth_failure) |
upstream auth failed or stale |
keycape.mfa.success |
partly (aal2 on auth_success) |
MFA/step-up satisfied |
keycape.mfa.failure |
yes (mfa_failed, mfa_check_error) |
MFA challenge failed or errored |
keycape.token.issued |
yes | token issued (any grant) |
keycape.token.denied |
no | /token refused: invalid_grant, invalid_scope, unauthorized_client |
keycape.client.auth_failure |
no | client authentication failed at /token, revoke or introspect |
keycape.scope.denied |
no | requested scope, tenant or principal-type precondition refused |
keycape.token.revoked |
no | revocation accepted |
keycape.token.introspected |
no | introspection served (volume to be judged; may be excluded) |
keycape.userinfo.served |
yes (auth_success on /userinfo) |
userinfo served |
keycape.profile.unsupported_feature |
yes | request used a feature the profile refuses |
keycape.heartbeat |
no | liveness, section 5 |
migration_event is excluded: it comes from offline tools, not the server.
5. Volume, heartbeat, retention
- Volume: UNKNOWN — no production measurement exists. Estimate for the
current one-node estate with a handful of users and six flex-auth consumers:
low hundreds to a few thousand events/day, peak under 5/s, dominated by
token.issued(client_credentials) anduserinfo.served. To be replaced by a measured count from the stdout stream before overlay sizing. emission_cadence: event-driven pluskeycape.heartbeatevery 5 minutes; proposed silence threshold 15 minutes.- Retention: audit-core default 30-day query window plus archive. Proposed archive for login/MFA/token/denial records: 1 year (security-relevant identity evidence). Final class is a NetKingdom/audit-core decision — UNKNOWN.
6. Credential path
The sender secret is minted through the attended OpenBao path that
warden route find "audit-core sender credential" points to
(railiance-platform OpenBao), delivered to the KeyCape pod as a Kubernetes
Secret reference, and never in Git, State Hub, logs or this document.
audit-core never holds or prints it; may_read stays false; may_write is
limited to source netkingdom.keycape. The exact OpenBao path and delivery
mechanism are UNKNOWN until railiance-platform names them.
7. Export mechanism
Open choice, recorded in KEY-WP-0044-T03: (a) a collector tailing KeyCape's
stdout JSON lines and posting envelopes, or (b) a KeyCape AuditEmitter
posting directly with retry on the stable event_id. Preference: (b), because
event_id and correlation_origin are known only inside KeyCape and a log
tail cannot guarantee idempotent retry. UNKNOWN until audit-core states its
preferred intake for application senders.