aws-cdk.aws-eks-v2-alpha 2.239.0a0
The CDK Construct Library for AWS::EKS
License: Apache-2.0
Requires Python: ~=3.9

# Amazon EKS V2 Construct Library

<!--BEGIN STABILITY BANNER-->---


![cdk-constructs: Developer Preview](https://img.shields.io/badge/cdk--constructs-developer--preview-informational.svg?style=for-the-badge)

> The APIs of higher level constructs in this module are in **developer preview** before they
> become stable. We will only make breaking changes to address unforeseen API issues. Therefore,
> these APIs are not subject to [Semantic Versioning](https://semver.org/), and breaking changes
> will be announced in release notes. This means that while you may use them, you may need to
> update your source code when upgrading to a newer version of this package.

---
<!--END STABILITY BANNER-->

The eks-v2-alpha module is a rewrite of the existing aws-eks module (https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_eks-readme.html). This new iteration leverages native L1 CFN resources, replacing the previous custom resource approach for creating EKS clusters and Fargate Profiles.

Compared to the original EKS module, it has the following major changes:

* Use native L1 AWS::EKS::Cluster resource to replace custom resource Custom::AWSCDK-EKS-Cluster
* Use native L1 AWS::EKS::FargateProfile resource to replace custom resource Custom::AWSCDK-EKS-FargateProfile
* Kubectl Handler will not be created by default. It will only be created if users specify it.
* Remove AwsAuth construct. Permissions to the cluster will be managed by Access Entry.
* Remove the limit of 1 cluster per stack
* Remove nested stacks
* API changes to make them more ergonomic.

## Quick start

Here is the minimal example of defining an AWS EKS cluster

```python
cluster = eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34
)
```

## Architecture

```text                                             +-----------------+
                                         kubectl    |                 |
                                      +------------>| Kubectl Handler |
                                      |             |   (Optional)    |
                                      |             +-----------------+
+-------------------------------------+-------------------------------------+
|                        EKS Cluster (Auto Mode)                            |
|                          AWS::EKS::Cluster                                |
|                                                                           |
|  +---------------------------------------------------------------------+  |
|  |           Auto Mode Compute (Managed by EKS) (Default)              |  |
|  |                                                                     |  |
|  |  - Automatically provisions EC2 instances                           |  |
|  |  - Auto scaling based on pod requirements                           |  |
|  |  - No manual node group configuration needed                        |  |
|  |                                                                     |  |
|  +---------------------------------------------------------------------+  |
|                                                                           |
+---------------------------------------------------------------------------+
```

In a nutshell:

* **[Auto Mode](#eks-auto-mode)** (Default) – The fully managed capacity mode in EKS.
  EKS automatically provisions and scales  EC2 capacity based on pod requirements.
  It manages internal *system* and *general-purpose* NodePools, handles networking and storage setup, and removes the need for user-managed node groups or Auto Scaling Groups.

  ```python
  cluster = eks.Cluster(self, "AutoModeCluster",
      version=eks.KubernetesVersion.V1_34
  )
  ```
* **[Managed Node Groups](#managed-node-groups)** – The semi-managed capacity mode.
  EKS provisions and manages EC2 nodes on your behalf but you configure the instance types, scaling ranges, and update strategy.
  AWS handles node health, draining, and rolling updates while you retain control over scaling and cost optimization.

  You can also define *Fargate Profiles* that determine which pods or namespaces run on Fargate infrastructure.

  ```python
  cluster = eks.Cluster(self, "ManagedNodeCluster",
      version=eks.KubernetesVersion.V1_34,
      default_capacity_type=eks.DefaultCapacityType.NODEGROUP
  )

  # Add a Fargate Profile for specific workloads (e.g., default namespace)
  cluster.add_fargate_profile("FargateProfile",
      selectors=[eks.Selector(namespace="default")
      ]
  )
  ```
* **[Fargate Mode](#fargate-profiles)** – The Fargate capacity mode.
  EKS runs your pods directly on AWS Fargate without provisioning EC2 nodes.

  ```python
  cluster = eks.FargateCluster(self, "FargateCluster",
      version=eks.KubernetesVersion.V1_34
  )
  ```
* **[Self-Managed Nodes](#self-managed-capacity)** – The fully manual capacity mode.
  You create and manage EC2 instances (via an Auto Scaling Group) and connect them to the cluster manually.
  This provides maximum flexibility for custom AMIs or configurations but also the highest operational overhead.

  ```python
  cluster = eks.Cluster(self, "SelfManagedCluster",
      version=eks.KubernetesVersion.V1_34
  )

  # Add self-managed Auto Scaling Group
  cluster.add_auto_scaling_group_capacity("self-managed-asg",
      instance_type=ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
      min_capacity=1,
      max_capacity=5
  )
  ```
* **[Kubectl Handler](#kubectl-support) (Optional)** – A Lambda-backed custom resource created by the AWS CDK to execute `kubectl` commands (like `apply` or `patch`) during deployment.
  Regardless of the capacity mode, this handler may still be created to apply Kubernetes manifests as part of CDK provisioning.

## Provisioning cluster

Creating a new cluster is done using the `Cluster` constructs. The only required property is the kubernetes version.

```python
eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34
)
```

You can also use `FargateCluster` to provision a cluster that uses only fargate workers.

```python
eks.FargateCluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34
)
```

**Note: Unlike the previous EKS cluster, `Kubectl Handler` will not
be created by default. It will only be deployed when `kubectlProviderOptions`
property is used.**

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl")
    )
)
```

### EKS Auto Mode

[Amazon EKS Auto Mode](https://aws.amazon.com/eks/auto-mode/) extends AWS management of Kubernetes clusters beyond the cluster itself, allowing AWS to set up and manage the infrastructure that enables the smooth operation of your workloads.

#### Using Auto Mode

While `aws-eks` uses `DefaultCapacityType.NODEGROUP` by default, `aws-eks-v2` uses `DefaultCapacityType.AUTOMODE` as the default capacity type.

Auto Mode is enabled by default when creating a new cluster without specifying any capacity-related properties:

```python
# Create EKS cluster with Auto Mode implicitly enabled
cluster = eks.Cluster(self, "EksAutoCluster",
    version=eks.KubernetesVersion.V1_34
)
```

You can also explicitly enable Auto Mode using `defaultCapacityType`:

```python
# Create EKS cluster with Auto Mode explicitly enabled
cluster = eks.Cluster(self, "EksAutoCluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.AUTOMODE
)
```

#### Node Pools

When Auto Mode is enabled, the cluster comes with two default node pools:

* `system`: For running system components and add-ons
* `general-purpose`: For running your application workloads

These node pools are managed automatically by EKS. You can configure which node pools to enable through the `compute` property:

```python
cluster = eks.Cluster(self, "EksAutoCluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.AUTOMODE,
    compute=eks.ComputeConfig(
        node_pools=["system", "general-purpose"]
    )
)
```

For more information, see [Create a Node Pool for EKS Auto Mode](https://docs.aws.amazon.com/eks/latest/userguide/create-node-pool.html).

#### Disabling Default Node Pools

You can disable the default node pools entirely by setting an empty array for `nodePools`. This is useful when you want to use Auto Mode features but manage your compute resources separately:

```python
cluster = eks.Cluster(self, "EksAutoCluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.AUTOMODE,
    compute=eks.ComputeConfig(
        node_pools=[]
    )
)
```

When node pools are disabled this way, no IAM role will be created for the node pools, preventing deployment failures that would otherwise occur when a role is created without any node pools.

### Node Groups as the default capacity type

If you prefer to manage your own node groups instead of using Auto Mode, you can use the traditional node group approach by specifying `defaultCapacityType` as `NODEGROUP`:

```python
# Create EKS cluster with traditional managed node group
cluster = eks.Cluster(self, "EksCluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.NODEGROUP,
    default_capacity=3,  # Number of instances
    default_capacity_instance=ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.LARGE)
)
```

You can also create a cluster with no initial capacity and add node groups later:

```python
cluster = eks.Cluster(self, "EksCluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.NODEGROUP,
    default_capacity=0
)

# Add node groups as needed
cluster.add_nodegroup_capacity("custom-node-group",
    min_size=1,
    max_size=3,
    instance_types=[ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.LARGE)]
)
```

Read [Managed node groups](#managed-node-groups) for more information on how to add node groups to the cluster.

### Mixed with Auto Mode and Node Groups

You can combine Auto Mode with traditional node groups for specific workload requirements:

```python
cluster = eks.Cluster(self, "Cluster",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.AUTOMODE,
    compute=eks.ComputeConfig(
        node_pools=["system", "general-purpose"]
    )
)

# Add specialized node group for specific workloads
cluster.add_nodegroup_capacity("specialized-workload",
    min_size=1,
    max_size=3,
    instance_types=[ec2.InstanceType.of(ec2.InstanceClass.C5, ec2.InstanceSize.XLARGE)],
    labels={
        "workload": "specialized"
    }
)
```

### Important Notes

1. Auto Mode and traditional capacity management are mutually exclusive at the default capacity level. You cannot opt in to Auto Mode and specify `defaultCapacity` or `defaultCapacityInstance`.
2. When Auto Mode is enabled:

   * The cluster will automatically manage compute resources
   * Node pools cannot be modified, only enabled or disabled
   * EKS will handle scaling and management of the node pools
3. Auto Mode requires specific IAM permissions. The construct will automatically attach the required managed policies.

### Managed node groups

Amazon EKS managed node groups automate the provisioning and lifecycle management of nodes (Amazon EC2 instances) for Amazon EKS Kubernetes clusters.
With Amazon EKS managed node groups, you don't need to separately provision or register the Amazon EC2 instances that provide compute capacity to run your Kubernetes applications. You can create, update, or terminate nodes for your cluster with a single operation. Nodes run using the latest Amazon EKS optimized AMIs in your AWS account while node updates and terminations gracefully drain nodes to ensure that your applications stay available.

> For more details visit [Amazon EKS Managed Node Groups](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html).

By default, when using `DefaultCapacityType.NODEGROUP`, this library will allocate a managed node group with 2 *m5.large* instances (this instance type suits most common use-cases, and is good value for money).

```python
eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.NODEGROUP
)
```

At cluster instantiation time, you can customize the number of instances and their type:

```python
eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.NODEGROUP,
    default_capacity=5,
    default_capacity_instance=ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.SMALL)
)
```

To access the node group that was created on your behalf, you can use `cluster.defaultNodegroup`.

Additional customizations are available post instantiation. To apply them, set the default capacity to 0, and use the `cluster.addNodegroupCapacity` method:

```python
cluster = eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    default_capacity_type=eks.DefaultCapacityType.NODEGROUP,
    default_capacity=0
)

