Skip to content

Commit 10c707f

Browse files
Merge pull request #124061 from Jefftree/conversion-webhook-invalidca
Validate CABundle when writing CRD Kubernetes-commit: 04d2f336419b5a824cb96cb88462ef18a90d619d
2 parents 3bbcc94 + f02b108 commit 10c707f

File tree

6 files changed

+722
-24
lines changed

6 files changed

+722
-24
lines changed

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ require (
2525
google.golang.org/protobuf v1.34.2
2626
gopkg.in/evanphx/json-patch.v4 v4.12.0
2727
gopkg.in/yaml.v2 v2.4.0
28-
k8s.io/api v0.0.0-20240722223049-b689d905290f
28+
k8s.io/api v0.0.0-20240723194852-871340c2e998
2929
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe
30-
k8s.io/apiserver v0.0.0-20240723030233-2b2a4b0fa8e4
31-
k8s.io/client-go v0.0.0-20240723023642-bad8f77ca6ef
30+
k8s.io/apiserver v0.0.0-20240723210659-c90207143c20
31+
k8s.io/client-go v0.0.0-20240723200359-dcfcc90795cc
3232
k8s.io/code-generator v0.0.0-20240720023521-ec3cc888df4c
3333
k8s.io/component-base v0.0.0-20240722183709-6cc953a9d440
3434
k8s.io/klog/v2 v2.130.1

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,14 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
365365
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
366366
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
367367
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
368-
k8s.io/api v0.0.0-20240722223049-b689d905290f h1:wtqzslJEcheiQ7hXjw1yGfqUyMCb7G4j72aL64Bzpbo=
369-
k8s.io/api v0.0.0-20240722223049-b689d905290f/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k=
368+
k8s.io/api v0.0.0-20240723194852-871340c2e998 h1:XvMrEqepRsNkn8Bl60PB5TO4ZEOgr70bYrpAedjvTV8=
369+
k8s.io/api v0.0.0-20240723194852-871340c2e998/go.mod h1:ytlEzqC2wOTwYET71W7+J+k7O2V7vrDuzmNLBSpgT+k=
370370
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe h1:V9MwpYUwbKlfLKVrhpVuKWiat/LBIhm1pGB9/xdHm5Q=
371371
k8s.io/apimachinery v0.0.0-20240720202316-95b78024e3fe/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
372-
k8s.io/apiserver v0.0.0-20240723030233-2b2a4b0fa8e4 h1:7nrffLiDUbMAXLKzBvyU8rwLHw5WpCw2AjhDO5IZYRs=
373-
k8s.io/apiserver v0.0.0-20240723030233-2b2a4b0fa8e4/go.mod h1:R1HYbPCD+ClvTmzeLBYaS4aktC3entK1o4hyD+WemtA=
374-
k8s.io/client-go v0.0.0-20240723023642-bad8f77ca6ef h1:+munBmXPvgGM5AFzdZh7Xe7S2LJ9udXYRfBDfm+0Eac=
375-
k8s.io/client-go v0.0.0-20240723023642-bad8f77ca6ef/go.mod h1:L1rDFyPUkmS0j6WXGYh5v/iWsfIFYH+LWnFOT1LCsf4=
372+
k8s.io/apiserver v0.0.0-20240723210659-c90207143c20 h1:32/qwZM293YJ71bcGQD2PhnPOLQBqQoDf6WvzQ/kpxI=
373+
k8s.io/apiserver v0.0.0-20240723210659-c90207143c20/go.mod h1:NQDM9jV7nUGYBnMcr1Wm1zo17QIrCW1RWoD1kcuH/80=
374+
k8s.io/client-go v0.0.0-20240723200359-dcfcc90795cc h1:qe0SREEjfE5w3ANvrSURWv00J/ISlqa9Sa3FCBYKRlg=
375+
k8s.io/client-go v0.0.0-20240723200359-dcfcc90795cc/go.mod h1:XfEsPNNFOR0wNkr3BtkPUN668l7Sx1W4ECSUolQ0mA4=
376376
k8s.io/code-generator v0.0.0-20240720023521-ec3cc888df4c h1:oiNPH9Y/YrQfxo8eTW/w71aBrSyr9MX/wGBKTwDSZsc=
377377
k8s.io/code-generator v0.0.0-20240720023521-ec3cc888df4c/go.mod h1:TVAwbna2B36D+IsWJ5oHqKZKSU8ZBtxeiMTb7uKM6Z0=
378378
k8s.io/component-base v0.0.0-20240722183709-6cc953a9d440 h1:14X+5sRQRsul6tLxIKTP0/DotvWlMd9DFCgMqHP1hZY=

pkg/apis/apiextensions/validation/validation.go

+26-9
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
"unicode/utf8"
2929

3030
celgo "github.com/google/cel-go/cel"
31-
3231
"k8s.io/apiextensions-apiserver/pkg/apihelpers"
3332
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
3433
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -94,6 +93,8 @@ func ValidateCustomResourceDefinition(ctx context.Context, obj *apiextensions.Cu
9493
requireMapListKeysMapSetValidation: true,
9594
// strictCost is always true to enforce cost limits.
9695
celEnvironmentSet: environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true),
96+
// allowInvalidCABundle is set to true since the CRD is not established yet.
97+
allowInvalidCABundle: true,
9798
}
9899

