Simple Terraform module for creating an Amazon EKS cluster with:
- EKS control plane IAM role
- Managed node group IAM role
- One or more EKS managed node groups
- Core EKS add-ons:
coredns,kube-proxy, andvpc-cni - Optional Amazon EKS managed capabilities: Argo CD, ACK, and KRO
- Optional EKS-side Karpenter readiness without installing Karpenter itself
- Useful connection and composition outputs
The module expects you to provide existing subnet IDs. In most deployments these should be private subnets with outbound internet access through NAT.
module "eks" {
source = "./eks"
name = "dev"
cluster_name = "dev-eks"
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
node_groups = {
default = {
instance_types = ["t3.medium"]
min_size = 1
desired_size = 2
max_size = 3
}
}
tags = {
Environment = "dev"
}
}Then configure kubectl:
aws eks update-kubeconfig --name dev-eksexamples/minimal- smallest practical module call using defaults for node groups, add-ons, API access, and logging.examples/basic- simple explicit managed node group configuration.examples/advanced- restricted API access, full control-plane logging, multiple node groups, expanded add-on configuration, optional IAM-backed add-ons, and optional node subnet overrides.examples/capabilities- Amazon EKS managed capabilities for Argo CD, ACK, and KRO, including IAM Identity Center authentication for Argo CD and optional capability role policies.examples/karpenter-ready- EKS-side Karpenter readiness with discovery tags, a Karpenter node role, and node access entry while leaving the Karpenter controller, Helm release, interruption queue, NodePool, and EC2NodeClass to a separate module.
Enable the capabilities map when this module should create Amazon EKS managed capabilities. Supported types are ARGOCD, ACK, and KRO.
module "eks" {
source = "./eks"
name = "dev"
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
capabilities = {
argocd = {
type = "ARGOCD"
argocd = {
idc_instance_arn = "arn:aws:sso:::instance/ssoins-7223a1b234567890"
namespace = "argocd"
rbac_role_mappings = [
{
role = "ADMIN"
identities = [
{
id = "12345678-1234-1234-1234-123456789012"
type = "SSO_GROUP"
}
]
}
]
}
}
ack = {
type = "ACK"
}
kro = {
type = "KRO"
create_iam_role = false
iam_role_arn = "arn:aws:iam::123456789012:role/platform/KROCapabilityRole"
}
}
}When enabled, the module can create a capability IAM role trusted by capabilities.eks.amazonaws.com and creates all configured entries through one aws_eks_capability.this resource block. Attach managed policies or an inline policy to the capability role only when a capability needs access to supporting AWS services.
For ARGOCD, configure the nested argocd object with IAM Identity Center settings, optional RBAC role mappings, and optional VPC endpoint IDs. If argocd.network_access_vpce_ids is empty, AWS exposes the default public managed Argo CD endpoint. Supplying VPC endpoint IDs makes the Argo CD server private-only through those endpoints.
Enable the karpenter object when this module should prepare the cluster for Karpenter-managed capacity:
module "eks" {
source = "./eks"
name = "dev"
subnet_ids = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
karpenter = {
enabled = true
create_node_iam_role = true
create_access_entry = true
}
}When enabled, the module can create the worker-node IAM role used by Karpenter-launched EC2 instances, authorize that role with an EKS EC2_LINUX access entry, and tag selected subnets plus the EKS-created cluster security group with karpenter.sh/discovery = <cluster_name>.
This module deliberately does not install the Karpenter controller, create its controller IAM role, create an interruption queue, or manage NodePool and EC2NodeClass resources. Use the karpenter_* outputs as inputs to that separate layer.
| Name | Version |
|---|---|
| terraform | >= 1.5.0 |
| aws | >= 6.0 |
| Name | Version |
|---|---|
| aws | >= 6.0 |
| Name | Type |
|---|---|
| aws_cloudwatch_log_group.cluster | resource |
| aws_ec2_tag.karpenter_cluster_security_group | resource |
| aws_ec2_tag.karpenter_subnets | resource |
| aws_eks_access_entry.karpenter_node | resource |
| aws_eks_addon.this | resource |
| aws_eks_capability.this | resource |
| aws_eks_cluster.this | resource |
| aws_eks_node_group.this | resource |
| aws_iam_role.cluster | resource |
| aws_iam_role.eks_capability | resource |
| aws_iam_role.karpenter_node | resource |
| aws_iam_role.node | resource |
| aws_iam_role_policy.eks_capability | resource |
| aws_iam_role_policy_attachment.cluster | resource |
| aws_iam_role_policy_attachment.eks_capability | resource |
| aws_iam_role_policy_attachment.karpenter_node | resource |
| aws_iam_role_policy_attachment.node | resource |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| access_config | Optional EKS access configuration for cluster authentication mode and creator admin permissions. | object({ |
null |
no |
| addons | EKS add-ons to install after the managed node groups are created. | map(object({ |
{ |
no |
| capabilities | Amazon EKS managed capabilities to create, keyed by a stable local name. Supported types are ARGOCD, ACK, and KRO. The module can create a capability IAM role per entry, or use an externally managed role ARN. | map(object({ |
{} |
no |
| cloudwatch_log_group_kms_key_id | Optional KMS key ID or ARN for encrypting the EKS control plane CloudWatch log group. | string |
null |
no |
| cloudwatch_log_retention_days | Retention in days for the EKS control plane CloudWatch log group. | number |
30 |
no |
| cluster_encryption_config | Optional EKS encryption configuration for Kubernetes secrets using an existing KMS key. | object({ |
null |
no |
| cluster_name | Optional EKS cluster name. When null, name is used as the cluster name. | string |
null |
no |
| cluster_security_group_ids | Additional security group IDs to associate with the EKS control plane. | list(string) |
[] |
no |
| deletion_protection | Whether to enable deletion protection for the EKS cluster. Leave null to use the AWS/provider default. | bool |
null |
no |
| enabled_cluster_log_types | EKS control plane log types to enable. | list(string) |
[ |
no |
| endpoint_private_access | Whether the Kubernetes API server endpoint is reachable from within the VPC. | bool |
true |
no |
| endpoint_public_access | Whether the Kubernetes API server endpoint is reachable from the public internet. | bool |
true |
no |
| karpenter | Optional EKS-side readiness settings for Karpenter. This module prepares AWS/EKS primitives only; install Karpenter, controller IAM, interruption handling, NodePools, and EC2NodeClasses separately. | object({ |
{} |
no |
| kubernetes_version | Kubernetes version for the EKS cluster and managed node groups. Leave null to use the current AWS default. | string |
null |
no |
| name | Name prefix for module-created resources. Used as the EKS cluster name when cluster_name is null. | string |
n/a | yes |
| node_groups | Managed node groups to create. | map(object({ |
{ |
no |
| public_access_cidrs | CIDR blocks that can access the public Kubernetes API endpoint. | list(string) |
[ |
no |
| service_ipv4_cidr | Optional Kubernetes service IPv4 CIDR. Set only when you need a non-default service CIDR. | string |
null |
no |
| subnet_ids | Subnet IDs for the EKS control plane and default node groups. Use at least two subnets in different Availability Zones. | list(string) |
n/a | yes |
| tags | Tags to apply to created resources. | map(string) |
{} |
no |
| Name | Description |
|---|---|
| addon_arns | EKS add-on ARNs by add-on name. |
| argocd_idc_managed_application_arns | IAM Identity Center managed application ARNs by ARGOCD capability key. |
| argocd_server_urls | Managed Argo CD server URLs by ARGOCD capability key. |
| capability_arns | Amazon EKS capability ARNs by capability key. |
| capability_iam_role_arns | IAM role ARNs used by Amazon EKS capabilities by capability key. |
| capability_iam_role_names | IAM role names used by Amazon EKS capabilities by capability key. |
| capability_names | Amazon EKS capability names by capability key. |
| capability_versions | Amazon EKS capability software versions by capability key. |
| cluster_arn | EKS cluster ARN. |
| cluster_certificate_authority_data | Base64-encoded cluster certificate authority data. |
| cluster_endpoint | Kubernetes API server endpoint. |
| cluster_iam_role_arn | IAM role ARN used by the EKS control plane. |
| cluster_log_group_name | CloudWatch log group for EKS control plane logs, if cluster logs are enabled. |
| cluster_name | EKS cluster name. |
| cluster_oidc_issuer_url | OIDC issuer URL for the EKS cluster. |
| cluster_security_group_id | Security group created by EKS for the cluster. |
| karpenter_discovery_tag_key | Tag key used by Karpenter discovery selectors when Karpenter readiness is enabled. |
| karpenter_discovery_tag_value | Tag value used by Karpenter discovery selectors when Karpenter readiness is enabled. |
| karpenter_node_iam_role_arn | IAM role ARN for Karpenter-launched worker nodes when Karpenter readiness is enabled. |
| karpenter_node_iam_role_name | IAM role name for Karpenter EC2NodeClass role configuration when Karpenter readiness is enabled. |
| node_group_arns | Managed node group ARNs by node group key. |
| node_iam_role_arn | IAM role ARN used by managed node groups. |
| update_kubeconfig_command | AWS CLI command to configure kubectl for this cluster. |
Enable the repository hooks after cloning or initializing Git:
git config core.hooksPath .githooksThe pre-commit hook checks Terraform formatting and verifies that generated Terraform docs in this README are up to date.
Regenerate the README module documentation manually with:
scripts/terraform-docs.shNative Terraform tests live in tests/ and use mocked AWS provider resources, so they can run without AWS credentials or creating infrastructure:
terraform testPull requests run the same tests through .github/workflows/terraform-pr.yml, along with formatting, generated-docs, validation, and example checks.
Use the Makefile for common local checks:
make fmt
make docs
make check- The module does not create VPC, subnet, route table, NAT gateway, or security baseline resources.
- For production use, restrict
public_access_cidrsinstead of leaving the default0.0.0.0/0. - Node group subnets default to
subnet_ids, but each node group can override them with its ownsubnet_ids.