################################################################################################################################################
#                                                                 VPC                                                                          #
################################################################################################################################################

module "vpc" {
    source  = "terraform-aws-modules/vpc/aws"
    version = "~> 5.0"

    name            = "demo-vpc"
    cidr            = "10.0.0.0/16"
    azs             = ["ap-northeast-2a", "ap-northeast-2b"]

    public_subnets  = ["10.0.1.0/24", "10.0.2.0/24"]
    public_subnet_names = ["demo-public-subnet-a" , "demo-public-subnet-b"]
    map_public_ip_on_launch = true
    public_subnet_tags = {
      "kubernetes.io/role/elb" = 1
    }

    private_subnets = ["10.0.3.0/24", "10.0.4.0/24"]
    private_subnet_names = ["demo-private-subnet-a" , "demo-private-subnet-b"]

    enable_nat_gateway = true
    single_nat_gateway = false
    one_nat_gateway_per_az = true

    enable_dns_hostnames = true
    enable_dns_support   = true
}

################################################################################################################################################
#                                                                 EC2                                                                          #
################################################################################################################################################

data "aws_ssm_parameter" "latest_ami" {
  name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64"
}

resource "tls_private_key" "rsa" {
  algorithm = "RSA"
  rsa_bits = 4096
}

resource "aws_key_pair" "keypair" {
  key_name   = "bastion"
  public_key = tls_private_key.rsa.public_key_openssh
}

resource "local_file" "keypair" {
  content = tls_private_key.rsa.private_key_pem
  filename = "bastion.pem"
}

resource "aws_security_group" "bastion_sg" {
  name        = "bastion-sg"
  description = "bastion-sg"
  vpc_id      = module.vpc.vpc_id

  ingress {
    from_port   = 22
    to_port     = 22
    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 = {
    Name = "bastion-sg"
  }
}

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

  managed_policy_arns = ["arn:aws:iam::aws:policy/AdministratorAccess"]
}

resource "aws_iam_instance_profile" "bastion" {
  name = "bastion-role"
  role = aws_iam_role.bastion.name
}

resource "aws_eip" "bastion" {
  depends_on = [aws_instance.bastion]
}

resource "aws_instance" "bastion" {
  ami = data.aws_ssm_parameter.latest_ami.value
  instance_type          = "t3.micro"
  subnet_id              = module.vpc.public_subnets[0]
  associate_public_ip_address = true
  iam_instance_profile   = aws_iam_instance_profile.bastion.name
  key_name               = aws_key_pair.keypair.key_name
  vpc_security_group_ids = [aws_security_group.bastion_sg.id]
  user_data = "${file("./src/userdata.sh")}"

  tags = {
    Name = "bastion"
  }
}

resource "aws_eip_association" "bastion_eip_assoc" {
  instance_id   = aws_instance.bastion.id
  allocation_id = aws_eip.bastion.id
}

output "bastion_details" {
  value = {
    ip_address        = aws_eip.bastion.public_ip
    instance_id       = aws_instance.bastion.id
    availability_zone = aws_instance.bastion.availability_zone
  }
}

################################################################################################################################################
#                                                     Karmada Control API EKS                                                                  #
################################################################################################################################################

module "karmada_eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.37.2"

  cluster_name    = "demo-karmada-cluster"
  cluster_version = "1.32"

  cluster_addons = {
    coredns                = {}
    eks-pod-identity-agent = {}
    kube-proxy             = {}
    vpc-cni                = {}
  }

  cluster_security_group_additional_rules = {
    hybrid-all = {
      cidr_blocks = [module.vpc.vpc_cidr_block]
      description = "Allow all traffic from remote node/pod network"
      from_port   = 0
      to_port     = 0
      protocol    = "all"
      type        = "ingress"
    }
  }

  enable_cluster_creator_admin_permissions = true

  access_entries = {
    example = {
      kubernetes_groups = []
      principal_arn     = aws_iam_role.bastion.arn

      policy_associations = {
        example = {
          policy_arn   = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type       = "cluster"
          }
        }
      }
    }
  }

  # Optional
  cluster_endpoint_public_access = true
  cluster_endpoint_private_access = true

  vpc_id                   = module.vpc.vpc_id
  subnet_ids               = [ module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]
  control_plane_subnet_ids = [ module.vpc.public_subnets[0], module.vpc.public_subnets[1], module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]

  eks_managed_node_groups = {
    karmada-ng = {
      use_name_prefix   = false
      name              = "karmada-ng"

      ami_type       = "BOTTLEROCKET_x86_64"
      instance_types = ["t3.small"]
      labels          = { app = "karmada"}

      desired_size = 2
      min_size     = 2
      max_size     = 10

      iam = {
        with_addon_policies = {
          image_builder         = true
          aws_load_balancer_controller   = true
          auto_scaler         = true
        }
      }
      create_launch_template = true
      launch_template_name   = "karmada-node-lt"
      launch_template_tags = {
        Name = "karmada-node"
      }
    }
  }
}

