Exchange Flow: apiserver 401s the exchanged token even though the RFC 8693 exchange succeeds #45

Closed
opened 2026-09-16 05:30:13 +00:00 by ginjiruu · 0 comments
Owner

Symptom

A kubectl request carrying a Kanidm Service Account Token (SAT) through the k8s-hub gateway returns 401 Unauthorized.

The bridge log shows Served the Exchange Check — the RFC 8693 exchange succeeded and the exchanged token was injected into the Authorization header — but the k8s API server rejects the exchanged token.

So the machine/Exchange Flow works up to the bridge; the failure is at the apiserver's token validation.

Context

  • Exchange uses clientID = portablecluster (the audience), scopes openid groups_name (from the TokenExchangePolicy).
  • The apiserver's --oidc-client-id is portablecluster and --oidc-issuer-url is https://auth.animeteamspeak.moe/oauth2/openid/portablecluster (per the kubelogin config in ~/.kube/config).
  • The SAT is a readonly service-account token; the service account was added to the httpbin testing group (the earlier access_denied was a missing group membership, now resolved — the exchange itself succeeds).

Open questions (to be grilled)

  • Does the exchanged token's iss / aud actually match the apiserver's --oidc-issuer-url / --oidc-client-id? (The token endpoint is shared across clients; confirm the iss Kanidm stamps on an exchanged token for this client.)
  • Is the exchanged token an access_token in a form the apiserver's OIDC provider accepts, or does the apiserver expect an id_token?
  • Which claims does the apiserver read (--oidc-username-claim, --oidc-groups-claim, --oidc-groups-prefix)? Does the exchanged token carry them (e.g. groups_name)?
  • Need to inspect the actual exchanged token (claims) and the apiserver authn logs (the rejection reason) to pin this down.
## Symptom A kubectl request carrying a Kanidm **Service Account Token** (SAT) through the k8s-hub gateway returns **401 Unauthorized**. The bridge log shows `Served the Exchange Check` — the RFC 8693 exchange **succeeded** and the exchanged token was injected into the `Authorization` header — but the **k8s API server rejects the exchanged token**. So the machine/Exchange Flow works up to the bridge; the failure is at the apiserver's token validation. ## Context - Exchange uses `clientID` = `portablecluster` (the audience), scopes `openid groups_name` (from the `TokenExchangePolicy`). - The apiserver's `--oidc-client-id` is `portablecluster` and `--oidc-issuer-url` is `https://auth.animeteamspeak.moe/oauth2/openid/portablecluster` (per the kubelogin config in `~/.kube/config`). - The SAT is a readonly service-account token; the service account was added to the httpbin testing group (the earlier `access_denied` was a missing group membership, now resolved — the exchange itself succeeds). ## Open questions (to be grilled) - Does the exchanged token's `iss` / `aud` actually match the apiserver's `--oidc-issuer-url` / `--oidc-client-id`? (The token endpoint is shared across clients; confirm the `iss` Kanidm stamps on an exchanged token for this client.) - Is the exchanged token an **access_token** in a form the apiserver's OIDC provider accepts, or does the apiserver expect an **id_token**? - Which claims does the apiserver read (`--oidc-username-claim`, `--oidc-groups-claim`, `--oidc-groups-prefix`)? Does the exchanged token carry them (e.g. `groups_name`)? - Need to inspect the **actual exchanged token** (claims) and the **apiserver authn logs** (the rejection reason) to pin this down.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lab/authz-bridge#45
No description provided.