From 778b1ba80e3abef80c9c42564d57d4bdd32d4b90 Mon Sep 17 00:00:00 2001 From: Arnob Kumar Saha Date: Sun, 26 Jul 2026 22:43:28 +0600 Subject: [PATCH] Impersonate only ACE extras DelegatingClient.Impersonate forwarded every extra key from the caller's identity. Impersonating an extra key requires an `impersonate` grant on userextras/, so a caller carrying provider-injected extras -- Rancher's principalid/username, EKS' arn, the reserved authentication.kubernetes.io/* keys -- had the whole request denied during impersonation authorization. Keep only ace.appscode.com/* extras, which are the ones our components hold RBAC for and the only ones that carry meaning downstream. RBAC ignores extras, so dropping the rest changes no authorization decision on an ordinary cluster. Signed-off-by: Arnob Kumar Saha --- client/delegated.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/client/delegated.go b/client/delegated.go index 6a4c4eca7..b1a1364e9 100644 --- a/client/delegated.go +++ b/client/delegated.go @@ -100,13 +100,38 @@ func (d *DelegatingClient) RestConfig() *restclient.Config { return d.config } +// aceExtraPrefix is the only extra-key namespace impersonated identities carry +// through. See impersonableExtra. +const aceExtraPrefix = "ace.appscode.com/" + +// impersonableExtra keeps only the ACE extras. Every other extra key is provider +// bookkeeping injected by the apiserver or the platform -- Rancher's principalid, +// EKS' arn, the reserved authentication.kubernetes.io/* keys -- and impersonating +// any of them needs an `impersonate` grant on userextras/ that callers do not +// hold, which fails the whole request during impersonation authorization. RBAC +// ignores extras, so dropping them changes no authorization decision. +func impersonableExtra(in map[string][]string) map[string][]string { + out := make(map[string][]string, len(in)) + for k, v := range in { + if strings.HasPrefix(k, aceExtraPrefix) { + out[k] = v + } + } + if len(out) == 0 { + return nil + } + return out +} + func (d *DelegatingClient) Impersonate(u user.Info) (*restclient.Config, client.Client, error) { + extra := impersonableExtra(u.GetExtra()) + config := restclient.CopyConfig(d.config) config.Impersonate = restclient.ImpersonationConfig{ UserName: u.GetName(), UID: u.GetUID(), Groups: u.GetGroups(), - Extra: u.GetExtra(), + Extra: extra, } // share the transport between all clients @@ -117,7 +142,7 @@ func (d *DelegatingClient) Impersonate(u user.Info) (*restclient.Config, client. UserName: u.GetName(), UID: u.GetUID(), Groups: u.GetGroups(), - Extra: u.GetExtra(), + Extra: extra, }, d.options.HTTPClient.Transport), } }