Agent: "Create Terraform module structure for:
- VPC with public/private subnets
- EKS cluster with node groups
- Application load balancer
- Security groups and IAM"
required_version = ">= 1.5.0"
Environment = var.environment
LastModified = timestamp()
length(var.private_subnets),
length(var.public_subnets),
length(var.database_subnets)
nat_gateway_count = var.single_nat_gateway ? 1 : var.one_nat_gateway_per_az ? length(var.azs) : local.max_subnet_length
resource "aws_vpc" "this" {
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
Name = format("%s-vpc", var.name)
resource "aws_internet_gateway" "this" {
count = length(var.public_subnets) > 0 ? 1 : 0
Name = format("%s-igw", var.name)
resource "aws_subnet" "public" {
count = length(var.public_subnets)
cidr_block = element(var.public_subnets, count.index)
availability_zone = element(var.azs, count.index)
map_public_ip_on_launch = var.map_public_ip_on_launch
Name = format("%s-public-%s", var.name, element(var.azs, count.index))
"kubernetes.io/role/elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
resource "aws_subnet" "private" {
count = length(var.private_subnets)
cidr_block = element(var.private_subnets, count.index)
availability_zone = element(var.azs, count.index)
Name = format("%s-private-%s", var.name, element(var.azs, count.index))
"kubernetes.io/role/internal-elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
resource "aws_subnet" "database" {
count = length(var.database_subnets)
cidr_block = element(var.database_subnets, count.index)
availability_zone = element(var.azs, count.index)
Name = format("%s-database-%s", var.name, element(var.azs, count.index))
# Elastic IPs for NAT Gateways
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
Name = format("%s-eip-%s", var.name, element(var.azs, count.index))
depends_on = [aws_internet_gateway.this]
resource "aws_nat_gateway" "this" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
allocation_id = element(aws_eip.nat[*].id, count.index)
subnet_id = element(aws_subnet.public[*].id, count.index)
Name = format("%s-nat-%s", var.name, element(var.azs, count.index))
depends_on = [aws_internet_gateway.this]
resource "aws_route_table" "public" {
count = length(var.public_subnets) > 0 ? 1 : 0
Name = format("%s-public-rt", var.name)
resource "aws_route_table" "private" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
Name = format("%s-private-rt-%s", var.name, element(var.azs, count.index))
resource "aws_route" "public_internet_gateway" {
count = length(var.public_subnets) > 0 ? 1 : 0
route_table_id = aws_route_table.public[0].id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this[0].id
resource "aws_route" "private_nat_gateway" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
route_table_id = element(aws_route_table.private[*].id, count.index)
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index)
# Route Table Associations
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = element(aws_subnet.public[*].id, count.index)
route_table_id = aws_route_table.public[0].id
resource "aws_route_table_association" "private" {
count = length(var.private_subnets)
subnet_id = element(aws_subnet.private[*].id, count.index)
route_table_id = element(
aws_route_table.private[*].id,
var.single_nat_gateway ? 0 : count.index
resource "aws_vpc_endpoint" "s3" {
count = var.enable_s3_endpoint ? 1 : 0
service_name = data.aws_vpc_endpoint_service.s3.service_name
Name = format("%s-s3-endpoint", var.name)
resource "aws_vpc_endpoint_route_table_association" "s3_public" {
count = var.enable_s3_endpoint && length(var.public_subnets) > 0 ? 1 : 0
vpc_endpoint_id = aws_vpc_endpoint.s3[0].id
route_table_id = aws_route_table.public[0].id
resource "aws_vpc_endpoint_route_table_association" "s3_private" {
count = var.enable_s3_endpoint ? local.nat_gateway_count : 0
vpc_endpoint_id = aws_vpc_endpoint.s3[0].id
route_table_id = element(aws_route_table.private[*].id, count.index)
resource "aws_flow_log" "this" {
count = var.enable_flow_log ? 1 : 0
iam_role_arn = aws_iam_role.flow_log[0].arn
log_destination = aws_cloudwatch_log_group.flow_log[0].arn
traffic_type = var.flow_log_traffic_type
Name = format("%s-flow-log", var.name)
resource "aws_cloudwatch_log_group" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = "/aws/vpc/${var.name}"
retention_in_days = var.flow_log_retention_in_days
kms_key_id = var.flow_log_kms_key_id
resource "aws_iam_role" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = format("%s-flow-log-role", var.name)
assume_role_policy = jsonencode({
Service = "vpc-flow-logs.amazonaws.com"
Action = "sts:AssumeRole"
resource "aws_iam_role_policy" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = format("%s-flow-log-policy", var.name)
role = aws_iam_role.flow_log[0].id
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"