Skip to content

Commit 3cc0375

Browse files
✨ Add ability to control "EKS Auto Mode" for EKS clusters
Signed-off-by: Siarhei Rasiukevich <[email protected]>
1 parent e906ef4 commit 3cc0375

12 files changed

+1712
-100
lines changed

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2245,6 +2245,25 @@ spec:
22452245
description: AWSManagedControlPlaneSpec defines the desired state of an
22462246
Amazon EKS Cluster.
22472247
properties:
2248+
accessConfig:
2249+
description: |-
2250+
AccessConfig specifies the EKS cluster access configuration.
2251+
It defines the authentication mode and whether to bootstrap the cluster creator
2252+
as a cluster-admin.
2253+
properties:
2254+
authenticationMode:
2255+
description: |-
2256+
AuthenticationMode mode controls how Kubernetes API authentication is performed:
2257+
- CONFIG_MAP — uses only the aws-auth ConfigMap (legacy mode).
2258+
- API — uses only EKS Access Entries (aws-auth is ignored).
2259+
- API_AND_CONFIG_MAP — enables both Access Entries and aws-auth.
2260+
type: string
2261+
bootstrapAdminPermissions:
2262+
description: |-
2263+
BootstrapAdminPermissions specifies whether or not the cluster creator IAM principal was set as a cluster
2264+
admin access entry during cluster creation time.
2265+
type: boolean
2266+
type: object
22482267
additionalTags:
22492268
additionalProperties:
22502269
type: string
@@ -2298,6 +2317,27 @@ spec:
22982317
AssociateOIDCProvider can be enabled to automatically create an identity
22992318
provider for the controller for use with IAM roles for service accounts
23002319
type: boolean
2320+
autoMode:
2321+
description: AutoMode is the EKS Auto Mode.
2322+
properties:
2323+
compute:
2324+
description: Compute capability configuration for EKS Auto Mode.
2325+
properties:
2326+
nodePools:
2327+
items:
2328+
type: string
2329+
type: array
2330+
nodeRoleArn:
2331+
description: |-
2332+
NodeRoleArn the ARN of the IAM Role EKS will assign to EC2 Managed Instances in your EKS
2333+
Auto Mode cluster. This value cannot be changed after the compute capability of
2334+
EKS Auto Mode is enabled. For more information, see the IAM Reference in the
2335+
Amazon EKS User Guide.
2336+
type: string
2337+
type: object
2338+
enabled:
2339+
type: boolean
2340+
type: object
23012341
bastion:
23022342
description: Bastion contains options to configure the bastion host.
23032343
properties:

config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanetemplates.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,25 @@ spec:
5353
description: AWSManagedControlPlaneSpec defines the desired state
5454
of an Amazon EKS Cluster.
5555
properties:
56+
accessConfig:
57+
description: |-
58+
AccessConfig specifies the EKS cluster access configuration.
59+
It defines the authentication mode and whether to bootstrap the cluster creator
60+
as a cluster-admin.
61+
properties:
62+
authenticationMode:
63+
description: |-
64+
AuthenticationMode mode controls how Kubernetes API authentication is performed:
65+
- CONFIG_MAP — uses only the aws-auth ConfigMap (legacy mode).
66+
- API — uses only EKS Access Entries (aws-auth is ignored).
67+
- API_AND_CONFIG_MAP — enables both Access Entries and aws-auth.
68+
type: string
69+
bootstrapAdminPermissions:
70+
description: |-
71+
BootstrapAdminPermissions specifies whether or not the cluster creator IAM principal was set as a cluster
72+
admin access entry during cluster creation time.
73+
type: boolean
74+
type: object
5675
additionalTags:
5776
additionalProperties:
5877
type: string
@@ -107,6 +126,28 @@ spec:
107126
AssociateOIDCProvider can be enabled to automatically create an identity
108127
provider for the controller for use with IAM roles for service accounts
109128
type: boolean
129+
autoMode:
130+
description: AutoMode is the EKS Auto Mode.
131+
properties:
132+
compute:
133+
description: Compute capability configuration for EKS
134+
Auto Mode.
135+
properties:
136+
nodePools:
137+
items:
138+
type: string
139+
type: array
140+
nodeRoleArn:
141+
description: |-
142+
NodeRoleArn the ARN of the IAM Role EKS will assign to EC2 Managed Instances in your EKS
143+
Auto Mode cluster. This value cannot be changed after the compute capability of
144+
EKS Auto Mode is enabled. For more information, see the IAM Reference in the
145+
Amazon EKS User Guide.
146+
type: string
147+
type: object
148+
enabled:
149+
type: boolean
150+
type: object
110151
bastion:
111152
description: Bastion contains options to configure the bastion
112153
host.

