Impersonate only ACE extras#437
Open
ArnobKumarSaha wants to merge 2 commits into
Open
Conversation
Picks up the ACE-extras allowlist in DelegatingClient.Impersonate (kmodules/client-go#645). Signed-off-by: Arnob Kumar Saha <arnob@appscode.com>
impersonableExtra dropped just the reserved authentication.kubernetes.io/* keys and forwarded every other extra from the caller's identity. Kubernetes authorizes impersonated extras per key, as userextras/<key>, and the chart grants kube-ui-server exactly one of those -- ace.appscode.com/org-id. So a caller carrying provider-injected extras had the whole EditorModel request denied during impersonation authorization, before its own RBAC was consulted. This is what a spoke imported through Rancher hits: Rancher forwards principalid, username, requesthost and requesttokenid, none of them ACE keys. Turn the denylist into an allowlist keeping only ace.appscode.com/* extras. Every platform invents its own -- Rancher's principalid, EKS' arn, OpenShift's scopes.authorization.openshift.io -- so widening the chart RBAC never converges, while an allowlist is correct on any provider. RBAC ignores extras, so this changes no authorization decision on an ordinary cluster. Signed-off-by: Arnob Kumar Saha <arnob@appscode.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
An EditorModel request from a spoke cluster imported into ACE through Rancher fails with:
kube-ui-serverreads the AppRelease as the calling user via impersonation, so the read is authorized against the caller's own RBAC.impersonableExtradropped only the reservedauthentication.kubernetes.io/*extras and forwarded everything else.Kubernetes authorizes impersonated extras per key, as a subresource: extra key
kneedsimpersonateonuserextras/kinauthentication.k8s.io. The installer chart grants exactly one —userextras/ace.appscode.com/org-id. Rancher authenticates its own user and forwardsprincipalid,username,requesthost,requesttokenid; none is an ACE key, so the request was denied in impersonation authorization (round 1), before the impersonated user's RBAC was ever consulted.Reproduced against the apiserver with the server's own SA token, which takes b3, Rancher and the console out of the picture:
The confusing
impersonate-on:user-info:getwording is Kubernetes 1.36's constrained impersonation (KEP-5284, beta/on by default) reporting the same denial through a different mode. Granting the constrained verbs would not help: constrained impersonation rejects extra keys that are not domain-prefixed, so bare keys likeprincipalidcan only ever go through the legacy path. Running a 1.35 spoke would not help either — it only changes the message.Fix
Allowlist instead of denylist: forward only
ace.appscode.com/*extras.Every platform invents its own extras — Rancher's
principalid, EKS'arn/sessionName, OpenShift'sscopes.authorization.openshift.io, plus the apiserver's ownauthentication.kubernetes.io/*. Chasing each with wider chart RBAC never converges; an allowlist is correct on any provider and needs no installer release. RBAC ignores extras entirely, so this changes no authorization decision on an ordinary cluster.The second commit bumps
kmodules.xyz/client-gofor the same fix inDelegatingClient.Impersonate(kmodules/client-go#645), which is the impersonation path used bypkg/graph.Impact on pkg/graph
graph.NewClient(pkg/graph/setup.go:335) is the only route intoDelegatingClient.Impersonatefrom this repo. Its callers:ExecRawQuery/ExecQuery(setup.go:253,289),_renderPageBlock(renderer.go:231),renderDashboard(dashboard.go:51) andrenderdashboard/storage.go:135.It bails out to the un-impersonated client unless the caller carries exactly one
ace.appscode.com/org-idextra, which bounds the change:org-id— no change.org-idplus another extra (e.g.authentication.kubernetes.io/credential-id, injected by the apiserver for token auth on k8s >= 1.30) — previously a hard denial, now works.It cannot break an impersonation that currently works: under the chart's RBAC any extra outside the single grant already caused a full denial, so the allowlist only turns denials into successes. The exception is a cluster whose ClusterRole was manually widened to
userextras/*— there, extras no longer reach the apiserver, which matters only to a custom authorization webhook, since RBAC ignores extras.Caveats for the reviewer
go.modpinskmodules.xyz/client-go v0.34.6-0.20260726164328-778b1ba80e3a, a pseudo-version of the branch behind Impersonate only ACE extras kmodules/client-go#645. That PR needs to merge and be tagged, and this one re-pinned to the tag, before merging.kmapi.ClientKeyPrefixisclient.ace.appscode.com/, which does not match theace.appscode.com/prefix. Nothing in this repo or its vendor tree uses it as an extra key, but if b3 or another producer sends one it will be dropped — that key would have been denied under the current chart RBAC anyway.Refs
kubeops.dev/installer/charts/kube-ui-server/templates/cluster-role.yaml:60-70