From 780be878698d0e57d4c5a642470f3e131bf2b4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20B=C3=A4hler?= <26610571+oliverbaehler@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:55:57 +0200 Subject: [PATCH] fix: preserve ca-bundles injected from external providers (#1948) * fix: preserve ca-bundles injected from external providers (#1948) Signed-off-by: Oliver Baehler --- internal/controllers/admission/mutating.go | 55 ++++++++++++++++++-- internal/controllers/admission/validating.go | 55 ++++++++++++++++++-- internal/controllers/tls/utils.go | 9 +--- 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/internal/controllers/admission/mutating.go b/internal/controllers/admission/mutating.go index 0817b4de..d1f6302f 100644 --- a/internal/controllers/admission/mutating.go +++ b/internal/controllers/admission/mutating.go @@ -144,14 +144,27 @@ func (r *mutatingReconciler) reconcileConfiguration( obj.SetAnnotations(annotations) + // Preserve existing CA Information (cert-manager) + existingCABundles := mutatingWebhookCABundlesByName(obj.Webhooks) + obj.Webhooks = desiredHooks - caCert, err := tls.FetchCurrentCaBundleForAdmission(ctx, r.client, r.configuration, cfg.Client.CABundle) - if err != nil { - return err + var caCert []byte + + if r.configuration.EnableTLSConfiguration() { + caCert, err = tls.FetchCurrentCaBundleForAdmission(ctx, r.client, r.configuration) + if err != nil { + return err + } + } else { + caCert = cfg.Client.CABundle } - preserveMutatingWebhookCABundles(obj.Webhooks, caCert) + if len(caCert) > 0 { + preserveMutatingWebhookCABundles(obj.Webhooks, caCert) + } else { + restoreMutatingWebhookCABundles(obj.Webhooks, existingCABundles) + } return err }) @@ -222,10 +235,44 @@ func (r *mutatingReconciler) webhooks( return hooks, nil } +func mutatingWebhookCABundlesByName( + hooks []admissionv1.MutatingWebhook, +) map[string][]byte { + out := make(map[string][]byte, len(hooks)) + + for _, hook := range hooks { + if hook.Name == "" || len(hook.ClientConfig.CABundle) == 0 { + continue + } + + out[hook.Name] = append([]byte(nil), hook.ClientConfig.CABundle...) + } + + return out +} + +func restoreMutatingWebhookCABundles( + hooks []admissionv1.MutatingWebhook, + existingCABundles map[string][]byte, +) { + for i := range hooks { + existingCABundle := existingCABundles[hooks[i].Name] + if len(existingCABundle) == 0 { + continue + } + + hooks[i].ClientConfig.CABundle = append([]byte(nil), existingCABundle...) + } +} + func preserveMutatingWebhookCABundles( hooks []admissionv1.MutatingWebhook, caBundle []byte, ) { + if len(caBundle) == 0 { + return + } + for i := range hooks { hooks[i].ClientConfig.CABundle = append([]byte(nil), caBundle...) } diff --git a/internal/controllers/admission/validating.go b/internal/controllers/admission/validating.go index ed33a98f..22070e01 100644 --- a/internal/controllers/admission/validating.go +++ b/internal/controllers/admission/validating.go @@ -146,14 +146,27 @@ func (r *validatingReconciler) reconcileValidatingConfiguration( obj.SetAnnotations(annotations) + // Preserve existing CA Information (cert-manager) + existingCABundles := validatingWebhookCABundlesByName(obj.Webhooks) + obj.Webhooks = desiredHooks - caCert, err := tls.FetchCurrentCaBundleForAdmission(ctx, r.client, r.configuration, cfg.Client.CABundle) - if err != nil { - return err + var caCert []byte + + if r.configuration.EnableTLSConfiguration() { + caCert, err = tls.FetchCurrentCaBundleForAdmission(ctx, r.client, r.configuration) + if err != nil { + return err + } + } else { + caCert = cfg.Client.CABundle } - preserveValidatingWebhookCABundles(obj.Webhooks, caCert) + if len(caCert) > 0 { + preserveValidatingWebhookCABundles(obj.Webhooks, caCert) + } else { + restoreValidatingWebhookCABundles(obj.Webhooks, existingCABundles) + } return err }) @@ -224,10 +237,44 @@ func (r *validatingReconciler) validatingWebhooks( return hooks, nil } +func validatingWebhookCABundlesByName( + hooks []admissionv1.ValidatingWebhook, +) map[string][]byte { + out := make(map[string][]byte, len(hooks)) + + for _, hook := range hooks { + if hook.Name == "" || len(hook.ClientConfig.CABundle) == 0 { + continue + } + + out[hook.Name] = append([]byte(nil), hook.ClientConfig.CABundle...) + } + + return out +} + +func restoreValidatingWebhookCABundles( + hooks []admissionv1.ValidatingWebhook, + existingCABundles map[string][]byte, +) { + for i := range hooks { + existingCABundle := existingCABundles[hooks[i].Name] + if len(existingCABundle) == 0 { + continue + } + + hooks[i].ClientConfig.CABundle = append([]byte(nil), existingCABundle...) + } +} + func preserveValidatingWebhookCABundles( hooks []admissionv1.ValidatingWebhook, caBundle []byte, ) { + if len(caBundle) == 0 { + return + } + for i := range hooks { hooks[i].ClientConfig.CABundle = append([]byte(nil), caBundle...) } diff --git a/internal/controllers/tls/utils.go b/internal/controllers/tls/utils.go index 79adbeb6..f8c37309 100644 --- a/internal/controllers/tls/utils.go +++ b/internal/controllers/tls/utils.go @@ -141,13 +141,7 @@ func FetchCurrentCaBundleForAdmission( ctx context.Context, c client.Reader, cfg configuration.Configuration, - configuredCABundle []byte, ) ([]byte, error) { - // Explicit configuration wins. - if len(configuredCABundle) > 0 { - return append([]byte(nil), configuredCABundle...), nil - } - // Internal Capsule TLS enabled: source of truth is the TLS Secret. if cfg.EnableTLSConfiguration() { secret := &corev1.Secret{} @@ -175,7 +169,6 @@ func FetchCurrentCaBundleForAdmission( return append([]byte(nil), caBundle...), nil } - // cert-manager / external injector mode: - // return nil and preserve current webhook caBundle. + // TLS Controller not enabled return nil, nil }