├── .gitignore ├── README.md ├── argocd.tf ├── aws-alb-controller.tf ├── eks.tf ├── main.tf ├── network.tf ├── variables.tf └── versions.tf /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | crash.*.log 11 | 12 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 13 | # password, private keys, and other secrets. These should not be part of version 14 | # control as they are data points which are potentially sensitive and subject 15 | # to change depending on the environment. 16 | *.tfvars 17 | *.tfvars.json 18 | 19 | # Ignore override files as they are usually used to override resources locally and so 20 | # are not checked in 21 | override.tf 22 | override.tf.json 23 | *_override.tf 24 | *_override.tf.json 25 | 26 | # Include override files you do wish to add to version control using negated pattern 27 | # !example_override.tf 28 | 29 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 30 | # example: *tfplan* 31 | 32 | # Ignore CLI configuration files 33 | .terraformrc 34 | terraform.rc 35 | 36 | # Ignore Dependency Lock File 37 | .terraform.lock.hcl 38 | 39 | # Ignore old and testing files 40 | old 41 | old/* 42 | testing 43 | testing/* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EKS infrastructure by Terraform 2 | This repository includes the required Terraform files to provision following components, 3 | - Single node group EKS cluster 4 | - AWS Load Balancer Controller 5 | - ArgoCD server exposed by AWS Application Load Balancer 6 | 7 | # terraform versions tested 8 | - Terraform v1.5.7 9 | - provider aws v5.23.1 10 | - provider cloudinit v2.3.2 11 | - provider external v2.3.1 12 | - provider helm v2.11.0 13 | - provider kubernetes v2.23.0 14 | - provider null v3.2.1 15 | - provider time v0.9.1 16 | - provider tls v4.0.4 17 | 18 | # Usage 19 | 1. Clone this repository 20 | 2. `cd` to the repository folder 21 | 3. Initialize terraform dependencies by, 22 | ``` 23 | terraform init 24 | ``` 25 | 4. Get the list of resources being created by, 26 | ``` 27 | terraform plan 28 | ``` 29 | 5. Create the planned resources by, 30 | ``` 31 | terraform apply 32 | ``` -------------------------------------------------------------------------------- /argocd.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_namespace_v1" "argocd_namespace" { 2 | metadata { 3 | name = var.argocd_target_namespace 4 | } 5 | 6 | depends_on = [ module.eks ] 7 | } 8 | 9 | resource "helm_release" "argocd" { 10 | name = var.argocd_deploy_name 11 | repository = var.argocd_helm_repo_url 12 | chart = var.argocd_helm_chart_name 13 | namespace = var.argocd_target_namespace 14 | cleanup_on_fail = true 15 | depends_on = [ helm_release.alb-controller, kubernetes_namespace_v1.argocd_namespace ] 16 | 17 | set { 18 | # Run server without TLS 19 | name = "configs.params.server\\.insecure" 20 | value = var.argocd_server_insecure 21 | } 22 | 23 | } 24 | 25 | resource "kubernetes_ingress_v1" "argocd_ingress" { 26 | metadata { 27 | name = "argocd-ingress" 28 | namespace = "argocd" 29 | annotations = { 30 | "alb.ingress.kubernetes.io/scheme" = "internet-facing" 31 | "alb.ingress.kubernetes.io/target-type" = "ip" 32 | } 33 | } 34 | 35 | spec { 36 | ingress_class_name = "alb" 37 | 38 | rule { 39 | http { 40 | path { 41 | path = "/" 42 | path_type = "Prefix" 43 | backend { 44 | service { 45 | name = "argocd-server" 46 | port { 47 | number = 80 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | depends_on = [ helm_release.argocd, module.eks, module.lbc_role, module.vpc, kubernetes_namespace_v1.argocd_namespace ] 57 | } -------------------------------------------------------------------------------- /aws-alb-controller.tf: -------------------------------------------------------------------------------- 1 | module "lbc_role" { 2 | source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks" 3 | 4 | create_role = true 5 | 6 | role_name = "${var.env_name}_eks_lbc" 7 | 8 | attach_load_balancer_controller_policy = true 9 | 10 | oidc_providers = { 11 | main = { 12 | provider_arn = module.eks.oidc_provider_arn 13 | namespace_service_accounts = ["${var.alb_controller_target_namespace}:${var.alb_controller_deploy_name}"] 14 | } 15 | } 16 | } 17 | 18 | resource "kubernetes_service_account" "service-account" { 19 | metadata { 20 | name = var.alb_controller_deploy_name 21 | namespace = var.alb_controller_target_namespace 22 | labels = { 23 | "app.kubernetes.io/name" = var.alb_controller_deploy_name 24 | "app.kubernetes.io/component" = "controller" 25 | } 26 | annotations = { 27 | "eks.amazonaws.com/role-arn" = module.lbc_role.iam_role_arn 28 | "eks.amazonaws.com/sts-regional-endpoints" = "true" 29 | } 30 | } 31 | } 32 | 33 | resource "helm_release" "alb-controller" { 34 | name = var.alb_controller_deploy_name 35 | repository = var.alb_controller_helm_repo_url 36 | chart = var.alb_controller_helm_chart_name 37 | namespace = var.alb_controller_target_namespace 38 | depends_on = [ 39 | kubernetes_service_account.service-account 40 | ] 41 | 42 | set { 43 | name = "region" 44 | value = var.aws_region 45 | } 46 | 47 | set { 48 | name = "vpcId" 49 | value = module.vpc.vpc_id 50 | } 51 | 52 | set { 53 | name = "image.repository" 54 | value = "602401143452.dkr.ecr.${var.aws_region}.amazonaws.com/amazon/aws-load-balancer-controller" 55 | } 56 | 57 | set { 58 | name = "serviceAccount.create" 59 | value = "false" 60 | } 61 | 62 | set { 63 | name = "serviceAccount.name" 64 | value = kubernetes_service_account.service-account.metadata[0].name 65 | } 66 | 67 | set { 68 | name = "clusterName" 69 | value = module.eks.cluster_name 70 | } 71 | } -------------------------------------------------------------------------------- /eks.tf: -------------------------------------------------------------------------------- 1 | module "eks" { 2 | source = "terraform-aws-modules/eks/aws" 3 | version = "~> 19.17.2" 4 | 5 | cluster_name = "${var.env_name}-cluster" 6 | cluster_version = var.cluster_version 7 | 8 | cluster_endpoint_public_access = true 9 | enable_irsa = true 10 | 11 | cluster_addons = var.cluster_addons 12 | 13 | vpc_id = module.vpc.vpc_id 14 | subnet_ids = concat(sort(module.vpc.public_subnets), sort(module.vpc.private_subnets)) 15 | 16 | eks_managed_node_group_defaults = { 17 | instance_types = var.default_instance_types 18 | } 19 | 20 | eks_managed_node_groups = var.eks_managed_node_groups 21 | } -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.aws_region 3 | shared_credentials_files = ["${var.aws_cred_file_path}"] 4 | profile = var.aws_cred_profile 5 | 6 | default_tags { 7 | tags = { 8 | provision-by = var.provisioner 9 | env = var.env_name 10 | } 11 | } 12 | } 13 | 14 | provider "kubernetes" { 15 | host = module.eks.cluster_endpoint 16 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) 17 | exec { 18 | api_version = "client.authentication.k8s.io/v1beta1" 19 | command = "aws" 20 | # This requires the awscli to be installed locally where Terraform is executed 21 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name] 22 | } 23 | } 24 | 25 | provider "helm" { 26 | kubernetes { 27 | host = module.eks.cluster_endpoint 28 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data) 29 | exec { 30 | api_version = "client.authentication.k8s.io/v1beta1" 31 | args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name] 32 | command = "aws" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /network.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | azs = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"] 3 | num_of_az = length(local.azs) 4 | subnet_cidr = cidrsubnets(var.vpc_cidr, var.public_subnets_cidr_root_newbits, var.private_subnets_cidr_root_newbits) 5 | } 6 | 7 | locals { 8 | public_subnets_list_cidr = cidrsubnets(local.subnet_cidr[0], [for i in range(local.num_of_az): var.public_subnets_cidr_sub_newbits]...) 9 | private_subnets_list_cidr = cidrsubnets(local.subnet_cidr[1], [for i in range(local.num_of_az): var.private_subnets_cidr_sub_newbits]...) 10 | } 11 | 12 | module "vpc" { 13 | source = "terraform-aws-modules/vpc/aws" 14 | 15 | name = "${var.name_prefix}-vpc" 16 | cidr = var.vpc_cidr 17 | 18 | azs = local.azs 19 | public_subnets = local.public_subnets_list_cidr 20 | private_subnets = local.private_subnets_list_cidr 21 | 22 | public_subnet_tags = { 23 | "kubernetes.io/role/elb" = 1 24 | } 25 | 26 | private_subnet_tags = { 27 | "kubernetes.io/role/internal-elb" = 1 28 | } 29 | 30 | enable_nat_gateway = true 31 | single_nat_gateway = true 32 | enable_vpn_gateway = true 33 | create_igw = true 34 | map_public_ip_on_launch = true 35 | } -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | ###################################################################### 2 | ## Core 3 | variable "name_prefix" { 4 | type = string 5 | default = "eks-env" 6 | } 7 | 8 | variable "aws_region" { 9 | type = string 10 | default = "us-east-1" 11 | } 12 | 13 | variable "aws_cred_file_path" { 14 | type = string 15 | default = "~/.aws/credentials" 16 | } 17 | 18 | variable "aws_cred_profile" { 19 | type = string 20 | default = "default" 21 | } 22 | 23 | variable "env_name" { 24 | type = string 25 | default = "dev" 26 | } 27 | 28 | variable "provisioner" { 29 | type = string 30 | default = "terraform" 31 | } 32 | 33 | ###################################################################### 34 | ## Network 35 | variable "vpc_cidr" { 36 | type = string 37 | default = "10.0.0.0/16" 38 | } 39 | 40 | variable "public_subnets_cidr_root_newbits" { 41 | type = number 42 | default = 4 43 | } 44 | 45 | variable "public_subnets_cidr_sub_newbits" { 46 | type = number 47 | default = 4 48 | } 49 | 50 | variable "private_subnets_cidr_root_newbits" { 51 | type = number 52 | default = 4 53 | } 54 | 55 | variable "private_subnets_cidr_sub_newbits" { 56 | type = number 57 | default = 4 58 | } 59 | 60 | ###################################################################### 61 | ## EKS 62 | variable "cluster_version" { 63 | type = number 64 | default = 1.28 65 | } 66 | 67 | variable "cluster_addons" { 68 | type = map(object({ 69 | most_recent = bool 70 | preserve = optional(bool) 71 | })) 72 | 73 | default = { 74 | coredns = { 75 | most_recent = true 76 | preserve = true 77 | } 78 | kube-proxy = { 79 | most_recent = true 80 | } 81 | vpc-cni = { 82 | most_recent = true 83 | } 84 | } 85 | } 86 | 87 | variable "default_instance_types" { 88 | type = list(string) 89 | default = [ "t3a.large" ] 90 | } 91 | 92 | variable "eks_managed_node_groups" { 93 | type = map(object({ 94 | name = string 95 | min_size = number 96 | max_size = number 97 | desired_size = number 98 | instance_types = list(string) 99 | })) 100 | 101 | default = { 102 | "app-node" = { 103 | name = "app-ng-1" 104 | min_size = 1 105 | max_size = 1 106 | desired_size = 1 107 | instance_types = ["t3a.large"] 108 | } 109 | } 110 | } 111 | 112 | ###################################################################### 113 | ## AWS ALB Controller 114 | variable "alb_controller_deploy_name" { 115 | type = string 116 | default = "aws-load-balancer-controller" 117 | } 118 | 119 | variable "alb_controller_helm_chart_name" { 120 | type = string 121 | default = "aws-load-balancer-controller" 122 | } 123 | 124 | variable "alb_controller_helm_repo_url" { 125 | type = string 126 | default = "https://aws.github.io/eks-charts" 127 | } 128 | 129 | variable "alb_controller_target_namespace" { 130 | type = string 131 | default = "kube-system" 132 | } 133 | 134 | ###################################################################### 135 | ## ArgoCD 136 | variable "argocd_deploy_name" { 137 | type = string 138 | default = "argocd" 139 | } 140 | 141 | variable "argocd_helm_chart_name" { 142 | type = string 143 | default = "argo-cd" 144 | } 145 | 146 | variable "argocd_helm_repo_url" { 147 | type = string 148 | default = "https://argoproj.github.io/argo-helm" 149 | } 150 | 151 | variable "argocd_target_namespace" { 152 | type = string 153 | default = "argocd" 154 | } 155 | 156 | variable "argocd_server_insecure" { 157 | type = bool 158 | default = true 159 | } -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 5.23.1" 6 | } 7 | } 8 | } --------------------------------------------------------------------------------