################################################################################################################################################
#                                                         Production EKS                                                                       #
################################################################################################################################################

module "prod_eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.37.2"

  cluster_name    = "demo-prod-cluster"
  cluster_version = "1.32"

  cluster_addons = {
    coredns                = {}
    eks-pod-identity-agent = {}
    kube-proxy             = {}
    vpc-cni                = {}
  }

  cluster_security_group_additional_rules = {
    hybrid-all = {
      cidr_blocks = [module.vpc.vpc_cidr_block]
      description = "Allow all traffic from remote node/pod network"
      from_port   = 0
      to_port     = 0
      protocol    = "all"
      type        = "ingress"
    }
  }

  enable_cluster_creator_admin_permissions = true

  access_entries = {
  # One access entry with a policy associated
    example = {
      kubernetes_groups = []
      principal_arn     = aws_iam_role.bastion.arn

      policy_associations = {
        example = {
          policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type       = "cluster"
          }
        }
      }
    }
  }

  # Optional
  cluster_endpoint_public_access = true
  cluster_endpoint_private_access = true

  vpc_id                   = module.vpc.vpc_id
  subnet_ids               = [ module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]
  control_plane_subnet_ids = [ module.vpc.public_subnets[0], module.vpc.public_subnets[1], module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]

  eks_managed_node_groups = {
    app-ng = {
      use_name_prefix   = false
      name              = "app-ng-prod"

      ami_type       = "BOTTLEROCKET_x86_64"
      instance_types = ["t3.small"]
      labels          = { app = "nga-prod"}

      desired_size = 2
      min_size     = 2
      max_size     = 10

      iam = {
        with_addon_policies = {
          image_builder = true
          aws_load_balancer_controller = true
          auto_scaler = true
        }
      }
      create_launch_template = true
      launch_template_name   = "app-node-lt-prod"
      launch_template_tags = {
        Name = "app-node-prod"
      }
    }
  }
}

################################################################################################################################################
#                                                         Staging EKS                                                                          #
################################################################################################################################################
module "staging_eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.37.2"

  cluster_name    = "demo-staging-cluster"
  cluster_version = "1.32"

  cluster_addons = {
    coredns                = {}
    eks-pod-identity-agent = {}
    kube-proxy             = {}
    vpc-cni                = {}
  }

  cluster_security_group_additional_rules = {
    hybrid-all = {
      cidr_blocks = [module.vpc.vpc_cidr_block]
      description = "Allow all traffic from remote node/pod network"
      from_port   = 0
      to_port     = 0
      protocol    = "all"
      type        = "ingress"
    }
  }

  enable_cluster_creator_admin_permissions = true

  access_entries = {
    example = {
      kubernetes_groups = []
      principal_arn     = aws_iam_role.bastion.arn

      policy_associations = {
        example = {
          policy_arn   = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type       = "cluster"
          }
        }
      }
    }
  }

  # Optional
  cluster_endpoint_public_access = true
  cluster_endpoint_private_access = true

  vpc_id                   = module.vpc.vpc_id
  subnet_ids               = [ module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]
  control_plane_subnet_ids = [ module.vpc.public_subnets[0], module.vpc.public_subnets[1], module.vpc.private_subnets[0], module.vpc.private_subnets[1] ]

  eks_managed_node_groups = {
    app-ng-staging = {
      use_name_prefix   = false
      name              = "app-ng-staging"

      ami_type       = "BOTTLEROCKET_x86_64"
      instance_types = ["t3.small"]
      labels          = { app = "nga-staging"}

      desired_size = 2
      min_size     = 2
      max_size     = 10

      iam = {
        with_addon_policies = {
          image_builder         = true
          aws_load_balancer_controller   = true
          auto_scaler         = true
        }
      }
      create_launch_template = true
      launch_template_name   = "app-node-lt-staging"  
      launch_template_tags = {
        Name = "app-node-staging"
      }
    }
  }
}