cluster.add_nodegroup_capacity("custom-node-group",
    instance_types=[ec2.InstanceType("m5.large")],
    min_size=4,
    disk_size=100
)
```

### Fargate profiles

AWS Fargate is a technology that provides on-demand, right-sized compute
capacity for containers. With AWS Fargate, you no longer have to provision,
configure, or scale groups of virtual machines to run containers. This removes
the need to choose server types, decide when to scale your node groups, or
optimize cluster packing.

You can control which pods start on Fargate and how they run with Fargate
Profiles, which are defined as part of your Amazon EKS cluster.

See [Fargate Considerations](https://docs.aws.amazon.com/eks/latest/userguide/fargate.html#fargate-considerations) in the AWS EKS User Guide.

You can add Fargate Profiles to any EKS cluster defined in your CDK app
through the `addFargateProfile()` method. The following example adds a profile
that will match all pods from the "default" namespace:

```python
# cluster: eks.Cluster

cluster.add_fargate_profile("MyProfile",
    selectors=[eks.Selector(namespace="default")]
)
```

You can also directly use the `FargateProfile` construct to create profiles under different scopes:

```python
# cluster: eks.Cluster

eks.FargateProfile(self, "MyProfile",
    cluster=cluster,
    selectors=[eks.Selector(namespace="default")]
)
```

To create an EKS cluster that **only** uses Fargate capacity, you can use `FargateCluster`.
The following code defines an Amazon EKS cluster with a default Fargate Profile that matches all pods from the "kube-system" and "default" namespaces. It is also configured to [run CoreDNS on Fargate](https://docs.aws.amazon.com/eks/latest/userguide/fargate-getting-started.html#fargate-gs-coredns).

```python
cluster = eks.FargateCluster(self, "MyCluster",
    version=eks.KubernetesVersion.V1_34
)
```

`FargateCluster` will create a default `FargateProfile` which can be accessed via the cluster's `defaultProfile` property. The created profile can also be customized by passing options as with `addFargateProfile`.

**NOTE**: Classic Load Balancers and Network Load Balancers are not supported on
pods running on Fargate. For ingress, we recommend that you use the [ALB Ingress
Controller](https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html)
on Amazon EKS (minimum version v1.1.4).

### Self-managed capacity

Self-managed capacity gives you the most control over your worker nodes by allowing you to create and manage your own EC2 Auto Scaling Groups. This approach provides maximum flexibility for custom AMIs, instance configurations, and scaling policies, but requires more operational overhead.

You can add self-managed capacity to any cluster using the `addAutoScalingGroupCapacity` method:

```python
cluster = eks.Cluster(self, "Cluster",
    version=eks.KubernetesVersion.V1_34
)

