Skip to content

kubernetes chart: a client-supplied X-Remote-Uid reaches tenant extension servers while a v1.31 to v1.32 control-plane upgrade rolls #4371

Description

During a control-plane version bump from v1.31 to v1.32 on a tenant with spec.oidc.mode other than None, the two apiserver versions serve side by side while the Deployment rolls (controlPlane.replicas defaults to 2), and for that window an aggregated API server inside the tenant can be handed a UID the client chose.

Mechanism, read at the pinned client-go. A v1.31 aggregator strips X-Remote-User, X-Remote-Group and X-Remote-Extra-* from the incoming request before proxying and does not know X-Remote-Uid, so a client-supplied one passes through (transport/round_trippers.go, SetAuthProxyHeaders at v0.31.14). From v1.32 the same function deletes X-Remote-Uid as well (v0.32.13). Once the first v1.32 replica is up it publishes requestheader-uid-headers into extension-apiserver-authentication, which is what #3539 renders, so an extension server built on k8s.io/apiserver starts trusting that header. A request that lands on a v1.31 replica during the roll therefore reaches the extension server with whatever X-Remote-Uid the client sent.

Severity is low. The username and groups still come from the v1.31 aggregator's own authentication and cannot be spoofed this way, RBAC does not consult the UID, and the window closes when the last v1.31 replica is gone. I have not checked whether a v1.31 trust controller drops the key again when it rewrites the ConfigMap; if it does, the window flickers instead of holding.

Two possible homes: a sentence in docs/oidc-tenant.md telling operators that UID-based decisions in tenant extension servers are unreliable until a version bump from v1.31 has finished, or nothing, on the grounds that this is upstream version-skew behaviour. Found during review of #3539 and not changed there.

Activity

  1. lexfrei commented on Sep 22, 2026

    @lexfrei
    ContributorAuthor

    One open point from the description is settled. I wrote that I had not checked what a v1.31 trust controller does to the key once a v1.32 replica has published it. Two independent reads of the controller at v1.31 and v1.32 agree: the v1.31 replica rebuilds extension-apiserver-authentication without requestheader-uid-headers, so during the roll the key comes and goes as replicas of both versions rewrite the ConfigMap. The window flickers rather than holds, and a single look at the ConfigMap during the roll proves nothing either way. The docs sentence for this is in the follow-up PR.

  2. lexfrei commented on Sep 23, 2026

    @lexfrei
    ContributorAuthor

    Obsolete with #4407. The window needs a v1.31 aggregator and a replica that publishes requestheader-uid-headers serving at the same time. After #4407 the chart renders the UID flags only from v1.33, and a control plane cannot roll from v1.31 to v1.33 in one step. On a v1.32 to v1.33 roll the older aggregator already strips a client-supplied X-Remote-Uid. No release shipped the v1.32 path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/kubernetesIssues or PRs related to the tenant Kubernetes appkind/documentationCategorizes issue or PR as related to documentationsecurity/lowLow severity security findingtriage/needs-triageIndicates an issue needs triage by a maintainer

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions