@@ -28,7 +28,6 @@ import (
28
28
"unicode/utf8"
29
29
30
30
celgo "github.com/google/cel-go/cel"
31
-
32
31
"k8s.io/apiextensions-apiserver/pkg/apihelpers"
33
32
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
34
33
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@@ -94,6 +93,8 @@ func ValidateCustomResourceDefinition(ctx context.Context, obj *apiextensions.Cu
94
93
requireMapListKeysMapSetValidation : true ,
95
94
// strictCost is always true to enforce cost limits.
96
95
celEnvironmentSet : environment .MustBaseEnvSet (environment .DefaultCompatibilityVersion (), true ),
96
+ // allowInvalidCABundle is set to true since the CRD is not established yet.
97
+ allowInvalidCABundle : true ,
97
98
}
98
99
99
100
allErrs := genericvalidation .ValidateObjectMeta (& obj .ObjectMeta , false , nameValidationFn , field .NewPath ("metadata" ))
@@ -140,6 +141,9 @@ type validationOptions struct {
140
141
suppressPerExpressionCost bool
141
142
142
143
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
143
147
}
144
148
145
149
type preexistingExpressions struct {
@@ -233,7 +237,8 @@ func ValidateCustomResourceDefinitionUpdate(ctx context.Context, obj, oldObj *ap
233
237
preexistingExpressions : findPreexistingExpressions (& oldObj .Spec ),
234
238
versionsWithUnchangedSchemas : findVersionsWithUnchangedSchemas (obj , oldObj ),
235
239
// 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 ),
237
242
}
238
243
return validateCustomResourceDefinitionUpdate (ctx , obj , oldObj , opts )
239
244
}
@@ -485,7 +490,7 @@ func validateCustomResourceDefinitionSpec(ctx context.Context, spec *apiextensio
485
490
if (spec .Conversion != nil && spec .Conversion .Strategy != apiextensions .NoneConverter ) && (spec .PreserveUnknownFields == nil || * spec .PreserveUnknownFields ) {
486
491
allErrs = append (allErrs , field .Invalid (fldPath .Child ("conversion" ).Child ("strategy" ), spec .Conversion .Strategy , "must be None if spec.preserveUnknownFields is true" ))
487
492
}
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 )... )
489
494
490
495
return allErrs
491
496
}
@@ -545,6 +550,20 @@ func validateConversionReviewVersions(versions []string, requireRecognizedVersio
545
550
return allErrs
546
551
}
547
552
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
+
548
567
// hasValidConversionReviewVersion return true if there is a valid version or if the list is empty.
549
568
func hasValidConversionReviewVersionOrEmpty (versions []string ) bool {
550
569
if len (versions ) < 1 {
@@ -558,12 +577,7 @@ func hasValidConversionReviewVersionOrEmpty(versions []string) bool {
558
577
return false
559
578
}
560
579
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 {
567
581
allErrs := field.ErrorList {}
568
582
if conversion == nil {
569
583
return allErrs
@@ -582,6 +596,9 @@ func validateCustomResourceConversion(conversion *apiextensions.CustomResourceCo
582
596
case cc .Service != nil :
583
597
allErrs = append (allErrs , webhook .ValidateWebhookService (fldPath .Child ("webhookClientConfig" ).Child ("service" ), cc .Service .Name , cc .Service .Namespace , cc .Service .Path , cc .Service .Port )... )
584
598
}
599
+ if len (cc .CABundle ) > 0 && ! opts .allowInvalidCABundle {
600
+ allErrs = append (allErrs , webhook .ValidateCABundle (fldPath .Child ("webhookClientConfig" ).Child ("caBundle" ), cc .CABundle )... )
601
+ }
585
602
}
586
603
allErrs = append (allErrs , validateConversionReviewVersions (conversion .ConversionReviewVersions , requireRecognizedVersion , fldPath .Child ("conversionReviewVersions" ))... )
587
604
} else {
0 commit comments