cluster.add_auto_scaling_group_capacity("self-managed-nodes",
    instance_type=ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
    min_capacity=1,
    max_capacity=10,
    desired_capacity=3
)
```

You can specify custom subnets for the Auto Scaling Group:

```python
# vpc: ec2.Vpc
# cluster: eks.Cluster


cluster.add_auto_scaling_group_capacity("custom-subnet-nodes",
    vpc_subnets=ec2.SubnetSelection(subnets=vpc.private_subnets),
    instance_type=ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MEDIUM),
    min_capacity=2
)
```

### Endpoint Access

When you create a new cluster, Amazon EKS creates an endpoint for the managed Kubernetes API server that you use to communicate with your cluster (using Kubernetes management tools such as `kubectl`)

You can configure the [cluster endpoint access](https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html) by using the `endpointAccess` property:

```python
cluster = eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34,
    endpoint_access=eks.EndpointAccess.PRIVATE
)
```

The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, but worker node traffic and `kubectl` commands issued by this library stay within your VPC.

### Alb Controller

Some Kubernetes resources are commonly implemented on AWS with the help of the [ALB Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/).

From the docs:

> AWS Load Balancer Controller is a controller to help manage Elastic Load Balancers for a Kubernetes cluster.
>
> * It satisfies Kubernetes Ingress resources by provisioning Application Load Balancers.
> * It satisfies Kubernetes Service resources by provisioning Network Load Balancers.

To deploy the controller on your EKS cluster, configure the `albController` property:

```python
eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    alb_controller=eks.AlbControllerOptions(
        version=eks.AlbControllerVersion.V2_8_2
    )
)
```

To provide additional Helm chart values supported by `albController` in CDK, use the `additionalHelmChartValues` property. For example, the following code snippet shows how to set the `enableWafV2` flag:

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    alb_controller=eks.AlbControllerOptions(
        version=eks.AlbControllerVersion.V2_8_2,
        additional_helm_chart_values={
            "enable_wafv2": False
        }
    )
)
```

