Files
terraform-foundation/terraform/05-workloads/_template/eks-cluster/main.tf
Greg Hendrickson 6136cde9bb feat: Terraform Foundation - AWS Landing Zone
Enterprise-grade multi-tenant AWS cloud foundation.

Modules:
- GitHub OIDC for keyless CI/CD authentication
- IAM account settings and security baseline
- AWS Config Rules for compliance
- ABAC (Attribute-Based Access Control)
- SCPs (Service Control Policies)

Features:
- Multi-account architecture
- Cost optimization patterns
- Security best practices
- Comprehensive documentation

Tech: Terraform, AWS Organizations, IAM Identity Center
2026-02-02 02:57:23 +00:00

969 lines
29 KiB
HCL

################################################################################
# Workload: EKS Cluster
#
# Deploys a managed Kubernetes cluster:
# - EKS cluster with managed node groups
# - Core addons (VPC CNI, CoreDNS, kube-proxy)
# - IRSA (IAM Roles for Service Accounts)
# - Cluster Autoscaler ready
# - AWS Load Balancer Controller ready
# - Optional Fargate profiles
#
# Usage:
# Copy this folder to 05-workloads/<tenant>-eks/
# Update locals and variables
# terraform init -backend-config=../../00-bootstrap/backend.hcl
# terraform apply
################################################################################
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
tls = {
source = "hashicorp/tls"
version = ">= 4.0"
}
}
backend "s3" {
key = "05-workloads/<TENANT>-eks/terraform.tfstate"
}
}
################################################################################
# Configuration - UPDATE THESE
################################################################################
locals {
# Naming
tenant = "<TENANT>"
env = "prod" # prod, staging, dev
name = "${local.tenant}-${local.env}"
# EKS Version
cluster_version = "1.29"
# Node Groups
node_groups = {
general = {
instance_types = ["t3.medium"]
capacity_type = "ON_DEMAND" # ON_DEMAND or SPOT
min_size = 2
max_size = 10
desired_size = 2
disk_size = 50
labels = {
role = "general"
}
taints = []
}
# Uncomment for spot instances
# spot = {
# instance_types = ["t3.medium", "t3.large", "t3a.medium"]
# capacity_type = "SPOT"
# min_size = 0
# max_size = 20
# desired_size = 0
# disk_size = 50
# labels = {
# role = "spot"
# }
# taints = [{
# key = "spot"
# value = "true"
# effect = "NO_SCHEDULE"
# }]
# }
}
# Fargate (for serverless pods)
enable_fargate = false
fargate_namespaces = ["serverless"] # Namespaces to run on Fargate
# Addons
enable_cluster_autoscaler = true
enable_aws_lb_controller = true
enable_ebs_csi_driver = true
enable_metrics_server = true
# Logging
cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
log_retention_days = 30
# Access
cluster_endpoint_public = true
cluster_endpoint_private = true
public_access_cidrs = ["0.0.0.0/0"] # Restrict in production!
# Admin access (IAM ARNs that can access cluster)
admin_arns = [
# "arn:aws:iam::123456789012:role/Admin",
# "arn:aws:iam::123456789012:user/admin",
]
}
################################################################################
# Variables
################################################################################
variable "region" {
type = string
default = "us-east-1"
}
variable "state_bucket" {
type = string
}
################################################################################
# Provider
################################################################################
provider "aws" {
region = var.region
default_tags {
tags = {
Tenant = local.tenant
Environment = local.env
ManagedBy = "terraform"
}
}
}
################################################################################
# Data Sources
################################################################################
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = var.state_bucket
key = "02-network/terraform.tfstate"
region = var.region
}
}
data "terraform_remote_state" "tenant" {
backend = "s3"
config = {
bucket = var.state_bucket
key = "04-tenants/${local.tenant}/terraform.tfstate"
region = var.region
}
}
data "aws_caller_identity" "current" {}
data "aws_region" "current" {}
data "aws_partition" "current" {}
################################################################################
# KMS Key for Secrets Encryption
################################################################################
resource "aws_kms_key" "eks" {
description = "EKS Secret Encryption Key for ${local.name}"
deletion_window_in_days = 7
enable_key_rotation = true
tags = { Name = "${local.name}-eks" }
}
resource "aws_kms_alias" "eks" {
name = "alias/${local.name}-eks"
target_key_id = aws_kms_key.eks.key_id
}
################################################################################
# CloudWatch Log Group
################################################################################
resource "aws_cloudwatch_log_group" "eks" {
name = "/aws/eks/${local.name}/cluster"
retention_in_days = local.log_retention_days
tags = { Name = "${local.name}-eks" }
}
################################################################################
# IAM - Cluster Role
################################################################################
resource "aws_iam_role" "cluster" {
name = "${local.name}-eks-cluster"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = { Service = "eks.amazonaws.com" }
}]
})
tags = { Name = "${local.name}-eks-cluster" }
}
resource "aws_iam_role_policy_attachment" "cluster_policy" {
role = aws_iam_role.cluster.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSClusterPolicy"
}
resource "aws_iam_role_policy_attachment" "cluster_vpc_policy" {
role = aws_iam_role.cluster.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSVPCResourceController"
}
################################################################################
# IAM - Node Role
################################################################################
resource "aws_iam_role" "node" {
name = "${local.name}-eks-node"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = { Service = "ec2.amazonaws.com" }
}]
})
tags = { Name = "${local.name}-eks-node" }
}
resource "aws_iam_role_policy_attachment" "node_policy" {
role = aws_iam_role.node.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy"
}
resource "aws_iam_role_policy_attachment" "node_cni_policy" {
role = aws_iam_role.node.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKS_CNI_Policy"
}
resource "aws_iam_role_policy_attachment" "node_ecr_policy" {
role = aws_iam_role.node.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}
resource "aws_iam_role_policy_attachment" "node_ssm_policy" {
role = aws_iam_role.node.name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
################################################################################
# IAM - Fargate Role
################################################################################
resource "aws_iam_role" "fargate" {
count = local.enable_fargate ? 1 : 0
name = "${local.name}-eks-fargate"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRole"
Principal = { Service = "eks-fargate-pods.amazonaws.com" }
}]
})
tags = { Name = "${local.name}-eks-fargate" }
}
resource "aws_iam_role_policy_attachment" "fargate_policy" {
count = local.enable_fargate ? 1 : 0
role = aws_iam_role.fargate[0].name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy"
}
################################################################################
# Security Groups
################################################################################
resource "aws_security_group" "cluster" {
name = "${local.name}-eks-cluster"
description = "EKS cluster security group"
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
tags = { Name = "${local.name}-eks-cluster" }
}
resource "aws_security_group_rule" "cluster_egress" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.cluster.id
description = "Allow all outbound"
}
resource "aws_security_group" "node" {
name = "${local.name}-eks-node"
description = "EKS node security group"
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
tags = {
Name = "${local.name}-eks-node"
"kubernetes.io/cluster/${local.name}" = "owned"
}
}
resource "aws_security_group_rule" "node_egress" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.node.id
description = "Allow all outbound"
}
resource "aws_security_group_rule" "node_ingress_self" {
type = "ingress"
from_port = 0
to_port = 65535
protocol = "-1"
source_security_group_id = aws_security_group.node.id
security_group_id = aws_security_group.node.id
description = "Node to node"
}
resource "aws_security_group_rule" "node_ingress_cluster" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
source_security_group_id = aws_security_group.cluster.id
security_group_id = aws_security_group.node.id
description = "Cluster to node (webhooks)"
}
resource "aws_security_group_rule" "node_ingress_cluster_kubelet" {
type = "ingress"
from_port = 10250
to_port = 10250
protocol = "tcp"
source_security_group_id = aws_security_group.cluster.id
security_group_id = aws_security_group.node.id
description = "Cluster to node (kubelet)"
}
resource "aws_security_group_rule" "cluster_ingress_node" {
type = "ingress"
from_port = 443
to_port = 443
protocol = "tcp"
source_security_group_id = aws_security_group.node.id
security_group_id = aws_security_group.cluster.id
description = "Node to cluster API"
}
################################################################################
# EKS Cluster
################################################################################
resource "aws_eks_cluster" "main" {
name = local.name
version = local.cluster_version
role_arn = aws_iam_role.cluster.arn
vpc_config {
subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
endpoint_private_access = local.cluster_endpoint_private
endpoint_public_access = local.cluster_endpoint_public
public_access_cidrs = local.public_access_cidrs
security_group_ids = [aws_security_group.cluster.id]
}
encryption_config {
provider {
key_arn = aws_kms_key.eks.arn
}
resources = ["secrets"]
}
enabled_cluster_log_types = local.cluster_log_types
depends_on = [
aws_iam_role_policy_attachment.cluster_policy,
aws_iam_role_policy_attachment.cluster_vpc_policy,
aws_cloudwatch_log_group.eks,
]
tags = { Name = local.name }
}
################################################################################
# EKS Addons
################################################################################
resource "aws_eks_addon" "vpc_cni" {
cluster_name = aws_eks_cluster.main.name
addon_name = "vpc-cni"
resolve_conflicts_on_create = "OVERWRITE"
resolve_conflicts_on_update = "OVERWRITE"
tags = { Name = "${local.name}-vpc-cni" }
}
resource "aws_eks_addon" "coredns" {
cluster_name = aws_eks_cluster.main.name
addon_name = "coredns"
resolve_conflicts_on_create = "OVERWRITE"
resolve_conflicts_on_update = "OVERWRITE"
depends_on = [aws_eks_node_group.main]
tags = { Name = "${local.name}-coredns" }
}
resource "aws_eks_addon" "kube_proxy" {
cluster_name = aws_eks_cluster.main.name
addon_name = "kube-proxy"
resolve_conflicts_on_create = "OVERWRITE"
resolve_conflicts_on_update = "OVERWRITE"
tags = { Name = "${local.name}-kube-proxy" }
}
resource "aws_eks_addon" "ebs_csi" {
count = local.enable_ebs_csi_driver ? 1 : 0
cluster_name = aws_eks_cluster.main.name
addon_name = "aws-ebs-csi-driver"
service_account_role_arn = aws_iam_role.ebs_csi[0].arn
resolve_conflicts_on_create = "OVERWRITE"
resolve_conflicts_on_update = "OVERWRITE"
depends_on = [aws_eks_node_group.main]
tags = { Name = "${local.name}-ebs-csi" }
}
################################################################################
# Node Groups
################################################################################
resource "aws_eks_node_group" "main" {
for_each = local.node_groups
cluster_name = aws_eks_cluster.main.name
node_group_name = "${local.name}-${each.key}"
node_role_arn = aws_iam_role.node.arn
subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
instance_types = each.value.instance_types
capacity_type = each.value.capacity_type
disk_size = each.value.disk_size
scaling_config {
min_size = each.value.min_size
max_size = each.value.max_size
desired_size = each.value.desired_size
}
update_config {
max_unavailable = 1
}
labels = merge(each.value.labels, {
Tenant = local.tenant
})
dynamic "taint" {
for_each = each.value.taints
content {
key = taint.value.key
value = taint.value.value
effect = taint.value.effect
}
}
# Launch template for security hardening
launch_template {
id = aws_launch_template.node[each.key].id
version = aws_launch_template.node[each.key].latest_version
}
depends_on = [
aws_iam_role_policy_attachment.node_policy,
aws_iam_role_policy_attachment.node_cni_policy,
aws_iam_role_policy_attachment.node_ecr_policy,
]
lifecycle {
ignore_changes = [scaling_config[0].desired_size]
}
tags = { Name = "${local.name}-${each.key}" }
}
################################################################################
# Launch Template for Node Security Hardening
################################################################################
resource "aws_launch_template" "node" {
for_each = local.node_groups
name = "${local.name}-${each.key}"
# IMDSv2 enforcement - critical security control
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # Enforces IMDSv2
http_put_response_hop_limit = 1 # Prevent container credential theft
instance_metadata_tags = "enabled"
}
# EBS encryption
block_device_mappings {
device_name = "/dev/xvda"
ebs {
volume_size = each.value.disk_size
volume_type = "gp3"
encrypted = true
delete_on_termination = true
}
}
# Monitoring
monitoring {
enabled = true
}
tag_specifications {
resource_type = "instance"
tags = {
Name = "${local.name}-${each.key}"
Tenant = local.tenant
}
}
tags = { Name = "${local.name}-${each.key}" }
}
################################################################################
# Fargate Profiles
################################################################################
resource "aws_eks_fargate_profile" "main" {
for_each = local.enable_fargate ? toset(local.fargate_namespaces) : []
cluster_name = aws_eks_cluster.main.name
fargate_profile_name = "${local.name}-${each.key}"
pod_execution_role_arn = aws_iam_role.fargate[0].arn
subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
selector {
namespace = each.key
labels = {
Tenant = local.tenant
}
}
tags = { Name = "${local.name}-${each.key}" }
}
################################################################################
# OIDC Provider for IRSA
################################################################################
data "tls_certificate" "eks" {
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
resource "aws_iam_openid_connect_provider" "eks" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.eks.certificates[0].sha1_fingerprint]
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
tags = { Name = "${local.name}-eks-oidc" }
}
################################################################################
# IRSA - EBS CSI Driver
################################################################################
resource "aws_iam_role" "ebs_csi" {
count = local.enable_ebs_csi_driver ? 1 : 0
name = "${local.name}-ebs-csi"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.eks.arn
}
Condition = {
StringEquals = {
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:aud" = "sts.amazonaws.com"
}
}
}]
})
tags = { Name = "${local.name}-ebs-csi" }
}
resource "aws_iam_role_policy_attachment" "ebs_csi" {
count = local.enable_ebs_csi_driver ? 1 : 0
role = aws_iam_role.ebs_csi[0].name
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
}
################################################################################
# IRSA - Cluster Autoscaler
################################################################################
resource "aws_iam_role" "cluster_autoscaler" {
count = local.enable_cluster_autoscaler ? 1 : 0
name = "${local.name}-cluster-autoscaler"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.eks.arn
}
Condition = {
StringEquals = {
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub" = "system:serviceaccount:kube-system:cluster-autoscaler"
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:aud" = "sts.amazonaws.com"
}
}
}]
})
tags = { Name = "${local.name}-cluster-autoscaler" }
}
resource "aws_iam_role_policy" "cluster_autoscaler" {
count = local.enable_cluster_autoscaler ? 1 : 0
name = "cluster-autoscaler"
role = aws_iam_role.cluster_autoscaler[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"autoscaling:DescribeAutoScalingGroups",
"autoscaling:DescribeAutoScalingInstances",
"autoscaling:DescribeLaunchConfigurations",
"autoscaling:DescribeScalingActivities",
"autoscaling:DescribeTags",
"ec2:DescribeInstanceTypes",
"ec2:DescribeLaunchTemplateVersions",
"ec2:DescribeImages",
"ec2:GetInstanceTypesFromInstanceRequirements",
"eks:DescribeNodegroup"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"autoscaling:SetDesiredCapacity",
"autoscaling:TerminateInstanceInAutoScalingGroup"
]
Resource = "*"
Condition = {
StringEquals = {
"autoscaling:ResourceTag/k8s.io/cluster-autoscaler/${local.name}" = "owned"
}
}
}
]
})
}
################################################################################
# IRSA - AWS Load Balancer Controller
################################################################################
resource "aws_iam_role" "lb_controller" {
count = local.enable_aws_lb_controller ? 1 : 0
name = "${local.name}-aws-lb-controller"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = "sts:AssumeRoleWithWebIdentity"
Principal = {
Federated = aws_iam_openid_connect_provider.eks.arn
}
Condition = {
StringEquals = {
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:sub" = "system:serviceaccount:kube-system:aws-load-balancer-controller"
"${replace(aws_iam_openid_connect_provider.eks.url, "https://", "")}:aud" = "sts.amazonaws.com"
}
}
}]
})
tags = { Name = "${local.name}-aws-lb-controller" }
}
resource "aws_iam_role_policy" "lb_controller" {
count = local.enable_aws_lb_controller ? 1 : 0
name = "aws-lb-controller"
role = aws_iam_role.lb_controller[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["iam:CreateServiceLinkedRole"]
Resource = "*"
Condition = {
StringEquals = {
"iam:AWSServiceName" = "elasticloadbalancing.amazonaws.com"
}
}
},
{
Effect = "Allow"
Action = [
"ec2:DescribeAccountAttributes",
"ec2:DescribeAddresses",
"ec2:DescribeAvailabilityZones",
"ec2:DescribeInternetGateways",
"ec2:DescribeVpcs",
"ec2:DescribeVpcPeeringConnections",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeInstances",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeTags",
"ec2:GetCoipPoolUsage",
"ec2:DescribeCoipPools",
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeLoadBalancerAttributes",
"elasticloadbalancing:DescribeListeners",
"elasticloadbalancing:DescribeListenerCertificates",
"elasticloadbalancing:DescribeSSLPolicies",
"elasticloadbalancing:DescribeRules",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DescribeTags"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"cognito-idp:DescribeUserPoolClient",
"acm:ListCertificates",
"acm:DescribeCertificate",
"iam:ListServerCertificates",
"iam:GetServerCertificate",
"waf-regional:GetWebACL",
"waf-regional:GetWebACLForResource",
"waf-regional:AssociateWebACL",
"waf-regional:DisassociateWebACL",
"wafv2:GetWebACL",
"wafv2:GetWebACLForResource",
"wafv2:AssociateWebACL",
"wafv2:DisassociateWebACL",
"shield:GetSubscriptionState",
"shield:DescribeProtection",
"shield:CreateProtection",
"shield:DeleteProtection"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:RevokeSecurityGroupIngress",
"ec2:CreateSecurityGroup",
"ec2:CreateTags",
"ec2:DeleteTags",
"ec2:DeleteSecurityGroup"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"elasticloadbalancing:CreateLoadBalancer",
"elasticloadbalancing:CreateTargetGroup"
]
Resource = "*"
Condition = {
Null = {
"aws:RequestTag/elbv2.k8s.aws/cluster" = "false"
}
}
},
{
Effect = "Allow"
Action = [
"elasticloadbalancing:AddTags",
"elasticloadbalancing:RemoveTags"
]
Resource = [
"arn:${data.aws_partition.current.partition}:elasticloadbalancing:*:*:targetgroup/*/*",
"arn:${data.aws_partition.current.partition}:elasticloadbalancing:*:*:loadbalancer/net/*/*",
"arn:${data.aws_partition.current.partition}:elasticloadbalancing:*:*:loadbalancer/app/*/*"
]
},
{
Effect = "Allow"
Action = [
"elasticloadbalancing:ModifyLoadBalancerAttributes",
"elasticloadbalancing:SetIpAddressType",
"elasticloadbalancing:SetSecurityGroups",
"elasticloadbalancing:SetSubnets",
"elasticloadbalancing:DeleteLoadBalancer",
"elasticloadbalancing:ModifyTargetGroup",
"elasticloadbalancing:ModifyTargetGroupAttributes",
"elasticloadbalancing:DeleteTargetGroup",
"elasticloadbalancing:RegisterTargets",
"elasticloadbalancing:DeregisterTargets",
"elasticloadbalancing:CreateListener",
"elasticloadbalancing:DeleteListener",
"elasticloadbalancing:CreateRule",
"elasticloadbalancing:ModifyRule",
"elasticloadbalancing:DeleteRule",
"elasticloadbalancing:SetWebAcl",
"elasticloadbalancing:ModifyListener",
"elasticloadbalancing:AddListenerCertificates",
"elasticloadbalancing:RemoveListenerCertificates"
]
Resource = "*"
}
]
})
}
################################################################################
# EKS Access Entries (K8s 1.29+)
################################################################################
resource "aws_eks_access_entry" "admins" {
for_each = toset(local.admin_arns)
cluster_name = aws_eks_cluster.main.name
principal_arn = each.value
type = "STANDARD"
}
resource "aws_eks_access_policy_association" "admins" {
for_each = toset(local.admin_arns)
cluster_name = aws_eks_cluster.main.name
principal_arn = each.value
policy_arn = "arn:${data.aws_partition.current.partition}:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
access_scope {
type = "cluster"
}
depends_on = [aws_eks_access_entry.admins]
}
################################################################################
# Outputs
################################################################################
output "cluster_name" {
value = aws_eks_cluster.main.name
}
output "cluster_endpoint" {
value = aws_eks_cluster.main.endpoint
}
output "cluster_ca_certificate" {
value = aws_eks_cluster.main.certificate_authority[0].data
sensitive = true
}
output "cluster_version" {
value = aws_eks_cluster.main.version
}
output "cluster_security_group_id" {
value = aws_security_group.cluster.id
}
output "node_security_group_id" {
value = aws_security_group.node.id
}
output "oidc_provider_arn" {
value = aws_iam_openid_connect_provider.eks.arn
}
output "oidc_provider_url" {
value = aws_iam_openid_connect_provider.eks.url
}
output "cluster_autoscaler_role_arn" {
value = local.enable_cluster_autoscaler ? aws_iam_role.cluster_autoscaler[0].arn : null
}
output "lb_controller_role_arn" {
value = local.enable_aws_lb_controller ? aws_iam_role.lb_controller[0].arn : null
}
output "kubeconfig_command" {
value = "aws eks update-kubeconfig --region ${data.aws_region.current.name} --name ${aws_eks_cluster.main.name}"
}
output "next_steps" {
value = <<-EOT
EKS Cluster Created: ${aws_eks_cluster.main.name}
=============================================
1. Configure kubectl:
${local.enable_cluster_autoscaler ? "aws eks update-kubeconfig --region ${data.aws_region.current.name} --name ${aws_eks_cluster.main.name}" : ""}
2. Install Cluster Autoscaler (if enabled):
helm repo add autoscaler https://kubernetes.github.io/autoscaler
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
--namespace kube-system \
--set autoDiscovery.clusterName=${aws_eks_cluster.main.name} \
--set awsRegion=${data.aws_region.current.name} \
--set rbac.serviceAccount.create=true \
--set rbac.serviceAccount.name=cluster-autoscaler \
--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${local.enable_cluster_autoscaler ? aws_iam_role.cluster_autoscaler[0].arn : "N/A"}
3. Install AWS Load Balancer Controller (if enabled):
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
--namespace kube-system \
--set clusterName=${aws_eks_cluster.main.name} \
--set serviceAccount.create=true \
--set serviceAccount.name=aws-load-balancer-controller \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${local.enable_aws_lb_controller ? aws_iam_role.lb_controller[0].arn : "N/A"}
EOT
}