Document inbound authentication for bench services
Summary
This MR adds docs/design/authn.md, documenting inbound authentication for a
service built on the bench chassis. In the target state, a composed LabKit
module verifies the User Request Token GATE attaches at the data plane,
checking signature against the issuer's published keys, issuer, expiry, and
audience. The module is middleware and LabKit's HTTP server already runs
middleware, so the chassis configures it rather than placing it in the
request path. Verification also checks nbf and the schema ver, and the
module keeps the verified token for the authorization seam (#97) while
handlers see only the principal.
Configuration is two values (issuer URL, keys URL) arriving from the
infrastructure contract per LB-D22's declared-need model, plus a mutually
exclusive development-mode block. The audience is compiled into the assembly
as gitlab-<assembly name>, matching IAM's hardcoded allowlist. Local
development uses a stub validator that accepts a static shared credential and
establishes no principal, kept out of staging and production by two layers:
the configuration exclusion fails startup, and deployable images don't contain
the stub at all. The module refreshes its key set during the process lifetime;
how is LabKit's to design.
Since no URT module exists in LabKit v2 yet, the doc delivers the composition
point and startup guards now. In the interim, the chassis builds middleware
from a bench build fixture and verifies the Rails-issued JWT from AUTH-021,
same identity claims and same five checks, differing in issuer, audience
(Rails stamps gitlab-iam-data-access on every token), authorization claims,
and a key set fixed at startup. Readiness waits on the first JWKS fetch. The
Rust fixture verifies with jsonwebtoken on the aws_lc_rs backend, so no
rsa crate is linked.
This MR depends on !148 (merged) ("Document the auth boundaries and record LB-D4"),
still a draft; this doc links to docs/design/auth-boundaries.md and
docs/decisions/LB-D4-service-identity-mtls.md, neither of which exists on
main yet, so those links are dead until !148 (merged) merges. More significantly, the
opening section assumes !148 (merged)'s division of concerns instead of restating it,
so this MR should merge after !148 (merged).
gRPC is out of scope: the chassis doesn't serve gRPC yet (#65), and stream-open verification moved to #102. The two #87 acceptance criteria that no longer matched the design (gRPC stream-open verification and the "verification is missing" warning) are amended on the issue.
Reviewer checklist
- Reviewed the changes.
- Change matches the described intent and stays in scope.
- Milestone and labels are applied.
- CI is green.
Related issue
Related to #87