controlplane/eks/api/v1beta1/conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ func (r *AWSManagedControlPlane) ConvertTo(dstRaw conversion.Hub) error {
121121
dst.Spec.RolePermissionsBoundary = restored.Spec.RolePermissionsBoundary
122122
dst.Status.Version = restored.Status.Version
123123
dst.Spec.BootstrapSelfManagedAddons = restored.Spec.BootstrapSelfManagedAddons
124+
dst.Spec.AccessConfig = restored.Spec.AccessConfig
125+
dst.Spec.AutoMode = restored.Spec.AutoMode
124126
return nil
125127
}
126128

controlplane/eks/api/v1beta1/zz_generated.conversion.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_types.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned
131131
// +optional
132132
IAMAuthenticatorConfig *IAMAuthenticatorConfig `json:"iamAuthenticatorConfig,omitempty"`
133133

134+
// AccessConfig specifies the EKS cluster access configuration.
135+
// It defines the authentication mode and whether to bootstrap the cluster creator
136+
// as a cluster-admin.
137+
// +optional
138+
AccessConfig AccessConfig `json:"accessConfig,omitempty"`
139+
134140
// Endpoints specifies access to this cluster's control plane endpoints
135141
// +optional
136142
EndpointAccess EndpointAccess `json:"endpointAccess,omitempty"`
@@ -200,7 +206,10 @@ type AWSManagedControlPlaneSpec struct { //nolint: maligned
200206
// bare EKS cluster without EKS default networking addons
201207
// If you set this value to false when creating a cluster, the default networking add-ons will not be installed
202208
// +kubebuilder:default=true
203-
BootstrapSelfManagedAddons bool `json:"bootstrapSelfManagedAddons,omitempty"`
209+
BootstrapSelfManagedAddons *bool `json:"bootstrapSelfManagedAddons,omitempty"`
210+
211+
// +optional
212+
AutoMode *AutoMode `json:"autoMode,omitempty"`
204213

205214
// RestrictPrivateSubnets indicates that the EKS control plane should only use private subnets.
206215
// +kubebuilder:default=false
@@ -221,6 +230,39 @@ type KubeProxy struct {
221230
Disable bool `json:"disable,omitempty"`
222231
}
223232

233+
// AccessConfig is the access configuration for the cluster.
234+
type AccessConfig struct {
235+
// AuthenticationMode mode controls how Kubernetes API authentication is performed:
236+
// - CONFIG_MAP — uses only the aws-auth ConfigMap (legacy mode).
237+
// - API — uses only EKS Access Entries (aws-auth is ignored).
238+
// - API_AND_CONFIG_MAP — enables both Access Entries and aws-auth.
239+
AuthenticationMode *string `json:"authenticationMode,omitempty"`
240+
241+
// BootstrapAdminPermissions specifies whether or not the cluster creator IAM principal was set as a cluster
242+
// admin access entry during cluster creation time.
243+
BootstrapAdminPermissions *bool `json:"bootstrapAdminPermissions,omitempty"`
244+
}
245+
246+
// AutoMode is the EKS Auto Mode.
247+
// allows to ootstrap cluster with aws compute, ebs, elb capability.
248+
type AutoMode struct {
249+
Enabled bool `json:"enabled,omitempty"`
250+
// Compute capability configuration for EKS Auto Mode.
251+
// +optional
252+
Compute Compute `json:"compute,omitempty"`
253+
}
254+
255+
// Compute allows to run compute capability with EKS AutoMode.
256+
type Compute struct {
257+
NodePools []string `json:"nodePools,omitempty"`
258+
// NodeRoleArn the ARN of the IAM Role EKS will assign to EC2 Managed Instances in your EKS
259+
// Auto Mode cluster. This value cannot be changed after the compute capability of
260+
// EKS Auto Mode is enabled. For more information, see the IAM Reference in the
261+
// Amazon EKS User Guide.
262+
// +optional
263+
NodeRoleArn *string `json:"nodeRoleArn,omitempty"`
264+
}
265+
224266
// VpcCni specifies configuration related to the VPC CNI.
225267
type VpcCni struct {
226268
// Disable indicates that the Amazon VPC CNI should be disabled. With EKS clusters the

controlplane/eks/api/v1beta2/awsmanagedcontrolplane_webhook.go

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
426520
func (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

Comments
 (0)