To overwrite an existing ALB controller service account, use the `overwriteServiceAccount` property:

```python
eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    alb_controller=eks.AlbControllerOptions(
        version=eks.AlbControllerVersion.V2_8_2,
        overwrite_service_account=True
    )
)
```

The `albController` requires `defaultCapacity` or at least one nodegroup. If there's no `defaultCapacity` or available
nodegroup for the cluster, the `albController` deployment would fail.

Querying the controller pods should look something like this:

```console
❯ kubectl get pods -n kube-system
NAME                                            READY   STATUS    RESTARTS   AGE
aws-load-balancer-controller-76bd6c7586-d929p   1/1     Running   0          109m
aws-load-balancer-controller-76bd6c7586-fqxph   1/1     Running   0          109m
...
...
```

Every Kubernetes manifest that utilizes the ALB Controller is effectively dependant on the controller.
If the controller is deleted before the manifest, it might result in dangling ELB/ALB resources.
Currently, the EKS construct library does not detect such dependencies, and they should be done explicitly.

For example:

```python
# cluster: eks.Cluster

manifest = cluster.add_manifest("manifest", {})
if cluster.alb_controller:
    manifest.node.add_dependency(cluster.alb_controller)
```

You can specify the VPC of the cluster using the `vpc` and `vpcSubnets` properties:

```python
# vpc: ec2.Vpc


eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    vpc=vpc,
    vpc_subnets=[ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS)]
)
```

If you do not specify a VPC, one will be created on your behalf, which you can then access via `cluster.vpc`. The cluster VPC will be associated to any EKS managed capacity (i.e Managed Node Groups and Fargate Profiles).

Please note that the `vpcSubnets` property defines the subnets where EKS will place the *control plane* ENIs. To choose
the subnets where EKS will place the worker nodes, please refer to the **Provisioning clusters** section above.

If you allocate self managed capacity, you can specify which subnets should the auto-scaling group use:

```python
# vpc: ec2.Vpc
# cluster: eks.Cluster

cluster.add_auto_scaling_group_capacity("nodes",
    vpc_subnets=ec2.SubnetSelection(subnets=vpc.private_subnets),
    instance_type=ec2.InstanceType("t2.medium")
)
```

There is an additional components you might want to provision within the VPC.

The `KubectlHandler` is a Lambda function responsible to issuing `kubectl` and `helm` commands against the cluster when you add resource manifests to the cluster.

