Skip to content

native-cube/terraform-aws-eks

Repository files navigation

Terraform AWS EKS Module

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, and vpc-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.

Usage

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-eks

Examples

  • examples/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.

EKS Capabilities

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.

Karpenter Readiness

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.

Module Documentation

Requirements

Name Version
terraform >= 1.5.0
aws >= 6.0

Providers

Name Version
aws >= 6.0

Resources

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

Inputs

Name Description Type Default Required
access_config Optional EKS access configuration for cluster authentication mode and creator admin permissions.
object({
authentication_mode = optional(string)
bootstrap_cluster_creator_admin_permissions = optional(bool)
})
null no
addons EKS add-ons to install after the managed node groups are created.
map(object({
configuration_values = optional(string)
pod_identity_associations = optional(list(object({
role_arn = string
service_account = string
})), [])
resolve_conflicts_on_create = optional(string, "OVERWRITE")
resolve_conflicts_on_update = optional(string, "OVERWRITE")
service_account_role_arn = optional(string)
version = optional(string)
}))
{
"coredns": {},
"kube-proxy": {},
"vpc-cni": {}
}
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({
capability_name = optional(string)
create_iam_role = optional(bool, true)
delete_propagation_policy = optional(string, "RETAIN")
iam_policy_arns = optional(set(string), [])
iam_role_arn = optional(string)
iam_role_name = optional(string)
inline_policy_json = optional(string)
type = string
argocd = optional(object({
idc_instance_arn = optional(string)
idc_region = optional(string)
namespace = optional(string)
network_access_vpce_ids = optional(set(string), [])
rbac_role_mappings = optional(list(object({
role = string
identities = list(object({
id = string
type = string
}))
})), [])
}))
}))
{} 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({
provider_key_arn = string
resources = optional(list(string), ["secrets"])
})
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)
[
"api",
"audit",
"authenticator"
]
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({
create_access_entry = optional(bool, true)
create_node_iam_role = optional(bool, true)
enabled = optional(bool, false)
node_iam_role_arn = optional(string)
node_iam_role_name = optional(string)
subnet_ids = optional(list(string), [])
tag_cluster_security_group = optional(bool, true)
tag_subnets = optional(bool, true)
})
{} 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({
ami_type = optional(string)
capacity_type = optional(string, "ON_DEMAND")
desired_size = optional(number, 2)
disk_size = optional(number, 20)
instance_types = optional(list(string), ["t3.medium"])
labels = optional(map(string), {})
max_size = optional(number, 3)
min_size = optional(number, 1)
subnet_ids = optional(list(string), [])
update_max_unavailable = optional(number, 1)
node_repair_config = optional(object({
enabled = optional(bool)
max_parallel_nodes_repaired_count = optional(number)
max_parallel_nodes_repaired_percentage = optional(number)
max_unhealthy_node_threshold_count = optional(number)
max_unhealthy_node_threshold_percentage = optional(number)
overrides = optional(list(object({
min_repair_wait_time_mins = number
node_monitoring_condition = string
node_unhealthy_reason = string
repair_action = string
})), [])
}))
taints = optional(list(object({
effect = string
key = string
value = optional(string, "")
})), [])
}))
{
"default": {}
}
no
public_access_cidrs CIDR blocks that can access the public Kubernetes API endpoint. list(string)
[
"0.0.0.0/0"
]
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

Outputs

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.

Git Hooks

Enable the repository hooks after cloning or initializing Git:

git config core.hooksPath .githooks

The 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.sh

Tests

Native Terraform tests live in tests/ and use mocked AWS provider resources, so they can run without AWS credentials or creating infrastructure:

terraform test

Pull requests run the same tests through .github/workflows/terraform-pr.yml, along with formatting, generated-docs, validation, and example checks.

Local Development

Use the Makefile for common local checks:

make fmt
make docs
make check

Notes

  • The module does not create VPC, subnet, route table, NAT gateway, or security baseline resources.
  • For production use, restrict public_access_cidrs instead of leaving the default 0.0.0.0/0.
  • Node group subnets default to subnet_ids, but each node group can override them with its own subnet_ids.

About

Terraform module to provision EKS Clusters

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors