# Terraform configuration to create an EKS cluster with a managed node group.

provider "aws" {
  region = "us-east-1"
}

# --- 1. VPC and Subnets for EKS ---
resource "aws_vpc" "eks_vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "my-terraform-eks-vpc"
  }
}

resource "aws_subnet" "eks_public_subnet_1" {
  vpc_id            = aws_vpc.eks_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "my-terraform-eks-public-1"
    "kubernetes.io/cluster/${aws_eks_cluster.main.name}" = "owned"
    "kubernetes.io/role/elb" = "1"
  }
}

resource "aws_subnet" "eks_public_subnet_2" {
  vpc_id            = aws_vpc.eks_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-east-1b"
  map_public_ip_on_launch = true

  tags = {
    Name = "my-terraform-eks-public-2"
    "kubernetes.io/cluster/${aws_eks_cluster.main.name}" = "owned"
    "kubernetes.io/role/elb" = "1"
  }
}

resource "aws_subnet" "eks_private_subnet_1" {
  vpc_id            = aws_vpc.eks_vpc.id
  cidr_block        = "10.0.3.0/24"
  availability_zone = "us-east-1a"

  tags = {
    Name = "my-terraform-eks-private-1"
    "kubernetes.io/cluster/${aws_eks_cluster.main.name}" = "owned"
    "kubernetes.io/role/internal-elb" = "1"
  }
}

resource "aws_subnet" "eks_private_subnet_2" {
  vpc_id            = aws_vpc.eks_vpc.id
  cidr_block        = "10.0.4.0/24"
  availability_zone = "us-east-1b"

  tags = {
    Name = "my-terraform-eks-private-2"
    "kubernetes.io/cluster/${aws_eks_cluster.main.name}" = "owned"
    "kubernetes.io/role/internal-elb" = "1"
  }
}

resource "aws_internet_gateway" "eks_igw" {
  vpc_id = aws_vpc.eks_vpc.id

  tags = {
    Name = "my-terraform-eks-igw"
  }
}

resource "aws_eip" "nat_eip" {
  vpc        = true
  depends_on = [aws_internet_gateway.eks_igw]
}

resource "aws_nat_gateway" "eks_nat_gw" {
  allocation_id = aws_eip.nat_eip.id
  subnet_id     = aws_subnet.eks_public_subnet_1.id

  tags = {
    Name = "my-terraform-eks-nat-gw"
  }
  depends_on = [aws_internet_gateway.eks_igw]
}

resource "aws_route_table" "eks_public_rt" {
  vpc_id = aws_vpc.eks_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.eks_igw.id
  }

  tags = {
    Name = "my-terraform-eks-public-rt"
  }
}

resource "aws_route_table_association" "eks_public_rt_assoc_1" {
  subnet_id      = aws_subnet.eks_public_subnet_1.id
  route_table_id = aws_route_table.eks_public_rt.id
}

resource "aws_route_table_association" "eks_public_rt_assoc_2" {
  subnet_id      = aws_subnet.eks_public_subnet_2.id
  route_table_id = aws_route_table.eks_public_rt.id
}

resource "aws_route_table" "eks_private_rt" {
  vpc_id = aws_vpc.eks_vpc.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.eks_nat_gw.id
  }

  tags = {
    Name = "my-terraform-eks-private-rt"
  }
}

resource "aws_route_table_association" "eks_private_rt_assoc_1" {
  subnet_id      = aws_subnet.eks_private_subnet_1.id
  route_table_id = aws_route_table.eks_private_rt.id
}

resource "aws_route_table_association" "eks_private_rt_assoc_2" {
  subnet_id      = aws_subnet.eks_private_subnet_2.id
  route_table_id = aws_route_table.eks_private_rt.id
}


# --- 2. IAM Roles ---
# EKS Cluster Role
resource "aws_iam_role" "eks_cluster_role" {
  name = "my-terraform-eks-cluster-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "eks.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "eks_cluster_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role       = aws_iam_role.eks_cluster_role.name
}

resource "aws_iam_role_policy_attachment" "eks_vpc_cni_policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
  role       = aws_iam_role.eks_cluster_role.name
}

# EKS Node Group Role
resource "aws_iam_role" "eks_nodegroup_role" {
  name = "my-terraform-eks-nodegroup-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "ec2.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy_attachment" "eks_worker_node_policy" {
  name       = "my-terraform-eks-worker-node-policy"
  roles      = [aws_iam_role.eks_nodegroup_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
}

resource "aws_iam_policy_attachment" "eks_cni_policy" {
  name       = "my-terraform-eks-cni-policy"
  roles      = [aws_iam_role.eks_nodegroup_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
}

resource "aws_iam_policy_attachment" "ec2_container_registry_read_only" {
  name       = "my-terraform-ec2-container-registry-read-only"
  roles      = [aws_iam_role.eks_nodegroup_role.name]
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

# --- 3. EKS Cluster ---
resource "aws_eks_cluster" "main" {
  name     = "my-terraform-eks-cluster"
  role_arn = aws_iam_role.eks_cluster_role.arn
  version  = "1.28" # Specify a supported Kubernetes version

  vpc_config {
    subnet_ids = [
      aws_subnet.eks_public_subnet_1.id,
      aws_subnet.eks_public_subnet_2.id,
      aws_subnet.eks_private_subnet_1.id,
      aws_subnet.eks_private_subnet_2.id,
    ]
    endpoint_private_access = false
    endpoint_public_access  = true
  }

  # Enable OIDC provider for IRSA
  enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]

  depends_on = [
    aws_iam_role_policy_attachment.eks_cluster_policy,
    aws_iam_role_policy_attachment.eks_vpc_cni_policy,
  ]

  tags = {
    Name = "my-terraform-eks-cluster"
  }
}

# --- 4. Managed Node Group ---
resource "aws_eks_node_group" "main" {
  cluster_name    = aws_eks_cluster.main.name
  node_group_name = "my-terraform-managed-nodegroup"
  node_role_arn   = aws_iam_role.eks_nodegroup_role.arn
  subnet_ids      = [aws_subnet.eks_private_subnet_1.id, aws_subnet.eks_private_subnet_2.id]
  instance_types  = ["t3.medium"]
  ami_type        = "AL2_x86_64" # Amazon Linux 2
  disk_size       = 20

  scaling_config {
    desired_size = 2
    max_size     = 3
    min_size     = 1
  }

  update_config {
    max_unavailable = 1
  }

  depends_on = [
    aws_iam_policy_attachment.eks_worker_node_policy,
    aws_iam_policy_attachment.eks_cni_policy,
    aws_iam_policy_attachment.ec2_container_registry_read_only,
  ]

  tags = {
    Name = "my-terraform-eks-nodegroup"
  }
}

# --- Outputs ---
output "eks_cluster_name" {
  value       = aws_eks_cluster.main.name
  description = "The name of the EKS cluster."
}

output "eks_cluster_endpoint" {
  value       = aws_eks_cluster.main.endpoint
  description = "The endpoint of the EKS cluster."
}

output "eks_kubeconfig_command" {
  value       = "aws eks update-kubeconfig --name ${aws_eks_cluster.main.name} --region ${provider.aws.region}"
  description = "Command to update your kubeconfig to connect to the EKS cluster."
}
