From 778b1ba80e3abef80c9c42564d57d4bdd32d4b90 Mon Sep 17 00:00:00 2001 From: Arnob Kumar Saha Date: Sun, 26 Jul 2026 22:43:28 +0600 Subject: [PATCH 1/2] 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), } } From 53cd41dde2a3a78dc831066cf165597c7bccf63b Mon Sep 17 00:00:00 2001 From: Arnob kumar saha Date: Mon, 27 Jul 2026 19:04:37 +0600 Subject: [PATCH 2/2] Reformat with updated gofmt Signed-off-by: Arnob kumar saha --- admissionregistration/v1/mutatingwebhookconfiguration.go | 6 ++++-- admissionregistration/v1/validatingwebhookconfiguration.go | 6 ++++-- .../v1beta1/mutatingwebhookconfiguration.go | 6 ++++-- .../v1beta1/validatingwebhookconfiguration.go | 6 ++++-- conditions/merge_strategies_test.go | 3 ++- discovery/lib.go | 3 ++- discovery/lib_test.go | 3 ++- dynamic/kubernetes.go | 3 ++- meta/preconditions.go | 3 ++- openapi/render.go | 3 ++- tools/queue/handler.go | 2 +- 11 files changed, 29 insertions(+), 15 deletions(-) diff --git a/admissionregistration/v1/mutatingwebhookconfiguration.go b/admissionregistration/v1/mutatingwebhookconfiguration.go index 362e7d8c9..c8df7f832 100644 --- a/admissionregistration/v1/mutatingwebhookconfiguration.go +++ b/admissionregistration/v1/mutatingwebhookconfiguration.go @@ -161,7 +161,8 @@ func UpdateMutatingWebhookCABundle(config *rest.Config, webhookConfigName string lw, ®.MutatingWebhookConfiguration{}, nil, - conditions...) + conditions..., + ) return err } @@ -213,7 +214,8 @@ func SyncMutatingWebhookCABundle(config *rest.Config, webhookConfigName string) default: return false, fmt.Errorf("unexpected event type: %v", event.Type) } - }) + }, + ) utilruntime.Must(err) }() return diff --git a/admissionregistration/v1/validatingwebhookconfiguration.go b/admissionregistration/v1/validatingwebhookconfiguration.go index 407bffc26..bf18cf16f 100644 --- a/admissionregistration/v1/validatingwebhookconfiguration.go +++ b/admissionregistration/v1/validatingwebhookconfiguration.go @@ -156,7 +156,8 @@ func UpdateValidatingWebhookCABundle(config *rest.Config, webhookConfigName stri }, }, extraConditions...) - _, err = watchtools.UntilWithSync(ctx, + _, err = watchtools.UntilWithSync( + ctx, lw, ®.ValidatingWebhookConfiguration{}, nil, @@ -213,7 +214,8 @@ func SyncValidatingWebhookCABundle(config *rest.Config, webhookConfigName string default: return false, fmt.Errorf("unexpected event type: %v", event.Type) } - }) + }, + ) utilruntime.Must(err) }() return diff --git a/admissionregistration/v1beta1/mutatingwebhookconfiguration.go b/admissionregistration/v1beta1/mutatingwebhookconfiguration.go index bd63ef200..943052612 100644 --- a/admissionregistration/v1beta1/mutatingwebhookconfiguration.go +++ b/admissionregistration/v1beta1/mutatingwebhookconfiguration.go @@ -161,7 +161,8 @@ func UpdateMutatingWebhookCABundle(config *rest.Config, webhookConfigName string lw, ®.MutatingWebhookConfiguration{}, nil, - conditions...) + conditions..., + ) return err } @@ -213,7 +214,8 @@ func SyncMutatingWebhookCABundle(config *rest.Config, webhookConfigName string) default: return false, fmt.Errorf("unexpected event type: %v", event.Type) } - }) + }, + ) utilruntime.Must(err) }() return diff --git a/admissionregistration/v1beta1/validatingwebhookconfiguration.go b/admissionregistration/v1beta1/validatingwebhookconfiguration.go index 0d8f0155d..3283ae7f3 100644 --- a/admissionregistration/v1beta1/validatingwebhookconfiguration.go +++ b/admissionregistration/v1beta1/validatingwebhookconfiguration.go @@ -156,7 +156,8 @@ func UpdateValidatingWebhookCABundle(config *rest.Config, webhookConfigName stri }, }, extraConditions...) - _, err = watchtools.UntilWithSync(ctx, + _, err = watchtools.UntilWithSync( + ctx, lw, ®.ValidatingWebhookConfiguration{}, nil, @@ -213,7 +214,8 @@ func SyncValidatingWebhookCABundle(config *rest.Config, webhookConfigName string default: return false, fmt.Errorf("unexpected event type: %v", event.Type) } - }) + }, + ) utilruntime.Must(err) }() return diff --git a/conditions/merge_strategies_test.go b/conditions/merge_strategies_test.go index c6fa4306d..ee6cdcf40 100644 --- a/conditions/merge_strategies_test.go +++ b/conditions/merge_strategies_test.go @@ -28,7 +28,8 @@ import ( func TestGetStepCounterMessage(t *testing.T) { g := NewWithT(t) - groups := getConditionGroups(conditionsWithSource(&conditioned{}, + groups := getConditionGroups(conditionsWithSource( + &conditioned{}, nil1, true1, true1, falseInfo1, diff --git a/discovery/lib.go b/discovery/lib.go index dd425b63c..800504361 100644 --- a/discovery/lib.go +++ b/discovery/lib.go @@ -223,7 +223,8 @@ func IsDefaultSupportedVersion(kc kubernetes.Interface) error { kc, DefaultConstraint, DefaultBlackListedVersions, - DefaultBlackListedMultiMasterVersions) + DefaultBlackListedMultiMasterVersions, + ) } func IsSupportedVersion(kc kubernetes.Interface, constraint string, blackListedVersions map[string]error, blackListedMultiMasterVersions map[string]error) error { diff --git a/discovery/lib_test.go b/discovery/lib_test.go index f8311679f..f0188c43a 100644 --- a/discovery/lib_test.go +++ b/discovery/lib_test.go @@ -54,7 +54,8 @@ func TestDefaultSupportedVersion(t *testing.T) { tc.multiMaster, DefaultConstraint, DefaultBlackListedVersions, - DefaultBlackListedMultiMasterVersions) + DefaultBlackListedMultiMasterVersions, + ) if tc.err && err == nil { t.Fatalf("expected error for input: %s", tc.version) } else if !tc.err && err != nil { diff --git a/dynamic/kubernetes.go b/dynamic/kubernetes.go index 584cc112b..6be3a2113 100644 --- a/dynamic/kubernetes.go +++ b/dynamic/kubernetes.go @@ -115,7 +115,8 @@ func untilHasKey( }, } - _, err = watchtools.UntilWithSync(ctx, + _, err = watchtools.UntilWithSync( + ctx, lw, &unstructured.Unstructured{}, nil, diff --git a/meta/preconditions.go b/meta/preconditions.go index 5dddddb48..cf7d673d5 100644 --- a/meta/preconditions.go +++ b/meta/preconditions.go @@ -37,7 +37,8 @@ func (s PreConditionSet) PreconditionFunc() []mergepatch.PreconditionFunc { } for _, field := range sets.List[string](s.Set) { - preconditions = append(preconditions, + preconditions = append( + preconditions, RequireChainKeyUnchanged(field), ) } diff --git a/openapi/render.go b/openapi/render.go index 029eea2df..1730b06b4 100644 --- a/openapi/render.go +++ b/openapi/render.go @@ -86,7 +86,8 @@ func RenderOpenAPISpec(cfg Config) (string, error) { // TODO: keep the generic API server from wanting this unversioned := schema.GroupVersion{Group: "", Version: "v1"} - cfg.Scheme.AddUnversionedTypes(unversioned, + cfg.Scheme.AddUnversionedTypes( + unversioned, &metav1.Status{}, &metav1.APIVersions{}, &metav1.APIGroupList{}, diff --git a/tools/queue/handler.go b/tools/queue/handler.go index d69b34568..281afb39d 100644 --- a/tools/queue/handler.go +++ b/tools/queue/handler.go @@ -121,7 +121,7 @@ func NewReconcilableHandler(queue workqueue.TypedRateLimitingInterface[any], res return !meta_util.MustAlreadyReconciled(o) }, enqueueUpdate: func(old, nu any) bool { - return (nu.(metav1.Object)).GetDeletionTimestamp() != nil || !meta_util.MustAlreadyReconciled(nu) + return nu.(metav1.Object).GetDeletionTimestamp() != nil || !meta_util.MustAlreadyReconciled(nu) }, enqueueDelete: true, restrictToNamespace: restrictToNamespace,