Repository navigation
[PAM-190] PAM access audit: API - #8507
Conversation
Bundle A6 of the pam/uat -> main extraction (PAM-173). Puts the access-audit store from #8230 to use: commands record what they do, and admins can read the trail back. - AccessAuditEventEmitter writes an Attempt before each action's point of no return and an Outcome after it. Wired into the nine commands on main: access rule create/update/delete, request submit/decide/cancel/ activate, and lease extend/revoke. The access-rule delete now takes the calling user so the event can name the actor. - ListAccessAuditTrailQuery and ListAccessAuditItemsQuery behind a new /organizations/{orgId}/audit endpoint group, with keyset continuation tokens and a range clamped to the 90-day history window. - PamDisableSqlAuditLogging kill switch: stops the writes and takes the read endpoint down with them. - AccessAuditEventKind gains the rotation and fleet kinds so the wire vocabulary is pinned in full. Content matches pam/uat except for omissions: the organization event log fan-out (B1), the push and mail notifiers (A7), and the rotation access-end hook in revoke (A12).
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8507 +/- ##
==========================================
- Coverage 71.35% 65.98% -5.38%
==========================================
Files 2547 2575 +28
Lines 109310 110572 +1262
Branches 9940 10054 +114
==========================================
- Hits 77999 72957 -5042
- Misses 28816 35235 +6419
+ Partials 2495 2380 -115 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Re-reviewed the full diff at Traced the paths the earlier threads opened and found them closed in code: the automatic approval records its own No findings. |
patriksvensson
left a comment
There was a problem hiding this comment.
LGTM 👍
Left a minor comment, but not 100% sure about it and if this is something we need to fix.
| await _accessAuditEventEmitter.EmitAsync( | ||
| audit with | ||
| { | ||
| Kind = AccessAuditEventKind.RequestDenied, |
There was a problem hiding this comment.
Maybe we should set the ActorId to null here, otherwise I think the audit log will look like something like (and I'm paraphrasing) "User X denied extension for user X". Not sure if it something we need to fix now though.
🎟️ Tracking
PAM-190 — bundle A6 of the
pam/uat→mainextraction, tracked under PAM-173. Builds on the access-audit store from #8230.Originating tickets on
pam/uat: PM-39047, PM-42480, PM-42614, PM-42814, PM-42816 and PM-43606.📔 Objective
#8230 landed the append-only
AccessAuditEventstore with nothing calling it. This PR writes to it and reads it back: PAM commands now record what they do, and organization admins can page through the trail.Recording.
AccessAuditEventEmitteris the write side. Each action emits anAttemptbefore its point of no return and anOutcomeafter it, sharing a correlation ID. AnAttemptwith noOutcomeis how the trail shows an action that may not have landed. The emitter is wired into the nine commands onmain:An access-rule delete now receives the calling user, because the audit event is the only record of who deleted the rule.
Reading. A new
/organizations/{orgId}/auditendpoint group, backed byListAccessAuditTrailQueryandListAccessAuditItemsQuery. Paging is keyset-based throughAccessAuditTrailContinuationToken. The requested range is clamped to the 90-day history window byAccessHistoryWindow.ResolveRange. Kinds go over the wire as the string vocabulary inAccessAuditEventKindNames, which a test pins against the web client's copy.Kill switch.
PamDisableSqlAuditLoggingstops the store writes and takes the read endpoint down with them, so the trail is never served as a complete record of a period it only partly covers. Off is both the default when the flag is absent and the only state self-host ever sees.AccessAuditEventKindalso gains the rotation and fleet kinds. Nothing onmainemits them yet, but the wire vocabulary covers them, so they land with it.Scope
Every file matches
pam/uatexactly or differs only by omission. Deliberately left out, each returning with its own bundle:IEventService, theEventTypemapping) and its tests go with B1, which needs Dirt review.daemon*kind names thatpam/uatstill accepts in the trail filter are dropped.mainnever served this endpoint, so no client sends them.This PR also takes the pieces A4 (#8494) deferred here: the acting-user argument to the access-rule delete, and
AuditEndpointsHandlerregistered in the endpoint test hosts.