You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(clusters): add generic kubeconfig-overrides annotation for ClusterKubeconfig - #2249
The kubeconfig controller fully overwrites ClusterKubeconfig.spec.kubeconfig on every reconcile (server URL + CA from the cluster secret, OIDC config from the org). Until now there was no way to override individual fields per cluster — needed e.g. for new-tenant OIDC setups.
This PR introduces greenhouse.sap/kubeconfig-overrides: an annotation on the Cluster resource that lets operators patch any kubeconfig field after the controller builds the spec.
Keys are dot-separated JSON field names matching the kubeconfig structure; use [0] for array entries (there is always exactly one cluster, user, and context).
Values can be either a plain JSON string or a {"secretRef": {"name": "…", "key": "…"}} object — the controller resolves secretRefs at reconcile time, keeping secrets out of the annotation.
Applied after the main spec patch, so it wins over greenhouse.sap/oidc-override on any overlapping field.
The existing greenhouse.sap/oidc-override annotation is kept for backwards compatibility.
Error handling
Condition
Reason
Annotation value is not valid JSON
OverrideResolveError
secretRef target secret / key does not exist
OverrideResolveError
Dot-path does not exist in the kubeconfig structure
OverrideError
k8s patch fails
OverridePatchError
Removing the bad annotation causes the controller to self-heal on the next reconcile.
Changes
api/well_known.go — new AnnotationKeyKubeconfigOverrides constant
internal/controller/cluster/kubeconfig_controller.go — resolveKubeconfigOverrides (secretRef + plain string resolution), applyKubeconfigOverrides (dot-path walker, now takes pre-resolved map), wired into Reconcile after the main spec patch
internal/controller/cluster/kubeconfig_controller_test.go — 4 new envtest specs covering OIDC field overrides, secretRef resolution (including missing-secret error), server URL override, and invalid-JSON error handling
Demo
Test plan
go build ./... passes
New envtest specs pass:
KUBEBUILDER_ASSETS=$(bin/setup-envtest use 1.36.0 -p path) \
go test ./internal/controller/cluster/ \
--ginkgo.focus="generic kubeconfig|secretRef values|ReconcileFailedCondition on invalid" \
--ginkgo.v --ginkgo.no-color -timeout 180s -v
Full ClusterKubeconfig suite (17 specs) passes with no regressions
json.Unmarshal silently ignores unknown object fields, so a typo such as clusters[0].cluster.serve is accepted, discarded during this decode, and reported as successfully applied instead of producing the documented OverrideError. Decode with unknown-field rejection; map entries under auth-provider.config will remain extensible because that node is a map.
Assert the invalid-JSON diagnostic after asynchronous reconciliation
This assertion can pass on the missing-secret condition left by the preceding ordered spec: deleting that annotation only schedules an asynchronous reconciliation, while both old and expected messages contain kubeconfig-overrides. Match the invalid-JSON diagnostic so this spec waits for and verifies its own reconciliation.
…erKubeconfig
Adds annotation greenhouse.sap/kubeconfig-overrides that accepts a flat
JSON object of dot-path → string overrides applied to the ClusterKubeconfig
spec after the controller builds it. This enables per-cluster overrides of
any kubeconfig field (server URL, CA, OIDC client-id/secret, issuer, namespace)
without requiring a new secret reference per field.
The existing greenhouse.sap/oidc-override annotation is kept for backwards
compatibility; the new annotation is applied after it and wins on conflict.
Closes#2248
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
…tation
Extends greenhouse.sap/kubeconfig-overrides so each value can be either
a plain JSON string or a {"secretRef": {"name": "...", "key": "..."}}
object. The controller resolves secretRefs at reconcile time via the
existing clientutil helper, keeping secrets out of the annotation itself.
A missing or unreadable secret sets KubeconfigReconcileFailedCondition
with reason OverrideResolveError so operators can identify the problem.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
…cile loops
Resolve overrides before CreateOrPatch and apply them inside the single
mutation closure so the controller writes one stable desired state. The
previous two-patch approach caused the ClusterKubeconfig watch to
re-enqueue the resource on every reconcile.
Also document the secretRef value form in the AnnotationKeyKubeconfigOverrides
constant comment.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
…s at API level
When resolvedOverrides participated in the desired spec and CreateOrPatch
fails at the Kubernetes API level, classify the failure as OverridePatchError
rather than the generic PatchError so operators can distinguish it from a
plain reconcile patch failure.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
…y reconcile
Contexts, CurrentContext, Kind, and APIVersion were only set during
initial creation. If an override wrote to those fields, removing the
annotation would leave the overridden values in place because the
mutation closure only rebuilt Clusters and AuthInfo.
Reset the complete baseline on every CreateOrPatch so that removing
greenhouse.sap/kubeconfig-overrides fully restores controller-managed values.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
The reason will be displayed to describe this comment to others. Learn more.
In my opinion Specing annotations with index and dot paths and merging them would be flaky.
This mirrors the drawbacks of ingress-nginx annotations sprawls and we should avoid it.
A declarative approach while verbose is a better fit due to strong typing and kubernetes CRD validation.
Example - A configOverrides in spec can be done the following way
…h strongly-typed Spec field
Move kubeconfig override configuration from a dot-path JSON annotation on
Cluster to a ClusterKubeconfigOverrides struct in ClusterKubeconfig.Spec.
This gives CRD validation, strong typing, and name-matched merging instead
of fragile index-based dot paths. Removes the greenhouse.sap/kubeconfig-overrides
and greenhouse.sap/oidc-override annotations entirely.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
Mark unused cluster parameter in getOIDCInfo as blank identifier and
run gofmt to fix struct field alignment in resolvedClusterOverride.
Signed-off-by: onuryilmaz <onur.yilmaz@sap.com>
The reason will be displayed to describe this comment to others. Learn more.
Replaced the annotation-based dot-path approach with the strongly-typed configOverrides spec field exactly as suggested — all types (ClusterKubeconfigOverrides, ClusterItemOverride, AuthInfoOverride, OIDCConfigOverride, ContextItemOverride) are implemented with name-matched merging. CreateOrPatch already handles early exits when nothing changes, so no additional go-cmp comparison is needed.
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
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.
Summary
Closes #2248.
The kubeconfig controller fully overwrites
ClusterKubeconfig.spec.kubeconfigon every reconcile (server URL + CA from the cluster secret, OIDC config from the org). Until now there was no way to override individual fields per cluster — needed e.g. for new-tenant OIDC setups.This PR introduces
greenhouse.sap/kubeconfig-overrides: an annotation on theClusterresource that lets operators patch any kubeconfig field after the controller builds the spec.Annotation format
[0]for array entries (there is always exactly one cluster, user, and context).{"secretRef": {"name": "…", "key": "…"}}object — the controller resolves secretRefs at reconcile time, keeping secrets out of the annotation.greenhouse.sap/oidc-overrideon any overlapping field.greenhouse.sap/oidc-overrideannotation is kept for backwards compatibility.Error handling
OverrideResolveErrorsecretReftarget secret / key does not existOverrideResolveErrorOverrideErrorOverridePatchErrorRemoving the bad annotation causes the controller to self-heal on the next reconcile.
Changes
api/well_known.go— newAnnotationKeyKubeconfigOverridesconstantinternal/controller/cluster/kubeconfig_controller.go—resolveKubeconfigOverrides(secretRef + plain string resolution),applyKubeconfigOverrides(dot-path walker, now takes pre-resolved map), wired intoReconcileafter the main spec patchinternal/controller/cluster/kubeconfig_controller_test.go— 4 new envtest specs covering OIDC field overrides, secretRef resolution (including missing-secret error), server URL override, and invalid-JSON error handlingDemo
Test plan
go build ./...passes