The handler association to the VPC is derived from the `endpointAccess` configuration. The rule of thumb is: *If the cluster VPC can be associated, it will be*.

Breaking this down, it means that if the endpoint exposes private access (via `EndpointAccess.PRIVATE` or `EndpointAccess.PUBLIC_AND_PRIVATE`), and the VPC contains **private** subnets, the Lambda function will be provisioned inside the VPC and use the private subnets to interact with the cluster. This is the common use-case.

If the endpoint does not expose private access (via `EndpointAccess.PUBLIC`) **or** the VPC does not contain private subnets, the function will not be provisioned within the VPC.

If your use-case requires control over the IAM role that the KubeCtl Handler assumes, a custom role can be passed through the ClusterProps (as `kubectlLambdaRole`) of the EKS Cluster construct.

### Kubectl Support

You can choose to have CDK create a `Kubectl Handler` - a Python Lambda Function to
apply k8s manifests using `kubectl apply`. This handler will not be created by default.

To create a `Kubectl Handler`, use `kubectlProviderOptions` when creating the cluster.
`kubectlLayer` is the only required property in `kubectlProviderOptions`.

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl")
    )
)
```

`Kubectl Handler` created along with the cluster will be granted admin permissions to the cluster.

If you want to use an existing kubectl provider function, for example with tight trusted entities on your IAM Roles - you can import the existing provider and then use the imported provider when importing the cluster:

```python
handler_role = iam.Role.from_role_arn(self, "HandlerRole", "arn:aws:iam::123456789012:role/lambda-role")
# get the serivceToken from the custom resource provider
function_arn = lambda_.Function.from_function_name(self, "ProviderOnEventFunc", "ProviderframeworkonEvent-XXX").function_arn
kubectl_provider = eks.KubectlProvider.from_kubectl_provider_attributes(self, "KubectlProvider",
    service_token=function_arn,
    role=handler_role
)

cluster = eks.Cluster.from_cluster_attributes(self, "Cluster",
    cluster_name="cluster",
    kubectl_provider=kubectl_provider
)
```

#### Environment

You can configure the environment of this function by specifying it at cluster instantiation. For example, this can be useful in order to configure an http proxy:

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


cluster = eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl"),
        environment={
            "http_proxy": "http://proxy.myproxy.com"
        }
    )
)
```

#### Runtime

The kubectl handler uses `kubectl`, `helm` and the `aws` CLI in order to
interact with the cluster. These are bundled into AWS Lambda layers included in
the `@aws-cdk/lambda-layer-awscli` and `@aws-cdk/lambda-layer-kubectl` modules.

