Document service tokens in AR auth ADR-020

What this changes

Adds a ## Service-to-service authentication section to ADR-020: the shared two-layer pattern, then one subsection per edge.

  • Artifact Registry to the relationships API (iam-data-access) carries both layers — a service token in gitlab-iam-data-access-token plus the end-user JWT. Covers token rotation, the opaque rejection behavior, the health-RPC exemption, which token flows on the data path versus the admin and UI flows, and that each side verifies the JWT independently rather than trusting the other's check.
  • GitLab Rails to the Artifact Registry internal API is not user-initiated, so there is no identity for the second layer to carry and the service token alone authenticates the caller.

The target-state direction (mutual TLS with workload identity, caller identity in a URT) goes to "Future work / open debates", since neither is decided.

Extends ADR-020's existing authentication-flow diagram with the relationships API call, showing both credentials on the wire (steps 5-6). Updates the ADR-021 authorization-flow diagram the same way, and links to the new ADR-020 section.

Also corrects four claims in ADR-020 about the token payload GitLab Rails issues, found while writing the new section.

Why

No ADR documented the service token, so every sequence diagram showed only JWTs on that call. A reader planning an integration would use the wrong credentials. This was agreed in gitlab-org/ops/artifact-registry#255 (closed), which concluded a short addition to ADR-020 was enough — no rewrite needed.

Drift fixes — please review

Checked against ee/lib/authn/token_exchange/token_issuer.rb on gitlab-org/gitlab master:

  1. aud carries two values, not one: the requested audience (gitlab-artifact-registry) plus gitlab-iam-data-access, which Rails appends to every token. This is what lets Artifact Registry forward the token to the relationships API.
  2. Added the ver claim (payload schema version, currently 1). IAM's verifier rejects a token without it.
  3. Replaced gitlab_realm and gitlab_organization_id, which do not exist, with the nested gitlab object Rails actually issues: origin, origin_id (an organization UUID), local_id, identity_kind, organization_role. organization_role is documented as the bootstrapping fallback, tying to ADR-021's R6 requirement.
  4. "Token duration" said a client "may request a shorter lifetime"; the endpoint accepts 1 second to a 12-hour cap, so a client can request longer than the 5-minute default too. "Enablement enforcement" now cites gitlab.origin_id instead of gitlab_organization_id.

Sources: https://gitlab.com/gitlab-org/auth/iam/-/blob/main/docs/service-access.md and https://gitlab.com/gitlab-org/auth/iam/-/blob/main/docs/relationships-api.md

vale reports no issues on ADR-020; markdownlint reports no issues on either file.

Not in scope

The interface agreement at agreements/auth.md has the same omission in its interim-state sequence diagram; a reviewer may want that as a separate MR.

pkg/userauth never refreshes its JWKS, so ADR-020's claim that keys are "refreshed periodically" with brief stale-key retention is untrue today. That is a code gap, filed as gitlab-org/gitlab#616174, and deliberately left out of this MR.

🤖 Drafted by Claude Code.

Edited by Matthias Käppler

Merge request reports

Loading
Loading