Skip to content

Commit 25216f6

Browse files
Jefftreek8s-publishing-bot
authored andcommitted
Validate CABundle when writing CRD
Kubernetes-commit: a5791b344c04ded4f443c7e134242a29bd0e2bac
1 parent 3bbcc94 commit 25216f6

File tree

4 files changed

+710
-15
lines changed

4 files changed

+710
-15
lines changed

pkg/apis/apiextensions/validation/validation.go

Lines changed: 26 additions & 9 deletions
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)