The version of kubectl used must be compatible with the Kubernetes version of the
cluster. kubectl is supported within one minor version (older or newer) of Kubernetes
(see [Kubernetes version skew policy](https://kubernetes.io/releases/version-skew-policy/#kubectl)).
Depending on which version of kubernetes you're targeting, you will need to use one of
the `@aws-cdk/lambda-layer-kubectl-vXY` packages.

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


cluster = eks.Cluster(self, "hello-eks",
    version=eks.KubernetesVersion.V1_34,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl")
    )
)
```

#### Memory

By default, the kubectl provider is configured with 1024MiB of memory. You can use the `memory` option to specify the memory size for the AWS Lambda function:

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


eks.Cluster(self, "MyCluster",
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl"),
        memory=Size.gibibytes(4)
    ),
    version=eks.KubernetesVersion.V1_34
)
```

### ARM64 Support

Instance types with `ARM64` architecture are supported in both managed nodegroup and self-managed capacity. Simply specify an ARM64 `instanceType` (such as `m6g.medium`), and the latest
Amazon Linux 2 AMI for ARM64 will be automatically selected.

```python
# cluster: eks.Cluster

# add a managed ARM64 nodegroup
cluster.add_nodegroup_capacity("extra-ng-arm",
    instance_types=[ec2.InstanceType("m6g.medium")],
    min_size=2
)

# add a self-managed ARM64 nodegroup
cluster.add_auto_scaling_group_capacity("self-ng-arm",
    instance_type=ec2.InstanceType("m6g.medium"),
    min_capacity=2
)
```

### Masters Role

When you create a cluster, you can specify a `mastersRole`. The `Cluster` construct will associate this role with `AmazonEKSClusterAdminPolicy` through [Access Entry](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html).

```python
# role: iam.Role

eks.Cluster(self, "HelloEKS",
    version=eks.KubernetesVersion.V1_34,
    masters_role=role
)
```

If you do not specify it, you won't have access to the cluster from outside of the CDK application.

### Encryption

When you create an Amazon EKS cluster, envelope encryption of Kubernetes secrets using the AWS Key Management Service (AWS KMS) can be enabled.
The documentation on [creating a cluster](https://docs.aws.amazon.com/eks/latest/userguide/create-cluster.html)
can provide more details about the customer master key (CMK) that can be used for the encryption.

You can use the `secretsEncryptionKey` to configure which key the cluster will use to encrypt Kubernetes secrets. By default, an AWS Managed key will be used.

> This setting can only be specified when the cluster is created and cannot be updated.

```python
secrets_key = kms.Key(self, "SecretsKey")
cluster = eks.Cluster(self, "MyCluster",
    secrets_encryption_key=secrets_key,
    version=eks.KubernetesVersion.V1_34
)
```

You can also use a similar configuration for running a cluster built using the FargateCluster construct.

```python
secrets_key = kms.Key(self, "SecretsKey")
cluster = eks.FargateCluster(self, "MyFargateCluster",
    secrets_encryption_key=secrets_key,
    version=eks.KubernetesVersion.V1_34
)
```

The Amazon Resource Name (ARN) for that CMK can be retrieved.

```python
# cluster: eks.Cluster

cluster_encryption_config_key_arn = cluster.cluster_encryption_config_key_arn
```

### Hybrid Nodes

When you create an Amazon EKS cluster, you can configure it to leverage the [EKS Hybrid Nodes](https://aws.amazon.com/eks/hybrid-nodes/) feature, allowing you to use your on-premises and edge infrastructure as nodes in your EKS cluster. Refer to the Hyrid Nodes [networking documentation](https://docs.aws.amazon.com/eks/latest/userguide/hybrid-nodes-networking.html) to configure your on-premises network, node and pod CIDRs, access control, etc before creating your EKS Cluster.

Once you have identified the on-premises node and pod (optional) CIDRs you will use for your hybrid nodes and the workloads running on them, you can specify them during cluster creation using the `remoteNodeNetworks` and `remotePodNetworks` (optional) properties:

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer


eks.Cluster(self, "Cluster",
    version=eks.KubernetesVersion.V1_34,
    remote_node_networks=[eks.RemoteNodeNetwork(
        cidrs=["10.0.0.0/16"]
    )
    ],
    remote_pod_networks=[eks.RemotePodNetwork(
        cidrs=["192.168.0.0/16"]
    )
    ]
)
```

### Self-Managed Add-ons

Amazon EKS automatically installs self-managed add-ons such as the Amazon VPC CNI plugin for Kubernetes, kube-proxy, and CoreDNS for every cluster. You can change the default configuration of the add-ons and update them when desired. If you wish to create a cluster without the default add-ons, set `bootstrapSelfManagedAddons` as `false`. When this is set to false, make sure to install the necessary alternatives which provide functionality that enables pod and service operations for your EKS cluster.

> Changing the value of `bootstrapSelfManagedAddons` after the EKS cluster creation will result in a replacement of the cluster.

## Permissions and Security

In the new EKS module, `ConfigMap` is deprecated. Clusters created by the new module will use `API` as authentication mode. Access Entry will be the only way for granting permissions to specific IAM users and roles.

### Access Entry

An access entry is a cluster identity—directly linked to an AWS IAM principal user or role that is used to authenticate to
an Amazon EKS cluster. An Amazon EKS access policy authorizes an access entry to perform specific cluster actions.

Access policies are Amazon EKS-specific policies that assign Kubernetes permissions to access entries. Amazon EKS supports
only predefined and AWS managed policies. Access policies are not AWS IAM entities and are defined and managed by Amazon EKS.
Amazon EKS access policies include permission sets that support common use cases of administration, editing, or read-only access
to Kubernetes resources. See [Access Policy Permissions](https://docs.aws.amazon.com/eks/latest/userguide/access-policies.html#access-policy-permissions) for more details.

Use `AccessPolicy` to include predefined AWS managed policies:

```python
# AmazonEKSClusterAdminPolicy with `cluster` scope
eks.AccessPolicy.from_access_policy_name("AmazonEKSClusterAdminPolicy",
    access_scope_type=eks.AccessScopeType.CLUSTER
)
# AmazonEKSAdminPolicy with `namespace` scope
eks.AccessPolicy.from_access_policy_name("AmazonEKSAdminPolicy",
    access_scope_type=eks.AccessScopeType.NAMESPACE,
    namespaces=["foo", "bar"]
)
```

Use `grantAccess()` to grant the AccessPolicy to an IAM principal:

```python
from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer
# vpc: ec2.Vpc


cluster_admin_role = iam.Role(self, "ClusterAdminRole",
    assumed_by=iam.ArnPrincipal("arn_for_trusted_principal")
)

eks_admin_role = iam.Role(self, "EKSAdminRole",
    assumed_by=iam.ArnPrincipal("arn_for_trusted_principal")
)

cluster = eks.Cluster(self, "Cluster",
    vpc=vpc,
    masters_role=cluster_admin_role,
    version=eks.KubernetesVersion.V1_34,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl"),
        memory=Size.gibibytes(4)
    )
)

# Cluster Admin role for this cluster
cluster.grant_access("clusterAdminAccess", cluster_admin_role.role_arn, [
    eks.AccessPolicy.from_access_policy_name("AmazonEKSClusterAdminPolicy",
        access_scope_type=eks.AccessScopeType.CLUSTER
    )
])

# EKS Admin role for specified namespaces of this cluster
cluster.grant_access("eksAdminRoleAccess", eks_admin_role.role_arn, [
    eks.AccessPolicy.from_access_policy_name("AmazonEKSAdminPolicy",
        access_scope_type=eks.AccessScopeType.NAMESPACE,
        namespaces=["foo", "bar"]
    )
])
```

#### Access Entry Types

You can optionally specify an access entry type when granting access. This is particularly useful for EKS Auto Mode clusters with custom node roles, which require the `EC2` type:

```python
# cluster: eks.Cluster
# node_role: iam.Role


# Grant access with EC2 type for Auto Mode node role
cluster.grant_access("nodeAccess", node_role.role_arn, [
    eks.AccessPolicy.from_access_policy_name("AmazonEKSAutoNodePolicy",
        access_scope_type=eks.AccessScopeType.CLUSTER
    )
], access_entry_type=eks.AccessEntryType.EC2)
```

The following access entry types are supported:

* `STANDARD` - Default type for standard IAM principals (default when not specified)
* `FARGATE_LINUX` - For Fargate profiles
* `EC2_LINUX` - For EC2 Linux worker nodes
* `EC2_WINDOWS` - For EC2 Windows worker nodes
* `EC2` - For EKS Auto Mode node roles
* `HYBRID_LINUX` - For EKS Hybrid Nodes
* `HYPERPOD_LINUX` - For Amazon SageMaker HyperPod

**Note**: Access entries with type `EC2`, `HYBRID_LINUX`, or `HYPERPOD_LINUX` cannot have access policies attached per AWS EKS API constraints. For these types, use the `AccessEntry` construct directly with an empty access policies array.

By default, the cluster creator role will be granted the cluster admin permissions. You can disable it by setting
`bootstrapClusterCreatorAdminPermissions` to false.

> **Note** - Switching `bootstrapClusterCreatorAdminPermissions` on an existing cluster would cause cluster replacement and should be avoided in production.

### Service Accounts

With services account you can provide Kubernetes Pods access to AWS resources.

```python
import aws_cdk.aws_s3 as s3
# cluster: eks.Cluster

# add service account
service_account = cluster.add_service_account("MyServiceAccount")

bucket = s3.Bucket(self, "Bucket")
bucket.grant_read_write(service_account)

mypod = cluster.add_manifest("mypod", {
    "api_version": "v1",
    "kind": "Pod",
    "metadata": {"name": "mypod"},
    "spec": {
        "service_account_name": service_account.service_account_name,
        "containers": [{
            "name": "hello",
            "image": "paulbouwer/hello-kubernetes:1.5",
            "ports": [{"container_port": 8080}]
        }
        ]
    }
})

# create the resource after the service account.
mypod.node.add_dependency(service_account)

# print the IAM role arn for this service account
CfnOutput(self, "ServiceAccountIamRole", value=service_account.role.role_arn)
```

Note that using `serviceAccount.serviceAccountName` above **does not** translate into a resource dependency.
This is why an explicit dependency is needed. See [https://github.com/aws/aws-cdk/issues/9910](https://github.com/aws/aws-cdk/issues/9910) for more details.

It is possible to pass annotations and labels to the service account.

```python
# cluster: eks.Cluster

# add service account with annotations and labels
service_account = cluster.add_service_account("MyServiceAccount",
    annotations={
        "eks.amazonaws.com/sts-regional-endpoints": "false"
    },
    labels={
        "some-label": "with-some-value"
    }
)
```

You can also add service accounts to existing clusters.
To do so, pass the `openIdConnectProvider` property when you import the cluster into the application.

```python
import aws_cdk.aws_s3 as s3

# or create a new one using an existing issuer url
# issuer_url: str

from aws_cdk.lambda_layer_kubectl_v34 import KubectlV34Layer

# you can import an existing provider
provider = eks.OidcProviderNative.from_oidc_provider_arn(self, "Provider", "arn:aws:iam::123456:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/AB123456ABC")
provider2 = eks.OidcProviderNative(self, "Provider",
    url=issuer_url
)

cluster = eks.Cluster.from_cluster_attributes(self, "MyCluster",
    cluster_name="Cluster",
    open_id_connect_provider=provider,
    kubectl_provider_options=eks.KubectlProviderOptions(
        kubectl_layer=KubectlV34Layer(self, "kubectl")
    )
)

service_account = cluster.add_service_account("MyServiceAccount")

bucket = s3.Bucket(self, "Bucket")
bucket.grant_read_write(service_account)
```

Note that adding service accounts requires running `kubectl` commands against the cluster which requires you to provide `kubectlProviderOptions` in the cluster props to create the `kubectl` provider. See [Kubectl Support](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-eks-v2-alpha-readme.html#kubectl-support)

#### Migrating from the deprecated eks.OpenIdConnectProvider to eks.OidcProviderNative

`eks.OpenIdConnectProvider` creates an IAM OIDC (OpenId Connect) provider using a custom resource while `eks.OidcProviderNative` uses the CFN L1 (AWS::IAM::OidcProvider) to create the provider. It is recommended for new and existing projects to use `eks.OidcProviderNative`.

To migrate without temporarily removing the OIDCProvider, follow these steps:

1. Set the `removalPolicy` of `cluster.openIdConnectProvider` to `RETAIN`.

   ```python
   import aws_cdk as cdk
   # cluster: eks.Cluster


   cdk.RemovalPolicies.of(cluster.open_id_connect_provider).apply(cdk.RemovalPolicy.RETAIN)
   ```
2. Run `cdk diff` to verify the changes are expected then `cdk deploy`.
3. Add the following to the `context` field of your `cdk.json` to enable the feature flag that creates the native oidc provider.

   ```json
   "@aws-cdk/aws-eks:useNativeOidcProvider": true,
   ```
4. Run `cdk diff` and ensure the changes are expected. Example of an expected diff:

   ```bash
   Resources
   [-] Custom::AWSCDKOpenIdConnectProvider TestCluster/OpenIdConnectProvider/Resource TestClusterOpenIdConnectProviderE18F0FD0 orphan
   [-] AWS::IAM::Role Custom::AWSCDKOpenIdConnectProviderCustomResourceProvider/Role CustomAWSCDKOpenIdConnectProviderCustomResourceProviderRole517FED65 destroy
   [-] AWS::Lambda::Function Custom::AWSCDKOpenIdConnectProviderCustomResourceProvider/Handler CustomAWSCDKOpenIdConnectProviderCustomResourceProviderHandlerF2C543E0 destroy
   [+] AWS::IAM::OIDCProvider TestCluster/OidcProviderNative TestClusterOidcProviderNative0BE3F155
   ```
5. Run `cdk import --force` and provide the ARN of the existing OpenIdConnectProvider when prompted. You will get a warning about pending changes to existing resources which is expected.
6. Run `cdk deploy` to apply any pending changes. This will apply the destroy/orphan changes in the above example.

If you are creating the OpenIdConnectProvider manually via `new eks.OpenIdConnectProvider`, follow these steps:

1. Set the `removalPolicy` of the existing `OpenIdConnectProvider` to `RemovalPolicy.RETAIN`.

   ```python
   import aws_cdk as cdk

   # Step 1: Add retain policy to existing provider
   existing_provider = eks.OpenIdConnectProvider(self, "Provider",
       url="https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLE",
       removal_policy=cdk.RemovalPolicy.RETAIN
   )
   ```
2. Deploy with the retain policy to avoid deletion of the underlying resource.

   ```bash
   cdk deploy
   ```
3. Replace `OpenIdConnectProvider` with `OidcProviderNative` in your code.

   ```python
   # Step 3: Replace with native provider
   native_provider = eks.OidcProviderNative(self, "Provider",
       url="https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLE"
   )
   ```
4. Run `cdk diff` and verify the changes are expected. Example of