Skip to content

fix(agent): apply pod-security labels from namespaceLabels again - #5687

Merged
p-se merged 1 commit into
rancher:mainfrom
p-se:issue-5550
Sep 3, 2026
Merged

fix(agent): apply pod-security labels from namespaceLabels again#5687
p-se merged 1 commit into
rancher:mainfrom
p-se:issue-5550

Conversation

@p-se

@p-se p-se commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

namespaceLabels in fleet.yaml exists so that a bundle can label the namespace it deploys into, and setting Pod Security Admission labels that way is what SURE-5906 (#1484) asked for. Since #5156 the agent dropped every pod-security.kubernetes.io/ key from the options and skipped those keys when pruning, so labels a user declares are silently ignored (SURE-11931, #5550).

That filter was the fix for GHSA-864g-863m-vcvq, where a bundle could weaken PSA enforcement on its target namespace because the agent applied namespaceLabels with its own cluster-admin credentials. #5351 changed that: the namespace is patched as the deployment's service account, so downstream RBAC decides what a bundle may write to it, and the prefix filter is no longer the control it was.

The filter never covered the whole path either. The same label reaches the same API call, under the same credentials, when it is declared on a Namespace object in the bundle, or when a pre-provisioned namespace is adopted with helm.takeOwnership. It also matched on the key alone, so it refused tightening enforcement, and setting warn or audit levels, just as it refused weakening.

Pod-security labels are therefore treated like every other namespace label again: applied when declared, pruned when they are not. Dropping the pruning exemption as well keeps un-setting working, which that exemption broke for these keys specifically.

Deployments that resolve to no service account still patch the namespace as the agent, which is cluster admin. Restricting those requires pinning a service account, in the bundle or through a Policy.

Refers to #5550

Additional Information

Checklist

  • I have updated the documentation via a pull request in the fleet-product-docs repository.

namespaceLabels in fleet.yaml exists so that a bundle can label the
namespace it deploys into, and setting Pod Security Admission labels
that way is what SURE-5906 (rancher#1484) asked for. Since rancher#5156 the agent
dropped every pod-security.kubernetes.io/ key from the options and
skipped those keys when pruning, so labels a user declares are silently
ignored (SURE-11931, rancher#5550).

That filter was the fix for GHSA-864g-863m-vcvq, where a bundle could
weaken PSA enforcement on its target namespace because the agent applied
namespaceLabels with its own cluster-admin credentials. rancher#5351 changed
that: the namespace is patched as the deployment's service account, so
downstream RBAC decides what a bundle may write to it, and the prefix
filter is no longer the control it was.

The filter never covered the whole path either. The same label reaches
the same API call, under the same credentials, when it is declared on a
Namespace object in the bundle, or when a pre-provisioned namespace is
adopted with helm.takeOwnership. It also matched on the key alone, so it
refused tightening enforcement, and setting warn or audit levels, just
as it refused weakening.

Pod-security labels are therefore treated like every other namespace
label again: applied when declared, pruned when they are not. Dropping
the pruning exemption as well keeps un-setting working, which that
exemption broke for these keys specifically.

Deployments that resolve to no service account still patch the namespace
as the agent, which is cluster admin. Restricting those requires pinning
a service account, in the bundle or through a Policy.

Refers to rancher#5550
Copilot AI lite review requested due to automatic review settings August 31, 2026 12:08
@p-se
p-se requested a review from a team as a code owner August 31, 2026 12:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment on lines +340 to +341
func addLabelsFromOptions(nsLabels map[string]string, optLabels map[string]string) {
maps.Copy(nsLabels, optLabels)

@p-se p-se Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

#5550 came from operators, not from tenants. The complaint is that an operator writes pod-security labels in namespaceLabels and the agent silently drops them. Those deployments are exactly the ones in the d.client fallback: no fleet-default service account ships with the agent chart, so out of the box nothing is pinned. Restricting pod-security labels to the impersonated path would keep ignoring them for every one of the people who reported this, and silently at that.

The tenant path is the one that's already handled. Since #5351 the namespace is patched as the deployment's service account, so whether a bundle may touch its target namespace at all is decided by that account's downstream RBAC. That's a coarser gate than the prefix filter, since RBAC scopes the namespace and not individual labels, but it's the same gate Kubernetes itself uses for PSA, and it's the one operators control through Policy and allowedServiceAccounts. The filter is redundant there.

On the fallback path being an escalation: there's no service account in that path, so every manifest in the bundle is already applied with the agent's cluster-admin credentials. You're right that PodSecurity admission still applies to cluster-admin, so relabeling a namespace is a genuine capability gain, but the filter never prevented it. The same actor can point the bundle at a new namespace (Fleet creates it, and with no cluster-wide AdmissionConfiguration default it has no enforcement at all), ship a Namespace object carrying the labels, or adopt an existing namespace with helm.takeOwnership. All three go through the same credentials and the same API call, and none of them were ever filtered. This was the narrowest of four doors.

Where you have a point is the pruning. Dropping the exemption means a bundle that declares one unrelated label removes an admin-set enforce=restricted without ever naming a pod-security key. That's #4564's clobber bug reaching the labels where it matters most, and it's a surprise rather than a deliberate act. ⚠️ But it's fixed by #5460 which rewrites the pruning to only remove what Fleet actually set. Without it, there is merit in keeping the pruning exemption in this PR.

@0xavi0 0xavi0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@p-se
p-se merged commit 8a826d0 into rancher:main Sep 3, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants