Terraform
AWS
Kubernetes
Infrastructure as Code
DevOps

Terraform cycle with AWS and Kubernetes provider

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

A Terraform cycle involving the AWS and Kubernetes providers usually appears when you try to create an EKS cluster and manage Kubernetes resources from the same dependency graph. The Kubernetes provider needs the cluster endpoint, certificate, and auth details before it can work, but those values come from AWS resources that Terraform has not finished creating yet.

That is why the error is not just a random graph problem. It is Terraform telling you that provider configuration depends on infrastructure that is still inside the same unresolved apply.

The Typical Cycle

A common setup looks like this:

hcl
1module "eks" {
2  source = "./modules/eks"
3}
4
5data "aws_eks_cluster" "this" {
6  name = module.eks.cluster_name
7}
8
9data "aws_eks_cluster_auth" "this" {
10  name = module.eks.cluster_name
11}
12
13provider "kubernetes" {
14  host                   = data.aws_eks_cluster.this.endpoint
15  cluster_ca_certificate = base64decode(data.aws_eks_cluster.this.certificate_authority[0].data)
16  token                  = data.aws_eks_cluster_auth.this.token
17}
18
19resource "kubernetes_namespace" "app" {
20  metadata {
21    name = "app"
22  }
23}

On its own, that can work after the cluster already exists. The trouble starts when the EKS module or related resources also depend on something that indirectly needs the Kubernetes provider during the same apply.

Why depends_on Usually Does Not Fix It

People often try to solve this by adding depends_on, but provider configuration happens before Terraform can use the provider for resources. If the provider itself needs outputs from resources that are not ready yet, a simple dependency edge does not break the cycle.

This is the key mental model:

  • resources can depend on providers
  • provider configuration cannot wait on a resource in the same flexible way you might expect

So the real solution is usually architectural, not a single extra line of HCL.

The Practical Fix: Split the Apply

The most reliable solution is to separate infrastructure creation from Kubernetes resource management.

Stage 1:

  • create VPC, IAM, and EKS with the AWS provider

Stage 2:

  • configure the Kubernetes provider from the already-created cluster outputs
  • apply namespaces, deployments, config maps, and other in-cluster resources

That usually means separate root modules or separate Terraform states.

For example:

text
1infra/
2  main.tf      # AWS, VPC, EKS
3
4cluster-apps/
5  main.tf      # Kubernetes provider, namespaces, workloads

The second stack can read cluster connection details from remote state, outputs, or another stable handoff mechanism.

A Safer Two-Stage Pattern

Root module one:

hcl
output "cluster_name" {
  value = module.eks.cluster_name
}

Root module two:

hcl
1data "terraform_remote_state" "infra" {
2  backend = "s3"
3  config = {
4    bucket = "my-tf-state"
5    key    = "infra/terraform.tfstate"
6    region = "us-east-1"
7  }
8}

Now the Kubernetes provider is configured from stable outputs of an already completed AWS apply, which removes the cycle entirely.

Other Things That Commonly Trigger the Problem

You may also hit this cycle when:

  • an EKS module tries to manage the aws-auth config map internally
  • Helm or Kubernetes resources live in the same root module as cluster creation
  • provider configuration uses data sources that cannot resolve until the cluster is live

All of these point back to the same root issue: trying to bootstrap the cluster and consume the cluster in one graph stage.

Common Pitfalls

  • Assuming depends_on can always fix provider bootstrapping cycles.
  • Mixing EKS creation and Kubernetes workload management in one root module without a clear boundary.
  • Using data.aws_eks_cluster before the cluster exists and expecting Terraform to treat it like a normal late-bound resource edge.
  • Letting a community EKS module manage in-cluster resources while you also configure the Kubernetes provider externally.
  • Keeping everything in one state file because it feels simpler at first, then fighting cycles later.

Summary

  • The cycle usually comes from configuring the Kubernetes provider from an EKS cluster Terraform is still creating.
  • This is a graph-design issue, not just a missing dependency edge.
  • The safest fix is to split AWS cluster creation and Kubernetes resource management into separate applies or states.
  • Remote state or explicit outputs are a clean handoff between the two stages.
  • If Terraform says there is a cycle between AWS and Kubernetes providers, treat that as a signal to separate bootstrap from workload management.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.