How does audit authenticate and authorize callers?¶
An Authenticator turns a request into a Principal. An Authorizer turns a Principal into a Grant.
type Authenticator interface {
Principal(ctx, req) (Principal, error) // issuer, subject, claims
}
type Authorizer interface {
Grant(ctx, Principal) (Grant, error)
}
type Grant struct {
AllTenants bool // an operator's grant, said out loud
Tenants []string
Profiles []string
Operations []Operation // search, facets, get, export, tail, resolve
From, Until time.Time
Rule string // stamped into the log_access record
}
The zero value grants nothing. An operator's all-tenant grant sets AllTenants explicitly.
The grant reaches a query as one more filter term, not as a check beside it. resolve is not implied by get: it undoes pseudonymisation, and a grant to read does not carry it.
Authenticators¶
| authenticator | status | use |
|---|---|---|
jwt |
built | a list of trusted issuers, each with a required audience |
| workload tokens | built | a workload in the application's namespace presents its projected service-account token |
none |
built | tests only |
jwt¶
The token's iss is read unverified only to choose which keys check it. That issuer's verifier then requires the same issuer. Verification is gateway-auth's, as for every fleet service.
Two issuers can assert the same claim, for example all:audit:auditor in groups. A rule therefore names the claim it reads and the issuer it trusts it from. With several issuers every rule must name one.
Workload tokens¶
The receiver verifies the token as a JWT from the cluster's own OIDC issuer. The subject is the service account, which the kubelet vouches for. The receiver stamps it on each record as the observer. It also authenticates RegisterCatalogue.
| Caller and records | Behaviour |
|---|---|
| Source of a record | with workloads listed, a record of another source is refused by id and the batch goes on; a caller not listed writes nothing |
| Tenant and actor | not bound: the workloads file carries neither |
On the SQS path¶
A record arriving through the ingest queue carries no verified caller identity. SQS delivers the body and attributes the sender chose. The writer attributes the record to itself.
| Consumer | Stamp in the message |
|---|---|
| writer Lambda, queue consumer | ignored: observer, recorded_at and origin_hash are made from what SQS sets |
| NATS consumer | kept: the stream admits this installation's receivers alone |
| Stamped from SQS | Value |
|---|---|
observer.id |
the senders entry for the message's SenderId (AROA... of the role, or the whole id with its session); empty when none |
recorded_at |
the message's SentTimestamp |
Whoever may send to the queue can therefore record under any source and actor a catalogue admits. Authenticity on this path rests on the queue policy's sender principals alone.
Ingest.Sendersis required. The queue policy allowssqs:SendMessageto those principals and denies every other (aws:PrincipalArn).Ingest.AnySenderInAccountallows any principal of the account withsqs:SendMessage, for a trial. The trail then cannot say who sent a record. The two settings are refused together.- Name one principal per sending workload (the receiver, the query service, the notary), each with
sqs:SendMessageon the queue only. Name a principal in another account the same way.
The observer is not taken from a message attribute, which is the sender's own claim. SQS sets a SenderId the sender cannot choose. Map each sender's role id to a name in senders, or give each sender its own queue.
The HTTP and stream paths differ: the receiver verifies the caller's token and stamps the observer.
Authorizers¶
| authorizer | status | reads |
|---|---|---|
declarative (default) |
built | configuration mapping claim values to grants, plus grant presets |
access-roster grants preset |
built | <scope>:audit:<role> from the groups claim |
| policy-engine adapter | optional | an engine whose query plan returns a filter and whose decision log names the rule |
An authorizer answers with every grant the caller holds. auth.Effective picks, per request, the grants covering the profile and operation asked. Tenants union within a profile and never across profiles. A time window never unions.
| Grants with windows | Effect |
|---|---|
| one covers another's tenants and window | the covered one is set aside |
| the rest differ in window | the request is refused |
The access-roster grants preset (legacy identifier, renamed in v1.75–v1.76) reads the estate's grant grammar, which sluis defines. authn.SplitGroup splits it. Roles bind to the framework profiles a profile is composed from, not to profile names. viewer must be tenant-scoped. resolve and time-boxed grants are explicit rules only. The reference lists the role table.
The Audit page¶
The application's own console hosts the page and passes the token it already holds. See the Audit page.
Resolution¶
resolve maps a pseudonym back to a person through the identity map. Grant it to as few roles as possible. It emits audit.get-class records naming the rule.
With no keys block, there is nothing to resolve. The operation is refused as unimplemented. A grant may still name it.