@@ -22,9 +22,12 @@ import (
2222 "net"
2323
2424 "github.com/apparentlymart/go-cidr/cidr"
25+ "github.com/aws/aws-sdk-go-v2/aws"
26+ ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types"
2527 "github.com/pkg/errors"
2628 apierrors "k8s.io/apimachinery/pkg/api/errors"
2729 "k8s.io/apimachinery/pkg/runtime"
30+ "k8s.io/apimachinery/pkg/util/sets"
2831 "k8s.io/apimachinery/pkg/util/validation/field"
2932 "k8s.io/apimachinery/pkg/util/version"
3033 "k8s.io/klog/v2"
@@ -52,6 +55,9 @@ const (
5255 cidrSizeMin = 16
5356 vpcCniAddon = "vpc-cni"
5457 kubeProxyAddon = "kube-proxy"
58+
59+ autoModeComputeNodePoolSystem = "system"
60+ autoModeComputeNodePoolGeneral = "general-purpose"
5561)
5662
5763// SetupWebhookWithManager will setup the webhooks for the AWSManagedControlPlane.
@@ -102,6 +108,8 @@ func (*awsManagedControlPlaneWebhook) ValidateCreate(_ context.Context, obj runt
102108 allErrs = append (allErrs , r .validateSecondaryCIDR ()... )
103109 allErrs = append (allErrs , r .validateEKSAddons ()... )
104110 allErrs = append (allErrs , r .validateDisableVPCCNI ()... )
111+ allErrs = append (allErrs , r .validateAccessConfig (nil )... )
112+ allErrs = append (allErrs , r .validateAutoMode (nil )... )
105113 allErrs = append (allErrs , r .validateRestrictPrivateSubnets ()... )
106114 allErrs = append (allErrs , r .validateKubeProxy ()... )
107115 allErrs = append (allErrs , r .Spec .AdditionalTags .Validate ()... )
@@ -142,6 +150,8 @@ func (*awsManagedControlPlaneWebhook) ValidateUpdate(ctx context.Context, oldObj
142150 allErrs = append (allErrs , r .Spec .Bastion .Validate ()... )
143151 allErrs = append (allErrs , r .validateIAMAuthConfig ()... )
144152 allErrs = append (allErrs , r .validateSecondaryCIDR ()... )
153+ allErrs = append (allErrs , r .validateAccessConfig (oldAWSManagedControlplane )... )
154+ allErrs = append (allErrs , r .validateAutoMode (oldAWSManagedControlplane )... )
145155 allErrs = append (allErrs , r .validateEKSAddons ()... )
146156 allErrs = append (allErrs , r .validateDisableVPCCNI ()... )
147157 allErrs = append (allErrs , r .validateRestrictPrivateSubnets ()... )
@@ -423,6 +433,90 @@ func validateDisableVPCCNI(vpcCni VpcCni, addons *[]Addon, path *field.Path) fie
423433 return allErrs
424434}
425435
436+ func (r * AWSManagedControlPlane ) validateAccessConfig (old * AWSManagedControlPlane ) field.ErrorList {
437+ return validateAccessConfig (r .Spec .AccessConfig , old , field .NewPath ("spec" , "accessConfig" ))
438+ }
439+
440+ func validateAccessConfig (accessConfig AccessConfig , old * AWSManagedControlPlane , path * field.Path ) field.ErrorList {
441+ var (
442+ allErrs field.ErrorList
443+ authModeOK bool
444+ )
445+
446+ authConfigField := path .Child ("authenticationMode" )
447+
448+ for _ , accessMode := range ekstypes .AuthenticationMode ("" ).Values () {
449+ if ekstypes .AuthenticationMode (* accessConfig .AuthenticationMode ) == accessMode {
450+ authModeOK = true
451+ }
452+ }
453+
454+ if ! authModeOK {
455+ allErrs = append (allErrs , field .Invalid (authConfigField , * accessConfig .AuthenticationMode , "unsupported authenticationMode provided" ))
456+ }
457+
458+ if old != nil {
459+ if * old .Spec .AccessConfig .AuthenticationMode != * accessConfig .AuthenticationMode {
460+ if ekstypes .AuthenticationMode (* accessConfig .AuthenticationMode ) == ekstypes .AuthenticationModeConfigMap {
461+ allErrs = append (allErrs , field .Invalid (authConfigField , * accessConfig .AuthenticationMode , "cannot switch authenticationMode to legacy CONFIG_MAP mode" ))
462+ }
463+ }
464+ }
465+
466+ if * accessConfig .BootstrapAdminPermissions && ekstypes .AuthenticationMode (* accessConfig .AuthenticationMode ) == ekstypes .AuthenticationModeConfigMap {
467+ authConfigField := path .Child ("bootstrapAdminPermissions" )
468+ allErrs = append (allErrs , field .Invalid (authConfigField , * accessConfig .BootstrapAdminPermissions , "authenticationMode CONFIG_MAP has no effect with the bootstrapAdminPermissions parameter" ))
469+ }
470+
471+ return allErrs
472+ }
473+
474+ func (r * AWSManagedControlPlane ) validateAutoMode (old * AWSManagedControlPlane ) field.ErrorList {
475+ return validateAutoMode (r .Spec , old , field .NewPath ("spec" ))
476+ }
477+
478+ func validateAutoMode (spec AWSManagedControlPlaneSpec , old * AWSManagedControlPlane , path * field.Path ) field.ErrorList {
479+ var allErrs field.ErrorList
480+
481+ if spec .AutoMode == nil {
482+ return nil
483+ }
484+
485+ if spec .AutoMode .Enabled {
486+ // EKS Auto mode is not compatible with configmap AuthenticationMode.
487+ if * spec .AccessConfig .AuthenticationMode == string (ekstypes .AuthenticationModeConfigMap ) {
488+ authConfigField := path .Child ("accessConfig" , "authenticationMode" )
489+ allErrs = append (allErrs , field .Invalid (authConfigField , spec .AccessConfig .AuthenticationMode , "authenticationMode CONFIG_MAP couldn't be used with autoMode" ))
490+ }
491+
492+ if old != nil {
493+ // nodeRoleArn cannot be changed after the compute capability of EKS Auto Mode is enabled.
494+ if old .Spec .AutoMode .Compute .NodeRoleArn != spec .AutoMode .Compute .NodeRoleArn {
495+ nodeRoleArnField := path .Child ("autoMode" , "compute" , "nodeRoleArn" )
496+ allErrs = append (allErrs , field .Invalid (nodeRoleArnField , spec .AutoMode .Compute .NodeRoleArn , "nodeRoleArn could not be changed" ))
497+ }
498+ }
499+
500+ if len (spec .AutoMode .Compute .NodePools ) > 0 {
501+ // nodeRoleArn should be always defined with node pools.
502+ if spec .AutoMode .Compute .NodeRoleArn == nil {
503+ nodeRoleArnField := path .Child ("autoMode" , "compute" , "nodeRoleArn" )
504+ allErrs = append (allErrs , field .Invalid (nodeRoleArnField , spec .AutoMode .Compute .NodeRoleArn , "nodeRoleArn is required when nodePools specified" ))
505+ }
506+
507+ allowedPoolNames := sets .New [string ](autoModeComputeNodePoolSystem , autoModeComputeNodePoolGeneral )
508+ for _ , poolName := range spec .AutoMode .Compute .NodePools {
509+ nodePoolsField := path .Child ("autoMode" , "compute" , "nodePools" )
510+ if ! allowedPoolNames .Has (poolName ) {
511+ allErrs = append (allErrs , field .Invalid (nodePoolsField , poolName , "nodePools contains an invalid pool" ))
512+ }
513+ }
514+ }
515+ }
516+
517+ return allErrs
518+ }
519+
426520func (r * AWSManagedControlPlane ) validateRestrictPrivateSubnets () field.ErrorList {
427521 return validateRestrictPrivateSubnets (r .Spec .RestrictPrivateSubnets , r .Spec .NetworkSpec , r .Spec .EKSClusterName , field .NewPath ("spec" ))
428522}
@@ -568,10 +662,16 @@ func (*awsManagedControlPlaneWebhook) Default(_ context.Context, obj runtime.Obj
568662 }
569663 }
570664
665+ if r .Spec .BootstrapSelfManagedAddons == nil {
666+ r .Spec .BootstrapSelfManagedAddons = aws .Bool (true )
667+ }
668+
669+ if r .Spec .AccessConfig .AuthenticationMode == nil {
670+ r .Spec .AccessConfig .AuthenticationMode = aws .String (string (ekstypes .AuthenticationModeConfigMap ))
671+ }
672+
571673 infrav1 .SetDefaults_Bastion (& r .Spec .Bastion )
572674 infrav1 .SetDefaults_NetworkSpec (& r .Spec .NetworkSpec )
573675
574- // Set default value for BootstrapSelfManagedAddons
575- r .Spec .BootstrapSelfManagedAddons = true
576676 return nil
577677}
0 commit comments