99100
allErrs := genericvalidation.ValidateObjectMeta(&obj.ObjectMeta, false, nameValidationFn, field.NewPath("metadata"))
@@ -140,6 +141,9 @@ type validationOptions struct {
140141
suppressPerExpressionCost bool
141142

142143
celEnvironmentSet *environment.EnvSet
144+
// allowInvalidCABundle allows an invalid conversion webhook CABundle on update only if the existing CABundle is invalid.
145+
// An invalid CABundle is also permitted on create and before a CRD is in an Established=True condition.
146+
allowInvalidCABundle bool
143147
}
144148

145149
type preexistingExpressions struct {
@@ -233,7 +237,8 @@ func ValidateCustomResourceDefinitionUpdate(ctx context.Context, obj, oldObj *ap
233237
preexistingExpressions: findPreexistingExpressions(&oldObj.Spec),
234238
versionsWithUnchangedSchemas: findVersionsWithUnchangedSchemas(obj, oldObj),
235239
// strictCost is always true to enforce cost limits.
236-
celEnvironmentSet: environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true),
240+
celEnvironmentSet: environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true),
241+
allowInvalidCABundle: allowInvalidCABundle(oldObj),
237242
}
238243
return validateCustomResourceDefinitionUpdate(ctx, obj, oldObj, opts)
239244
}
@@ -485,7 +490,7 @@ func validateCustomResourceDefinitionSpec(ctx context.Context, spec *apiextensio
485490
if (spec.Conversion != nil && spec.Conversion.Strategy != apiextensions.NoneConverter) && (spec.PreserveUnknownFields == nil || *spec.PreserveUnknownFields) {
486491
allErrs = append(allErrs, field.Invalid(fldPath.Child("conversion").Child("strategy"), spec.Conversion.Strategy, "must be None if spec.preserveUnknownFields is true"))
487492
}
488-
allErrs = append(allErrs, validateCustomResourceConversion(spec.Conversion, opts.requireRecognizedConversionReviewVersion, fldPath.Child("conversion"))...)
493+
allErrs = append(allErrs, validateCustomResourceConversion(spec.Conversion, opts.requireRecognizedConversionReviewVersion, fldPath.Child("conversion"), opts)...)
489494

490495
return allErrs
491496
}
@@ -545,6 +550,20 @@ func validateConversionReviewVersions(versions []string, requireRecognizedVersio
545550
return allErrs
546551
}
547552

553+
// Allows invalid CA Bundle to be specified only if the existing CABundle is invalid
554+
// or if the CRD is not established yet.
555+
func allowInvalidCABundle(oldCRD *apiextensions.CustomResourceDefinition) bool {
556+
if !apiextensions.IsCRDConditionTrue(oldCRD, apiextensions.Established) {
557+
return true
558+
}
559+
oldConversion := oldCRD.Spec.Conversion
560+
if oldConversion == nil || oldConversion.WebhookClientConfig == nil ||
561+
len(oldConversion.WebhookClientConfig.CABundle) == 0 {
562+
return false
563+
}
564+
return len(webhook.ValidateCABundle(field.NewPath("caBundle"), oldConversion.WebhookClientConfig.CABundle)) > 0
565+
}
566+
548567
// hasValidConversionReviewVersion return true if there is a valid version or if the list is empty.
549568
func hasValidConversionReviewVersionOrEmpty(versions []string) bool {
550569
if len(versions) < 1 {
@@ -558,12 +577,7 @@ func hasValidConversionReviewVersionOrEmpty(versions []string) bool {
558577
return false
559578
}
560579

561-
// ValidateCustomResourceConversion statically validates
562-
func ValidateCustomResourceConversion(conversion *apiextensions.CustomResourceConversion, fldPath *field.Path) field.ErrorList {
563-
return validateCustomResourceConversion(conversion, true, fldPath)
564-
}
565-
566-
func validateCustomResourceConversion(conversion *apiextensions.CustomResourceConversion, requireRecognizedVersion bool, fldPath *field.Path) field.ErrorList {
580+
func validateCustomResourceConversion(conversion *apiextensions.CustomResourceConversion, requireRecognizedVersion bool, fldPath *field.Path, opts validationOptions) field.ErrorList {
567581
allErrs := field.ErrorList{}
568582
if conversion == nil {
569583
return allErrs
@@ -582,6 +596,9 @@ func validateCustomResourceConversion(conversion *apiextensions.CustomResourceCo
582596
case cc.Service != nil:
583597
allErrs = append(allErrs, webhook.ValidateWebhookService(fldPath.Child("webhookClientConfig").Child("service"), cc.Service.Name, cc.Service.Namespace, cc.Service.Path, cc.Service.Port)...)
584598
}
599+
if len(cc.CABundle) > 0 && !opts.allowInvalidCABundle {
600+
allErrs = append(allErrs, webhook.ValidateCABundle(fldPath.Child("webhookClientConfig").Child("caBundle"), cc.CABundle)...)
601+
}
585602
}
586603
allErrs = append(allErrs, validateConversionReviewVersions(conversion.ConversionReviewVersions, requireRecognizedVersion, fldPath.Child("conversionReviewVersions"))...)
587604
} else {

0 commit comments

Comments
 (0)