Skip to content

Fix(controller,webhook): write client-id.txt in federated-jwt mode for inbound JWT validation#483

Merged
Alan-Cha merged 2 commits into
mainfrom
fix/federated-jwt-client-id-txt
Jul 15, 2026
Merged

Fix(controller,webhook): write client-id.txt in federated-jwt mode for inbound JWT validation#483
Alan-Cha merged 2 commits into
mainfrom
fix/federated-jwt-client-id-txt

Conversation

@Alan-Cha

@Alan-Cha Alan-Cha commented Jul 15, 2026

Copy link
Copy Markdown
Member

Problem

In federated-jwt mode, agent pods reject all inbound authenticated requests with HTTP 503:

identity not yet configured (credentials pending)

The authbridge-proxy sidecar polls indefinitely for /shared/client-id.txt — the file the inbound jwt-validation plugin reads to determine the expected audience when validating incoming JWTs.

Root cause

PR #476 correctly intended to skip writing client-secret.txt in federated-jwt mode. However it skipped the entire ensureClientCredentialsSecret call, which also skipped client-id.txt. It also skipped patchTemplate, so the Secret annotation was never set and the webhook never mounted the Secret into the pod at all. The broken chain:

  1. ensureClientCredentialsSecret skipped → no Secret, no client-id.txt
  2. patchTemplate skipped → no annotation on pod template → webhook doesn't mount Secret
  3. Webhook separately skipped annotation pre-population → same result

Fix

Controller — in federated-jwt mode, pass an empty clientSecret to ensureClientCredentialsSecret instead of skipping the call. The Secret is always written with both keys: client-id.txt (the agent's SPIFFE ID) and client-secret.txt (empty string in federated-jwt mode). Writing an empty client-secret.txt rather than omitting the key avoids a Kubernetes quirk where a subPath mount for an absent Secret key creates a directory at the mount path instead of a file. Remove the authType guard so patchTemplate also runs in federated-jwt mode.

Webhook — remove the federated-jwt guard on annotation pre-population. The Secret now exists in this mode, so the volume mount annotation is needed for the first pod to start without a pod recreate.

In federated-jwt mode AuthBridge uses identity.type=spiffe for outbound token exchange and never reads client-secret.txt, so the empty value is harmless.

Testing

  • go build ./... clean
  • go vet ./internal/controller/... ./internal/webhook/... clean

Fixes #482

Assisted-By: Claude Code

…r inbound JWT validation

In federated-jwt mode the inbound jwt-validation plugin in AuthBridge reads
/shared/client-id.txt to determine the expected audience for incoming requests.
PR #476 skipped the entire ensureClientCredentialsSecret call in this mode,
which meant client-id.txt was never written and every inbound request to the
agent was rejected with HTTP 503 indefinitely.

Controller:
- Pass empty clientSecret (not clientID) to ensureClientCredentialsSecret in
  federated-jwt mode so the Secret is still created with client-id.txt only.
- Remove the authType guard so patchTemplate still runs in federated-jwt mode,
  keeping the pod template annotation that causes the webhook to mount the Secret.
- In ensureClientCredentialsSecret, omit client-secret.txt when clientSecret is
  empty rather than always writing it.

Webhook:
- Remove the federated-jwt guard that skipped annotation pre-population.
  The Secret still exists in federated-jwt mode (with client-id.txt only), so
  the volume mount annotation is needed for the first pod to come up correctly.

Fixes #482

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Alan Cha <Alan.cha1@ibm.com>
A subPath mount for an absent Secret key creates a directory at the
mount path rather than a file. Write client-secret.txt as an empty
string so the mount produces a regular file. AuthBridge ignores the
file in SPIFFE mode (it never reads client-secret.txt when
identity.type=spiffe), but a directory at that path is confusing and
fragile.

Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Alan Cha <Alan.cha1@ibm.com>
@Alan-Cha Alan-Cha changed the title fix(controller,webhook): write client-id.txt in federated-jwt mode for inbound JWT validation Fix(controller,webhook): write client-id.txt in federated-jwt mode for inbound JWT validation Jul 15, 2026

@pdettori pdettori left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, minimal fix that restores the inbound-JWT audience config broken by #476.

Verified the logic against the full head-branch files: the controller now always calls ensureClientCredentialsSecret + patchTemplate (passing an empty clientSecret in federated-jwt mode), and the webhook now always pre-populates the annotation. The two sides are consistent — the Secret is created for every auth type and the webhook annotates for every eligible workload. The subPath-creates-a-directory-for-absent-key rationale for writing an empty client-secret.txt is a real Kubernetes quirk and a sound defensive choice.

Supply-chain gate clear (no .claude//.vscode/ changes). All 16 CI checks green, both commits signed off.

One non-blocking nit inline.

Assisted-By: Claude Code

// Skip in federated-jwt mode: AuthBridge reads JWT-SVIDs from the SPIFFE workload API
// socket directly and no credential Secret is created or needed. Injecting the volume
// mount for a non-existent Secret would leave pods stuck in Init.
// In federated-jwt mode the Secret still exists (written by the operator with only

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this comment says the Secret is "written by the operator with only client-id.txt, no client-secret.txt", but the controller change in this same PR writes client-secret.txt as an empty string rather than omitting it (that's the whole point of the subPath fix). Suggest rewording to "written with client-id.txt and an empty client-secret.txt" so it matches the actual behavior and the controller-side comment.

@Alan-Cha Alan-Cha merged commit 30438f8 into main Jul 15, 2026
17 of 18 checks passed
@github-project-automation github-project-automation Bot moved this from New/ToDo to Done in Kagenti Issue Prioritization Jul 15, 2026
@pdettori pdettori deleted the fix/federated-jwt-client-id-txt branch July 15, 2026 23:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

bug: inbound JWT validation broken in federated-jwt mode (client-id.txt never written)

3 participants