Skip to content

Commit 35df946

Browse files
committed
docs(admin): scope Audit middleware coverage to the protected chain
Codex P2 on the latest review of #674: the audit-log section said the Audit middleware "is emitted for every non-GET/HEAD/ OPTIONS request that reaches the admin mux on this node, regardless of which handler served it." That overstates coverage: - `/auth/login` is wired through `publicAuth`, not `protect` — the middleware can't identify the actor without a pre-existing session, so it is intentionally skipped. AuthService emits `admin_audit action=login` directly (auth_handler.go:432). - `/auth/logout` is wired through `protectNoAudit` — the middleware is omitted to avoid emitting two audit lines per logout (a generic one plus the action-specific one); the specific line is the one operators want (auth_handler.go:442). - The `protect` chain is `BodyLimit → SessionAuth → Audit → CSRFDoubleSubmit → handler` (server.go:247-255). Audit only fires AFTER SessionAuth accepts the session, so an unauthenticated write attempt (missing / expired / invalid cookie) gets 401'd before reaching Audit and produces no middleware line. CSRF-rejected requests still produce one, by design, because the actor is known by then. An operator building log-monitoring on top of the previous text could conclude that every write attempt is guaranteed to appear in `admin_audit`, then miss CSRF-bypassing probes against an unauthenticated endpoint. Rewrote the middleware-shape section to: - Scope the rule to the protected mux chain. - Explain the ordering choice (Audit between SessionAuth and CSRFDoubleSubmit) so the CSRF-rejection-still-audits guarantee is preserved in the doc. - Enumerate the two auth endpoints that bypass the middleware and what they emit instead. - Adjust the intro paragraph: protected-chain mutations produce two audit lines, auth endpoints produce one (was: "every state-changing request typically produces two"). No behaviour change; doc-only. Verified against internal/admin/server.go:236-296 and internal/admin/auth_handler.go:432-449.
1 parent 0813968 commit 35df946

1 file changed

Lines changed: 31 additions & 11 deletions

File tree

docs/admin.md

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,37 @@ logs first.
193193

194194
Every state-changing admin request emits structured slog lines at
195195
`INFO` level under the `admin_audit` key on the leader's stdout (or
196-
wherever the process slog handler is wired). A single state-changing
197-
request typically produces **two** audit lines: one operation-specific
198-
line from the source that performed the mutation, plus one generic
199-
HTTP-shaped line from the `Audit` middleware. The shapes differ by
200-
source — log parsers should treat the `admin_audit` key as a union
201-
and dispatch on the fields present.
202-
203-
**`Audit` middleware** — emitted for every non-GET/HEAD/OPTIONS
204-
request that reaches the admin mux on this node, regardless of which
205-
handler served it. Always present on the node that received the HTTP
206-
request (which may be a follower if the request was then forwarded):
196+
wherever the process slog handler is wired). A protected-chain
197+
mutation (Dynamo / S3 / cluster / keyviz writes) typically produces
198+
**two** audit lines: one operation-specific line from the source
199+
that performed the mutation, plus one generic HTTP-shaped line from
200+
the `Audit` middleware. Auth endpoints (`/auth/login`, `/auth/logout`)
201+
produce **one** line — the action-specific one from `AuthService`
202+
because the generic middleware is intentionally not wrapped around
203+
them (see the per-shape section below for why). The shapes differ
204+
by source — log parsers should treat the `admin_audit` key as a
205+
union and dispatch on the fields present.
206+
207+
**`Audit` middleware** — emitted for non-GET/HEAD/OPTIONS requests
208+
on the **protected mux chain** (Dynamo, S3, cluster, keyviz) after
209+
`SessionAuth` accepts the session, but **before** `CSRFDoubleSubmit`
210+
runs. That ordering is deliberate: a CSRF-rejected protected
211+
request still produces an audit line because the actor is already
212+
known, but an unauthenticated request (no / invalid session) is
213+
rejected at `SessionAuth` and never reaches the middleware. The
214+
following endpoints are **not** wrapped by this middleware and rely
215+
on their own `admin_audit` emission instead:
216+
217+
- `/auth/login` — runs without a pre-existing session, so the
218+
generic middleware cannot identify the actor; `AuthService`
219+
emits `admin_audit action=login` (success and failure) directly.
220+
- `/auth/logout` — runs through `protectNoAudit` so logout produces
221+
exactly one `admin_audit action=logout` line from `AuthService`
222+
rather than two (a generic line plus the action-specific one).
223+
224+
For requests that *do* reach the middleware, the line is always
225+
present on the node that received the HTTP request — which may be
226+
a follower if the request was then forwarded:
207227

208228
```
209229
admin_audit actor=AKIA_ADMIN role=full method=POST path=/admin/api/v1/buckets status=201 remote=10.0.0.7:51234 duration=8.2ms

0 commit comments

Comments
 (0)