Terraform and Amazon EKS

The Terraform EKS module: what it builds, and what is still yours to do

terraform-aws-modules/eks/aws is the standard way to create an Amazon EKS cluster with Terraform. One apply gives you a control plane, add-ons and nodes. It does not give you ingress, DNS, certificates or a process for upgrades, and those are the parts that take the most time after the first cluster is up.

By , Founder at SeaGit

·

Key takeaways

  • The module creates the EKS control plane, its add-ons, access entries and, if you ask, managed node groups or Auto Mode compute. It does not create a VPC.
  • Module version 21 uses name, kubernetes_version and addons. Examples written for older majors use other input names, so check the version line before you copy one.
  • EKS gives each Kubernetes minor version 14 months of standard support, then 12 months of extended support at a higher hourly rate. Plan an upgrade inside that window.
  • Ingress, DNS, TLS and application delivery are separate layers. The module leaves them to you, and an apply that succeeds does not mean an application has a working URL.
  • SeaGit creates EKS clusters in your own AWS account. It is AWS-only today, so Azure and GCP clusters need the module or another platform.

What the module creates

The module creates the EKS cluster, which is the control plane that AWS operates. It creates the add-ons you list under addons, such as vpc-cni, kube-proxy and coredns, as managed EKS add-ons. It creates access entries from access_entries and the cluster creator permission when you enable it. If you set eks_managed_node_groups, it creates EC2 Auto Scaling groups and the node IAM roles. If you set compute_config with enabled set to true, it turns on EKS Auto Mode instead.

It does not create a VPC, subnets or route tables. It does not install a load balancer controller, an ingress controller, external-dns or cert-manager. Those are cluster add-ons in the Kubernetes sense, and you install them after the module finishes. kubectl works as soon as apply completes. A public URL for an application does not, until you add those layers.

The EKS module creates the cluster and its node capacity. Ingress, DNS, TLS and application delivery sit outside it.A dashed box labelled terraform-aws-modules/eks/aws contains the control plane, add-ons, access entries and managed node groups. Outside the box, on the right, are ingress and load balancing, DNS, TLS certificates and application workloads, each marked as a separate step you add.terraform-aws-modules/eks/awsControl planeEKS APIAdd-onsvpc-cni, corednsAccess entriesIAM to RBACManaged node groupsEC2 Auto ScalingIngress and load balanceryou addDNS recordsyou addTLS certificatesyou addApplication workloadsOutside the dashed box is the layer the module does not manage.
The dashed box is what the module manages. Everything outside it is the day-2 layer. The boundary is the reason an apply can succeed while the application still has no URL.

A working example on module v21

The module is published on the Terraform Registry and developed on GitHub. The example below uses the input names from its v21 usage examples. The VPC is passed in as variables, so the example does not depend on how you build your network. Add-ons with before_compute are created before the node group, which the module’s examples use for vpc-cni and the pod identity agent.

hcl
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 21.0"

  name               = "my-cluster"
  kubernetes_version = "1.33"

  vpc_id     = var.vpc_id
  subnet_ids = var.private_subnet_ids

  endpoint_public_access = true

  # Adds the identity running Terraform as an administrator,
  # through an access entry.
  enable_cluster_creator_admin_permissions = true

  addons = {
    coredns                = {}
    kube-proxy             = {}
    eks-pod-identity-agent = { before_compute = true }
    vpc-cni                = { before_compute = true }
  }

  eks_managed_node_groups = {
    default = {
      ami_type       = "AL2023_x86_64_STANDARD"
      instance_types = ["m5.large"]

      min_size     = 2
      max_size     = 6
      desired_size = 2
    }
  }

  tags = {
    Environment = "production"
    Terraform   = "true"
  }
}
Module v21 example. Values are placeholders; the Kubernetes version and instance type are yours to set.

Older examples use different names, such as cluster_name for the cluster and cluster_version for the Kubernetes version. Those names belong to earlier major versions. Check the version constraint first. A v21 plan run against a v19-era block fails on unknown arguments, and that failure is the cheap outcome.

Who can use kubectl

Access entries are the EKS-native way to map IAM principals to Kubernetes permissions. The enable_cluster_creator_admin_permissions input adds the identity that runs Terraform as an administrator, so the first apply leaves you a way in. Everyone else should get a narrower entry, scoped to the namespaces they work in.

hcl
access_entries = {
  viewer = {
    principal_arn = "arn:aws:iam::123456789012:role/eks-viewer"

    policy_associations = {
      view = {
        policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy"
        access_scope = {
          namespaces = ["web"]
          type       = "namespace"
        }
      }
    }
  }
}
An access entry with a read-only policy scoped to one namespace. The role ARN is a placeholder.

The module’s documentation describes authentication_mode set to API_AND_CONFIG_MAP, which accepts both access entries and the aws-auth ConfigMap. Access entries created for node roles are managed for you. Entries for people are yours to keep current, and removing a person means removing their entry.

Kubernetes versions and what they cost

Every Kubernetes minor version on EKS has a fixed lifecycle. It gets 14 months of standard support, then 12 months of extended support. The AWS pricing page lists standard support at $0.10 per cluster per hour and extended support at $0.60 per cluster per hour, which includes the standard rate, as of October 2026. A cluster left on an old minor version costs more every hour, and after extended support it has no further security patches.

An EKS Kubernetes version has 14 months of standard support, then 12 months of extended support at a higher hourly price.A horizontal timeline for one Kubernetes minor version. A wide segment labelled standard support spans 14 months at a cluster hourly rate. A second segment labelled extended support spans 12 months at a higher rate. The timeline ends after extended support, and the cluster must be upgraded before then.One Kubernetes minor version on Amazon EKSStandard support: 14 monthsExtended support: 12 monthsStandard: $0.10 per cluster per hour. Extended: $0.60 per cluster per hour.Rates from the Amazon EKS pricing page, checked as of October 2026.Upgrade before extended support ends, one minor version at a time.
The rates in the figure come from the Amazon EKS pricing page, checked as of October 2026. Plan the next upgrade against the end of standard support, not the end of extended support.

Upgrading the cluster

An upgrade is a change to kubernetes_version followed by a normal plan and apply. Review the plan before you apply it, because the node groups and add-ons that follow the cluster version can be replaced in the same run. Upgrade one minor version at a time. Skipping a minor version is not supported by EKS, so a jump from 1.31 to 1.33 is two upgrades.

shell
# Confirm the control plane version after an apply
aws eks describe-cluster --name my-cluster --query "cluster.version" --output text

# The usual cycle for a version change
terraform plan -out=upgrade.tfplan
terraform apply upgrade.tfplan
Check the running version, then run the normal Terraform cycle. The cluster name is an example.

Before the change, read the release notes for the target minor version. Each one lists removed APIs and behaviour changes. Run your manifests against those lists before the apply, not after.

What the module leaves to you

The module is scoped to the cluster, and it does that well. The rest is real work, and it is where most of the setup time goes.

Node sizing and scaling. A managed node group keeps a fixed instance type and a size range you set. Pod-driven scaling needs Karpenter or the Cluster Autoscaler, or Auto Mode, installed and configured separately.

Ingress and load balancing. Something must receive traffic and route it to services. That is a controller and a load balancer, and the choice of controller matters for future migrations. See the ingress end-of-life guide on this site for the current state of ingress-nginx.

DNS and TLS. Records for each hostname, and certificates for each one, are created outside the module. Decide who owns the zone and how certificates renew before the first public service goes live.

Workload identity. The example installs the pod identity agent, but the associations that give each workload its IAM role are separate resources. Create them per workload, and keep node roles narrow.

Observability and backup. Logs, metrics and alerts are not part of the module. Neither is a backup of cluster state or of the volumes your workloads use.

What to check after the first apply

A successful apply only means that AWS accepted the resources. Three checks show whether the cluster can run something. First, the managed nodes should join and report Ready. Second, the core add-ons should be running, because coredns cannot schedule until nodes exist, and the vpc-cni add-on has to be ready before nodes can get pod addresses. The example creates vpc-cni and the pod identity agent before the node group for that reason. Third, a second person should be able to reach the cluster through their own access entry, not through the identity that created it.

shell
kubectl get nodes -o wide
kubectl get pods --namespace kube-system
aws eks list-addons --cluster-name my-cluster
First-apply checks. The cluster name and namespace are examples.

