Backport: [webhook-handler] fix: patch crd conversion without dropping schema - #22870
Merged
deckhouse-BOaTswain merged 1 commit intoSep 7, 2026
Conversation
…22814) Signed-off-by: Ruslan Gorbunov <ruslan.gorbunov@flant.com>
deckhouse-BOaTswain
deleted the
cherry-pick-release-1.77-7edc20ba866d37e4c059efe6092a2cf69ef85d69
branch
September 7, 2026 13:20
4 tasks
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.
Description
webhook-handlerwrites a CRD in three places, and all three sent the whole object back to the apiserver when the only field they meant to change wasspec.conversion. Each one now issues a JSON Patch scoped to that single field:CrdClientConfig.PatchConversion(shell-operator)resetCRDConversionToNone(cmd/main.go)cleanupCRDConversion(internal/controller)ConversionWebhookresource is deletedThe registration path lives in shell-operator and is fixed by flant/shell-operator#930, which replaces the
Get+ fullUpdateinCrdClientConfigwith the same patch and renames the methodUpdate→PatchConversionso the call site says what it does. This PR bumps the dependency tov1.20.4and follows the rename.RBAC gains the
patchverb oncustomresourcedefinitions— without it every call above fails with a 403.The stored
spec.conversionis identical to what the previous code produced. JSON Patchaddreplaces the whole subtree rather than merging into it, so aclientConfig.urlleft by an earlier registration is still removed, exactly as the oldURL: nilassignment did.No restarts of critical components: the only workload affected is
webhook-handlerind8-system.Why do we need it, and what problem does it solve?
Adding
x-kubernetes-sensitive-datato a CRD that has aConversionWebhookhad no effect: the marker was present in the module's manifest and applied to the cluster, then vanished a few seconds later. The same marker on a CRD without a conversion webhook worked fine.The marker is served by the apiserver as part of
openAPIV3Schema(theCRDSensitiveDatafeature addsXSensitiveDatatoJSONSchemaProps), but the upstreamk8s.io/apiextensions-apiservertypes every client vendors have no field for it. So aGetintoapiextensionsv1.CustomResourceDefinitionsilently discards it — decoding into a Go struct ignores unknown keys, with no error and no warning — and the subsequent fullUpdatewrites that truncated schema back. For the apiserver a
PUTis the complete desired state, so a key missing from the request means "delete it".The consequence is not cosmetic: fields marked sensitive stop being encrypted at rest in etcd, stop being filtered by RBAC on
get/list/watch, and stop being masked in audit logs. Credentials that the module declared sensitive — registry passwords, Grafana datasource passwords — are silently stored and served in plain text.This is deterministic, not a race between
deckhouse-controllerandwebhook-handler. Ordering does not decide the outcome: whoever writes the truncated object wins whenever it writes, and it writes on every operator start and on every hook reload.managedFieldsshows it directly — thewebhook-operatormanager ownsf:versions, and ownership on anUpdateis recorded only for fields whose value the request actually changed. Registering a conversion webhook has no business changingspec.versionsat all.Patching one field also removes the whole class of problem for any future schema extension this operator does not know about.
Checklist
Changelog entries