Skip to content

Backport: [webhook-handler] fix: patch crd conversion without dropping schema - #22870

Merged
deckhouse-BOaTswain merged 1 commit into
release-1.77from
cherry-pick-release-1.77-7edc20ba866d37e4c059efe6092a2cf69ef85d69
Sep 7, 2026
Merged

deckhouse-BOaTswain merged 1 commit into
release-1.77from
cherry-pick-release-1.77-7edc20ba866d37e4c059efe6092a2cf69ef85d69

Conversation

@deckhouse-BOaTswain

Copy link
Copy Markdown
Collaborator

Description

webhook-handler writes a CRD in three places, and all three sent the whole object back to the apiserver when the only field they meant to change was spec.conversion. Each one now issues a JSON Patch scoped to that single field:

Where When it runs
CrdClientConfig.PatchConversion (shell-operator) on every operator start and every hook reload, to register a conversion webhook
resetCRDConversionToNone (cmd/main.go) when a conversion hook disappears from disk
cleanupCRDConversion (internal/controller) when a ConversionWebhook resource is deleted

The registration path lives in shell-operator and is fixed by flant/shell-operator#930, which replaces the Get + full Update in CrdClientConfig with the same patch and renames the method UpdatePatchConversion so the call site says what it does. This PR bumps the dependency to v1.20.4 and follows the rename.

RBAC gains the patch verb on customresourcedefinitions — without it every call above fails with a 403.

The stored spec.conversion is identical to what the previous code produced. JSON Patch add replaces the whole subtree rather than merging into it, so a clientConfig.url left by an earlier registration is still removed, exactly as the old URL: nil assignment did.

No restarts of critical components: the only workload affected is webhook-handler in d8-system.

Why do we need it, and what problem does it solve?

Adding x-kubernetes-sensitive-data to a CRD that has a ConversionWebhook had 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 (the CRDSensitiveData feature adds XSensitiveData to JSONSchemaProps), but the upstream k8s.io/apiextensions-apiserver types every client vendors have no field for it. So a Get into apiextensionsv1.CustomResourceDefinition silently discards it — decoding into a Go struct ignores unknown keys, with no error and no warning — and the subsequent full Update
writes that truncated schema back. For the apiserver a PUT is 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-controller and webhook-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. managedFields shows it directly — the webhook-operator manager owns f:versions, and ownership on an Update is recorded only for fields whose value the request actually changed. Registering a conversion webhook has no business changing spec.versions at all.

Patching one field also removes the whole class of problem for any future schema extension this operator does not know about.

Checklist

  • The code is covered by unit tests.
  • e2e tests passed.
  • Documentation updated according to the changes.
  • Changes were tested in the Kubernetes cluster manually.

Changelog entries

section: deckhouse
type: fix
summary: Keep `x-kubernetes-sensitive-data` on CRDs that have a conversion webhook.
impact_level: low

…22814)

Signed-off-by: Ruslan Gorbunov <ruslan.gorbunov@flant.com>
@deckhouse-BOaTswain deckhouse-BOaTswain added this to the v1.77.1 milestone Sep 7, 2026
@deckhouse-BOaTswain
deckhouse-BOaTswain merged commit 08a56e1 into release-1.77 Sep 7, 2026
7 of 9 checks passed
@deckhouse-BOaTswain
deckhouse-BOaTswain deleted the cherry-pick-release-1.77-7edc20ba866d37e4c059efe6092a2cf69ef85d69 branch September 7, 2026 13:20
@github-actions github-actions Bot added type/dependencies Pull requests that update a dependency file go Pull requests that update Go code labels Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto backported go Pull requests that update Go code type/dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants