EKS with Terraform: separating cluster infrastructure from add-ons

An EKS cluster and the controllers running inside it have different dependencies. In this repository, I separate the AWS foundation from the Helm add-ons so each layer has a clear place in the change process.

How the pieces connect
  1. Cluster Terraform root
  2. VPC + EKS + IAM
  3. Published state outputs
  4. Add-ons Terraform root
  5. Helm controllers

The problem this structure addresses

A Kubernetes or Helm provider needs a reachable cluster before it can manage resources. Keeping the cluster and its add-ons in separate Terraform roots makes that dependency explicit. The add-ons root reads the cluster name, endpoint and identity outputs from remote state instead of asking an engineer to copy them between files.

  • Review cluster changes separately from controller upgrades.
  • Apply the cluster layer before initializing providers that connect to it.
  • Protect the state backend and review access to state snapshots.

What the code actually contains

The cluster module creates private and public subnets, managed node groups and EKS add-ons. System nodes have a CriticalAddonsOnly taint; application nodes use Spot capacity. The VPC configuration selects a single NAT gateway outside production and disables that single-gateway setting for production.

  • Verify system workloads have suitable tolerations.
  • Plan for Spot interruptions and choose appropriate workload availability settings.
  • Check the installed configuration rather than assuming the README describes every default.

The boundary I would review before handover

The public example includes broad Secrets Manager permissions for the External Secrets role. Those permissions need narrowing to the intended accounts, regions and secret resources. A private cluster endpoint also requires a working network path from the machine or runner applying the add-ons.

  • Replace example backend configuration and inspect the effective IAM policy.
  • Confirm cluster endpoint access, DNS resolution and runner connectivity.
  • Test a controller upgrade, workload rollout and recovery path in staging.

What this example proves

The source demonstrates a two-layer infrastructure layout and the intended controller configuration. It does not establish a measured provisioning time, production uptime or benchmark result. Those depend on a deployed environment and recorded validation.

Checks to run in your environment

Validation steps for a configured sandbox; initialization needs backend and provider access.

terraform -chdir=terraform/cluster init
terraform -chdir=terraform/cluster validate
terraform -chdir=terraform/addons init
terraform -chdir=terraform/addons validate

These are suggested verification steps, not a record of a production test run. Check prerequisites and resource access before using them.

Source and references

Project links point to the exact source revision reviewed for this note.