Nodes that never reach Ready usually point to one of three causes: the node role is not allowed to join, the subnets have no route for the node to reach the EKS endpoint and pull images, or the add-ons did not start. Read the node group’s health issues in the EKS console or with the AWS CLI before you change the Terraform code, so you know which of the three you are fixing.

Keep the first apply small. Create the cluster and one node group, confirm the checks above, and only then add the controllers and the workloads. A failure in one of those layers is then easy to locate, because the earlier layers were known to work.

Keeping the module current

The version constraint in the example, ~> 21.0, accepts any 21.x release and blocks version 22. A minor or patch release is usually an update you can apply with a plan review. A new major version changes input names and defaults, and it needs the upgrade notes the module publishes for that major version before you change the constraint.

Pin the module version in the lock file and commit it, so a later plan on another machine uses the same module code. Review the plan for the cluster and node groups after each change, and treat a replacement of the cluster or of the node group as a change that needs a maintenance window, not a routine update.

Module or platform: how to choose

Use the module when your team wants to own the cluster and the layers above it, and has people who will keep those layers current. The module is versioned, documented and widely used, so the parts you write are the ones that are specific to you.

A platform fits when the cluster is one part of a larger job, and the team would rather not run the ingress, DNS, certificate and upgrade cycle itself. The trade-off is that the platform’s choices become yours too. Ask what it manages, where the cluster lives, and how you leave if you need to.

How SeaGit handles this

SeaGit creates Amazon EKS clusters inside your own AWS account, and the cluster belongs to that account. It sets up the cluster layers that this article lists as yours, including an ingress option, so you can run an application without writing those pieces yourself. The cluster and its settings are documented on the clusters page.

The limits are the same as everywhere in this article. SeaGit supports AWS and Amazon EKS only. If your target is Azure, GCP or a self-managed Kubernetes cluster, the module and the layers above it are your path.

Terraform EKS module: FAQ

Do I need to write the VPC myself before using the EKS module?

The module takes vpc_id and subnet_ids as inputs. It does not create a VPC. Most setups use the companion terraform-aws-modules/vpc/aws module, or a VPC managed elsewhere. Pass the private subnets to subnet_ids, and pass the control plane subnets to control_plane_subnet_ids if you use separate ones.

What is the difference between managed node groups and EKS Auto Mode?

Managed node groups, set with eks_managed_node_groups, create EC2 Auto Scaling groups that EKS manages. You choose the instance types and the minimum, maximum and desired sizes. Auto Mode is turned on with compute_config. The module’s examples show it with enabled set to true and a list of node pools. Auto Mode hands compute management to EKS. Read the EKS Auto Mode documentation before you choose one.

Should I use access entries or the aws-auth ConfigMap?

Access entries are the EKS-native way to map IAM principals to Kubernetes permissions. The module creates them from access_entries, and enable_cluster_creator_admin_permissions adds the identity running Terraform as an administrator. The module documents authentication_mode set to API_AND_CONFIG_MAP, which accepts access entries and the aws-auth ConfigMap during a migration. Check the module’s access entry section before you remove an existing aws-auth mapping.

Does the module install an ingress controller, DNS or TLS?

No. The module stops at the cluster, its add-ons and its compute. An ingress controller, a load balancer, external DNS records and certificates are separate installs against the cluster the module hands back. You can install them with Helm, with another Terraform module, or with a platform that manages that layer.

How do I upgrade the Kubernetes version afterward?

Change kubernetes_version, run terraform plan to review the change, then terraform apply. Upgrade one minor version at a time. Managed node groups and add-ons follow the cluster version, and the plan shows what will be replaced. Check the EKS release notes for the target minor version before you start, because each one lists its own removals and required changes.

Sources

Checked as of October 2026.

  1. terraform-aws-modules/eks/aws: Terraform Registry — module version, input names and the published documentation
  2. terraform-aws-modules/terraform-aws-eks (GitHub repository) — the usage examples for v21, access entries and Auto Mode
  3. Understand the Kubernetes version lifecycle on EKS (Amazon EKS User Guide) — standard and extended support windows
  4. Amazon EKS pricing — per cluster per hour rates for standard and extended support
  5. Amazon EKS managed node groups (Amazon EKS User Guide) — what EKS manages on a node group and what stays with you