instruction: Write a Terraform module for AWS EKS cluster with VPC and security groups
output: Here's a comprehensive Terraform module for AWS EKS:
  
  ```hcl
  # variables.tf
  variable "cluster_name" {
   description = "Name of the EKS cluster"
   type = string
  }
  
  variable "cluster_version" {
   description = "Kubernetes version for the EKS cluster"
   type = string
   default = "1.27"
  }
  
  variable "vpc_cidr" {
   description = "CIDR block for VPC"
   type = string
   default = "10.0.0.0/16"
  }
  
  variable "availability_zones" {
   description = "List of availability zones"
   type = list(string)
   default = ["us-west-2a", "us-west-2b", "us-west-2c"]
  }
  
  variable "node_groups" {
   description = "Map of node group configurations"
   type = map(object({
   instance_types = list(string)
   scaling_config = object({
   desired_size = number
   max_size = number
   min_size = number
   })
   capacity_type = string
   ami_type = string
   disk_size = number
   }))
   default = {
   main = {
   instance_types = ["t3.medium"]
   scaling_config = {
   desired_size = 2
   max_size = 4
   min_size = 1
   }
   capacity_type = "ON_DEMAND"
   ami_type = "AL2_x86_64"
   disk_size = 50
   }
   }
  }
  
  variable "enable_irsa" {
   description = "Enable IAM Roles for Service Accounts"
   type = bool
   default = true
  }
  
  variable "tags" {
   description = "Tags to apply to resources"
   type = map(string)
   default = {}
  }
  
  # vpc.tf
  resource "aws_vpc" "main" {
   cidr_block = var.vpc_cidr
   enable_dns_hostnames = true
   enable_dns_support = true
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-vpc"
   "kubernetes.io/cluster/${var.cluster_name}" = "shared"
   })
  }
  
  resource "aws_internet_gateway" "main" {
   vpc_id = aws_vpc.main.id
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-igw"
   })
  }
  
  resource "aws_subnet" "public" {
   count = length(var.availability_zones)
  
   vpc_id = aws_vpc.main.id
   cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
   availability_zone = var.availability_zones[count.index]
  
   map_public_ip_on_launch = true
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-public-${count.index + 1}"
   Type = "Public"
   "kubernetes.io/cluster/${var.cluster_name}" = "shared"
   "kubernetes.io/role/elb" = "1"
   })
  }
  
  resource "aws_subnet" "private" {
   count = length(var.availability_zones)
  
   vpc_id = aws_vpc.main.id
   cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + length(var.availability_zones))
   availability_zone = var.availability_zones[count.index]
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-private-${count.index + 1}"
   Type = "Private"
   "kubernetes.io/cluster/${var.cluster_name}" = "shared"
   "kubernetes.io/role/internal-elb" = "1"
   })
  }
  
  resource "aws_eip" "nat" {
   count = length(var.availability_zones)
  
   domain = "vpc"
   depends_on = [aws_internet_gateway.main]
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-nat-${count.index + 1}"
   })
  }
  
  resource "aws_nat_gateway" "main" {
   count = length(var.availability_zones)
  
   allocation_id = aws_eip.nat[count.index].id
   subnet_id = aws_subnet.public[count.index].id
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-nat-${count.index + 1}"
   })
  
   depends_on = [aws_internet_gateway.main]
  }
  
  resource "aws_route_table" "public" {
   vpc_id = aws_vpc.main.id
  
   route {
   cidr_block = "0.0.0.0/0"
   gateway_id = aws_internet_gateway.main.id
   }
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-public-rt"
   })
  }
  
  resource "aws_route_table" "private" {
   count = length(var.availability_zones)
  
   vpc_id = aws_vpc.main.id
  
   route {
   cidr_block = "0.0.0.0/0"
   nat_gateway_id = aws_nat_gateway.main[count.index].id
   }
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-private-rt-${count.index + 1}"
   })
  }
  
  resource "aws_route_table_association" "public" {
   count = length(aws_subnet.public)
  
   subnet_id = aws_subnet.public[count.index].id
   route_table_id = aws_route_table.public.id
  }
  
  resource "aws_route_table_association" "private" {
   count = length(aws_subnet.private)
  
   subnet_id = aws_subnet.private[count.index].id
   route_table_id = aws_route_table.private[count.index].id
  }
  
  # security-groups.tf
  resource "aws_security_group" "cluster" {
   name_prefix = "${var.cluster_name}-cluster-"
   vpc_id = aws_vpc.main.id
  
   ingress {
   description = "HTTPS"
   from_port = 443
   to_port = 443
   protocol = "tcp"
   cidr_blocks = ["0.0.0.0/0"]
   }
  
   egress {
   from_port = 0
   to_port = 0
   protocol = "-1"
   cidr_blocks = ["0.0.0.0/0"]
   }
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-cluster-sg"
   })
  }
  
  resource "aws_security_group" "node_group" {
   name_prefix = "${var.cluster_name}-node-"
   vpc_id = aws_vpc.main.id
  
   ingress {
   description = "Cluster API to node groups"
   from_port = 443
   to_port = 443
   protocol = "tcp"
   security_groups = [aws_security_group.cluster.id]
   }
  
   ingress {
   description = "Node to node communication"
   from_port = 0
   to_port = 65535
   protocol = "tcp"
   security_groups = [aws_security_group.cluster.id]
   self = true
   }
  
   egress {
   from_port = 0
   to_port = 0
   protocol = "-1"
   cidr_blocks = ["0.0.0.0/0"]
   }
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-node-sg"
   })
  }
  
  # iam.tf
  resource "aws_iam_role" "cluster" {
   name = "${var.cluster_name}-cluster-role"
  
   assume_role_policy = jsonencode({
   Statement = [{
   Action = "sts:AssumeRole"
   Effect = "Allow"
   Principal = {
   Service = "eks.amazonaws.com"
   }
   }]
   Version = "2012-10-17"
   })
  
   tags = var.tags
  }
  
  resource "aws_iam_role_policy_attachment" "cluster_AmazonEKSClusterPolicy" {
   policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
   role = aws_iam_role.cluster.name
  }
  
  resource "aws_iam_role" "node_group" {
   name = "${var.cluster_name}-node-role"
  
   assume_role_policy = jsonencode({
   Statement = [{
   Action = "sts:AssumeRole"
   Effect = "Allow"
   Principal = {
   Service = "ec2.amazonaws.com"
   }
   }]
   Version = "2012-10-17"
   })
  
   tags = var.tags
  }
  
  resource "aws_iam_role_policy_attachment" "node_group_AmazonEKSWorkerNodePolicy" {
   policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
   role = aws_iam_role.node_group.name
  }
  
  resource "aws_iam_role_policy_attachment" "node_group_AmazonEKS_CNI_Policy" {
   policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
   role = aws_iam_role.node_group.name
  }
  
  resource "aws_iam_role_policy_attachment" "node_group_AmazonEC2ContainerRegistryReadOnly" {
   policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
   role = aws_iam_role.node_group.name
  }
  
  # eks.tf
  resource "aws_eks_cluster" "main" {
   name = var.cluster_name
   role_arn = aws_iam_role.cluster.arn
   version = var.cluster_version
  
   vpc_config {
   security_group_ids = [aws_security_group.cluster.id]
   subnet_ids = concat(aws_subnet.public[*].id, aws_subnet.private[*].id)
   endpoint_private_access = true
   endpoint_public_access = true
   public_access_cidrs = ["0.0.0.0/0"]
   }
  
   encryption_config {
   provider {
   key_arn = aws_kms_key.eks.arn
   }
   resources = ["secrets"]
   }
  
   enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
  
   depends_on = [
   aws_iam_role_policy_attachment.cluster_AmazonEKSClusterPolicy,
   aws_cloudwatch_log_group.cluster,
   ]
  
   tags = var.tags
  }
  
  resource "aws_eks_node_group" "main" {
   for_each = var.node_groups
  
   cluster_name = aws_eks_cluster.main.name
   node_group_name = each.key
   node_role_arn = aws_iam_role.node_group.arn
   subnet_ids = aws_subnet.private[*].id
  
   capacity_type = each.value.capacity_type
   instance_types = each.value.instance_types
   ami_type = each.value.ami_type
   disk_size = each.value.disk_size
  
   scaling_config {
   desired_size = each.value.scaling_config.desired_size
   max_size = each.value.scaling_config.max_size
   min_size = each.value.scaling_config.min_size
   }
  
   remote_access {
   ec2_ssh_key = aws_key_pair.cluster.key_name
   source_security_group_ids = [aws_security_group.node_group.id]
   }
  
   depends_on = [
   aws_iam_role_policy_attachment.node_group_AmazonEKSWorkerNodePolicy,
   aws_iam_role_policy_attachment.node_group_AmazonEKS_CNI_Policy,
   aws_iam_role_policy_attachment.node_group_AmazonEC2ContainerRegistryReadOnly,
   ]
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-${each.key}"
   })
  }
  
  # kms.tf
  resource "aws_kms_key" "eks" {
   description = "EKS Secret Encryption Key"
   deletion_window_in_days = 7
   enable_key_rotation = true
  
   tags = merge(var.tags, {
   Name = "${var.cluster_name}-eks-key"
   })
  }
  
  resource "aws_kms_alias" "eks" {
   name = "alias/${var.cluster_name}-eks"
   target_key_id = aws_kms_key.eks.key_id
  }
  
  # cloudwatch.tf
  resource "aws_cloudwatch_log_group" "cluster" {
   name = "/aws/eks/${var.cluster_name}/cluster"
   retention_in_days = 14
   kms_key_id = aws_kms_key.eks.arn
  
   tags = var.tags
  }
  
  # outputs.tf
  output "cluster_endpoint" {
   description = "Endpoint for EKS control plane"
   value = aws_eks_cluster.main.endpoint
  }
  
  output "cluster_security_group_id" {
   description = "Security group ids attached to the cluster control plane"
   value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
  }
  
  output "cluster_iam_role_name" {
   description = "IAM role name associated with EKS cluster"
   value = aws_iam_role.cluster.name
  }
  
  output "cluster_certificate_authority_data" {
   description = "Base64 encoded certificate data required to communicate with the cluster"
   value = aws_eks_cluster.main.certificate_authority[0].data
  }
  
  output "cluster_name" {
   description = "The name of the EKS cluster"
   value = aws_eks_cluster.main.name
  }
  
  output "node_groups" {
   description = "EKS node groups"
   value = aws_eks_node_group.main
  }
  
  output "vpc_id" {
   description = "ID of the VPC where the cluster is deployed"
   value = aws_vpc.main.id
  }
  
  output "private_subnets" {
   description = "List of IDs of private subnets"
   value = aws_subnet.private[*].id
  }
  
  output "public_subnets" {
   description = "List of IDs of public subnets"
   value = aws_subnet.public[*].id
  }
  ```
  
  This Terraform module provides:
  - Complete VPC with public/private subnets
  - EKS cluster with encryption and logging
  - Configurable node groups
  - Proper IAM roles and security groups
  - KMS encryption for secrets
  - CloudWatch logging
  - Comprehensive outputs