├── modules ├── network │ ├── region.tf │ ├── vpc.tf │ ├── output.tf │ ├── variables.tf │ ├── igw.tf │ ├── private.tf │ ├── public.tf │ ├── ngw.tf │ └── README.md ├── aws-load-balancer-controller │ ├── locals.tf │ ├── data.tf │ ├── serviceaccount.tf │ ├── policy.tf │ ├── variables.tf │ ├── helm.tf │ ├── iam.tf │ ├── README.md │ └── iam_policy.json ├── cluster │ ├── sg-rule.tf │ ├── output.tf │ ├── oidc.tf │ ├── variables.tf │ ├── cluster.tf │ ├── iam.tf │ └── README.md └── managed-node-group │ ├── variables.tf │ ├── mng.tf │ ├── iam.tf │ └── README.md ├── output.tf ├── .pre-commit-config.yaml ├── variables.tf ├── .gitignore ├── modules.tf ├── LICENSE ├── provider.tf └── README.md /modules/network/region.tf: -------------------------------------------------------------------------------- 1 | data "aws_region" "current" {} 2 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | oidc = split("/", var.oidc)[4] 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/data.tf: -------------------------------------------------------------------------------- 1 | data "aws_caller_identity" "current" {} 2 | 3 | data "aws_region" "current" {} -------------------------------------------------------------------------------- /output.tf: -------------------------------------------------------------------------------- 1 | output "oidc" { 2 | value = module.eks_cluster.oidc 3 | } 4 | 5 | output "certificate_authority" { 6 | value = module.eks_cluster.certificate_authority 7 | } 8 | 9 | output "cluster_endpoint" { 10 | value = module.eks_cluster.cluster_endpoint 11 | } 12 | -------------------------------------------------------------------------------- /modules/network/vpc.tf: -------------------------------------------------------------------------------- 1 | resource "aws_vpc" "eks_vpc" { 2 | cidr_block = var.cidr_block 3 | enable_dns_support = true 4 | enable_dns_hostnames = true 5 | tags = merge( 6 | var.tags, 7 | { 8 | Name = "${var.project_name}-vpc" 9 | } 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /modules/cluster/sg-rule.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group_rule" "eks_cluster_sg_rule" { 2 | type = "ingress" 3 | from_port = 443 4 | to_port = 443 5 | protocol = "tcp" 6 | cidr_blocks = [ 7 | "0.0.0.0/0" 8 | ] 9 | security_group_id = aws_eks_cluster.eks_cluster.vpc_config[0].cluster_security_group_id 10 | } -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/serviceaccount.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_service_account" "example" { 2 | metadata { 3 | name = "aws-load-balancer-controller" 4 | namespace = "kube-system" 5 | annotations = { 6 | "eks.amazonaws.com/role-arn" = aws_iam_role.eks_controller_role.arn 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/policy.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_policy" "eks_controller_policy" { 2 | name = "${var.project_name}-aws-load-balancer-controller" 3 | 4 | # Terraform's "jsonencode" function converts a 5 | # Terraform expression result to valid JSON syntax. 6 | policy = file("${path.module}/iam_policy.json") 7 | tags = var.tags 8 | } 9 | -------------------------------------------------------------------------------- /modules/network/output.tf: -------------------------------------------------------------------------------- 1 | output "subnet_pub_1a" { 2 | value = aws_subnet.eks_subnet_public-1a.id 3 | } 4 | 5 | output "subnet_pub_1b" { 6 | value = aws_subnet.eks_subnet_public-1b.id 7 | } 8 | 9 | output "subnet_priv_1a" { 10 | value = aws_subnet.eks_subnet_private-1a.id 11 | } 12 | 13 | output "subnet_priv_1b" { 14 | value = aws_subnet.eks_subnet_private-1b.id 15 | } 16 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.89.0 4 | hooks: 5 | - id: terraform_fmt 6 | args: 7 | - --args=-recursive 8 | - --hook-config=--parallelism-ci-cpu-cores=2 9 | - id: terraform_validate 10 | - id: terraform_docs 11 | args: 12 | - --args=--output-file README.md 13 | -------------------------------------------------------------------------------- /modules/cluster/output.tf: -------------------------------------------------------------------------------- 1 | output "cluster_name" { 2 | value = aws_eks_cluster.eks_cluster.id 3 | } 4 | 5 | output "oidc" { 6 | value = aws_eks_cluster.eks_cluster.identity[0].oidc[0].issuer 7 | } 8 | 9 | output "certificate_authority" { 10 | value = aws_eks_cluster.eks_cluster.certificate_authority[0].data 11 | } 12 | 13 | output "cluster_endpoint" { 14 | value = aws_eks_cluster.eks_cluster.endpoint 15 | } 16 | -------------------------------------------------------------------------------- /modules/network/variables.tf: -------------------------------------------------------------------------------- 1 | variable "cidr_block" { 2 | type = string 3 | description = "Networking CIDR block to be used for the VPC" 4 | } 5 | 6 | variable "project_name" { 7 | type = string 8 | description = "Project name to be used to name the resources (Name tag)" 9 | 10 | } 11 | 12 | variable "tags" { 13 | type = map(any) 14 | description = "Tags to be added to AWS resources" 15 | 16 | } 17 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "cidr_block" { 2 | type = string 3 | description = "Networking CIDR block to be used for the VPC" 4 | } 5 | 6 | variable "project_name" { 7 | type = string 8 | description = "Project name to be used to name the resources (Name tag)" 9 | 10 | } 11 | 12 | variable "region" { 13 | type = string 14 | description = "AWS regiton to create the resources" 15 | 16 | } 17 | 18 | variable "tags" { 19 | type = map(any) 20 | description = "A map of tags to add to all AWS resources" 21 | 22 | } 23 | -------------------------------------------------------------------------------- /modules/cluster/oidc.tf: -------------------------------------------------------------------------------- 1 | data "tls_certificate" "eks_oidc_tls_certificate" { 2 | url = aws_eks_cluster.eks_cluster.identity[0].oidc[0].issuer 3 | } 4 | 5 | resource "aws_iam_openid_connect_provider" "eks_oidc" { 6 | client_id_list = ["sts.amazonaws.com"] 7 | thumbprint_list = [data.tls_certificate.eks_oidc_tls_certificate.certificates[0].sha1_fingerprint] 8 | url = data.tls_certificate.eks_oidc_tls_certificate.url 9 | tags = merge( 10 | var.tags, 11 | { 12 | Name = "${var.project_name}-oidc" 13 | } 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /modules/cluster/variables.tf: -------------------------------------------------------------------------------- 1 | variable "project_name" { 2 | type = string 3 | description = "Project name to be used to name the resources (Name tag)" 4 | 5 | } 6 | 7 | variable "tags" { 8 | type = map(any) 9 | description = "Tags to be added to AWS resources" 10 | 11 | } 12 | 13 | variable "public_subnet_1a" { 14 | type = string 15 | description = "Subnet to create EKS cluster AZ 1a" 16 | } 17 | 18 | variable "public_subnet_1b" { 19 | type = string 20 | description = "Subnet to create EKS cluster AZ 1b" 21 | } 22 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/variables.tf: -------------------------------------------------------------------------------- 1 | variable "project_name" { 2 | type = string 3 | description = "Project name to be used to name the resources (Name tag)" 4 | 5 | } 6 | 7 | variable "tags" { 8 | type = map(any) 9 | description = "Tags to be added to AWS resources" 10 | 11 | } 12 | 13 | variable "oidc" { 14 | type = string 15 | description = "HTTPS URL from OIDC provider of the EKS cluster" 16 | } 17 | 18 | variable "cluster_name" { 19 | type = string 20 | description = "EKS cluster name" 21 | 22 | } 23 | -------------------------------------------------------------------------------- /modules/network/igw.tf: -------------------------------------------------------------------------------- 1 | resource "aws_internet_gateway" "eks_igw" { 2 | vpc_id = aws_vpc.eks_vpc.id 3 | 4 | tags = merge( 5 | var.tags, 6 | { 7 | Name = "${var.project_name}-eks_igw" 8 | } 9 | ) 10 | } 11 | 12 | resource "aws_route_table" "eks_public_route_table" { 13 | vpc_id = aws_vpc.eks_vpc.id 14 | 15 | route { 16 | cidr_block = "0.0.0.0/0" 17 | gateway_id = aws_internet_gateway.eks_igw.id 18 | } 19 | 20 | tags = merge( 21 | var.tags, 22 | { 23 | Name = "${var.project_name}-pub-route-table" 24 | } 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /modules/cluster/cluster.tf: -------------------------------------------------------------------------------- 1 | resource "aws_eks_cluster" "eks_cluster" { 2 | name = "${var.project_name}-cluster" 3 | role_arn = aws_iam_role.eks_cluster_role.arn 4 | 5 | vpc_config { 6 | subnet_ids = [ 7 | var.public_subnet_1a, 8 | var.public_subnet_1b 9 | ] 10 | endpoint_private_access = true 11 | endpoint_public_access = true 12 | } 13 | depends_on = [ 14 | aws_iam_role_policy_attachment.eks_cluster_role_attachment 15 | ] 16 | 17 | tags = merge( 18 | var.tags, 19 | { 20 | Name = "${var.project_name}-cluster" 21 | } 22 | ) 23 | } -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/helm.tf: -------------------------------------------------------------------------------- 1 | resource "helm_release" "eks_helm_controller" { 2 | name = "aws-load-balancer-controller" 3 | repository = "https://aws.github.io/eks-charts" 4 | chart = "aws-load-balancer-controller" 5 | version = "1.7.2" 6 | namespace = "kube-system" 7 | 8 | set { 9 | name = "clusterName" 10 | value = var.cluster_name 11 | } 12 | 13 | set { 14 | name = "serviceAccount.create" 15 | value = "false" 16 | } 17 | 18 | set { 19 | name = "serviceAccount.name" 20 | value = "aws-load-balancer-controller " 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /modules/managed-node-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "project_name" { 2 | type = string 3 | description = "Project name to be used to name the resources (Name tag)" 4 | 5 | } 6 | 7 | variable "tags" { 8 | type = map(any) 9 | description = "Tags to be added to AWS resources" 10 | 11 | } 12 | 13 | variable "cluster_name" { 14 | type = string 15 | description = "EKS cluster name to create MNG" 16 | 17 | } 18 | 19 | variable "subnet_private_1a" { 20 | type = string 21 | description = "Subnet ID from AZ 1a" 22 | 23 | } 24 | variable "subnet_private_1b" { 25 | type = string 26 | description = "Subnet ID from AZ 1b" 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modules/cluster/iam.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "eks_cluster_role" { 2 | name = "${var.project_name}-cluster-role" 3 | 4 | # Terraform's "jsonencode" function converts a 5 | # Terraform expression result to valid JSON syntax. 6 | assume_role_policy = jsonencode({ 7 | Version = "2012-10-17" 8 | Statement = [ 9 | { 10 | Action = "sts:AssumeRole" 11 | Effect = "Allow" 12 | Sid = "" 13 | Principal = { 14 | Service = "eks.amazonaws.com" 15 | } 16 | }, 17 | ] 18 | }) 19 | 20 | tags = merge( 21 | var.tags, 22 | { 23 | Name = "${var.project_name}-cluster-role" 24 | } 25 | ) 26 | } 27 | 28 | resource "aws_iam_role_policy_attachment" "eks_cluster_role_attachment" { 29 | role = aws_iam_role.eks_cluster_role.name 30 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" 31 | } 32 | -------------------------------------------------------------------------------- /modules/managed-node-group/mng.tf: -------------------------------------------------------------------------------- 1 | resource "aws_eks_node_group" "eks_managed_node_group" { 2 | cluster_name = var.cluster_name 3 | node_group_name = "${var.project_name}-nodegroup" 4 | node_role_arn = aws_iam_role.eks_mng_role.arn 5 | subnet_ids = [ 6 | var.subnet_private_1a, 7 | var.subnet_private_1b 8 | ] 9 | 10 | tags = merge( 11 | var.tags, 12 | { 13 | Name = "${var.project_name}-nodegroup" 14 | } 15 | ) 16 | scaling_config { 17 | desired_size = 1 18 | max_size = 1 19 | min_size = 1 20 | } 21 | 22 | # Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling. 23 | # Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces. 24 | depends_on = [ 25 | aws_iam_role_policy_attachment.eks_mng_role_attachment_worker, 26 | aws_iam_role_policy_attachment.eks_mng_role_attachment_cni, 27 | aws_iam_role_policy_attachment.eks_mng_role_attachment_ecr, 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | .terraform.lock.hcl 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 | -------------------------------------------------------------------------------- /modules.tf: -------------------------------------------------------------------------------- 1 | module "eks_network" { 2 | source = "./modules/network" 3 | cidr_block = var.cidr_block 4 | project_name = var.project_name 5 | tags = var.tags 6 | } 7 | 8 | module "eks_cluster" { 9 | source = "./modules/cluster" 10 | project_name = var.project_name 11 | tags = var.tags 12 | public_subnet_1a = module.eks_network.subnet_pub_1a 13 | public_subnet_1b = module.eks_network.subnet_pub_1b 14 | } 15 | 16 | module "eks_managed_node_group" { 17 | source = "./modules/managed-node-group" 18 | project_name = var.project_name 19 | cluster_name = module.eks_cluster.cluster_name 20 | subnet_private_1a = module.eks_network.subnet_priv_1a 21 | subnet_private_1b = module.eks_network.subnet_priv_1b 22 | tags = var.tags 23 | } 24 | 25 | module "eks_aws_load_balancer_controller" { 26 | source = "./modules/aws-load-balancer-controller" 27 | project_name = var.project_name 28 | tags = var.tags 29 | oidc = module.eks_cluster.oidc 30 | cluster_name = module.eks_cluster.cluster_name 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Lucas Cosme 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /modules/network/private.tf: -------------------------------------------------------------------------------- 1 | resource "aws_subnet" "eks_subnet_private-1a" { 2 | vpc_id = aws_vpc.eks_vpc.id 3 | cidr_block = cidrsubnet(var.cidr_block, 8, 3) 4 | availability_zone = "${data.aws_region.current.name}a" 5 | 6 | tags = merge( 7 | var.tags, 8 | { 9 | Name = "${var.project_name}-priv-subnet-1a" 10 | "kubernetes.io/role/internal-elb" = 1 11 | } 12 | ) 13 | } 14 | 15 | resource "aws_subnet" "eks_subnet_private-1b" { 16 | vpc_id = aws_vpc.eks_vpc.id 17 | cidr_block = cidrsubnet(var.cidr_block, 8, 4) 18 | availability_zone = "${data.aws_region.current.name}b" 19 | 20 | tags = merge( 21 | var.tags, 22 | { 23 | Name = "${var.project_name}-priv-subnet-1b" 24 | "kubernetes.io/role/internal-elb" = 1 25 | } 26 | ) 27 | } 28 | 29 | resource "aws_route_table_association" "eks_rtb_assoc_priv_1a" { 30 | subnet_id = aws_subnet.eks_subnet_private-1a.id 31 | route_table_id = aws_route_table.eks_private_route_table_1a.id 32 | } 33 | 34 | resource "aws_route_table_association" "eks_rtb_assoc_priv_1b" { 35 | subnet_id = aws_subnet.eks_subnet_private-1b.id 36 | route_table_id = aws_route_table.eks_private_route_table_1b.id 37 | } 38 | 39 | -------------------------------------------------------------------------------- /modules/managed-node-group/iam.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "eks_mng_role" { 2 | name = "${var.project_name}-mng-role" 3 | 4 | # Terraform's "jsonencode" function converts a 5 | # Terraform expression result to valid JSON syntax. 6 | assume_role_policy = jsonencode({ 7 | Version = "2012-10-17" 8 | Statement = [ 9 | { 10 | Action = "sts:AssumeRole" 11 | Effect = "Allow" 12 | Sid = "" 13 | Principal = { 14 | Service = "ec2.amazonaws.com" 15 | } 16 | }, 17 | ] 18 | }) 19 | 20 | tags = merge( 21 | var.tags, 22 | { 23 | Name = "${var.project_name}-mng-role" 24 | } 25 | ) 26 | } 27 | 28 | resource "aws_iam_role_policy_attachment" "eks_mng_role_attachment_worker" { 29 | role = aws_iam_role.eks_mng_role.name 30 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" 31 | } 32 | 33 | resource "aws_iam_role_policy_attachment" "eks_mng_role_attachment_ecr" { 34 | role = aws_iam_role.eks_mng_role.name 35 | policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" 36 | } 37 | 38 | resource "aws_iam_role_policy_attachment" "eks_mng_role_attachment_cni" { 39 | role = aws_iam_role.eks_mng_role.name 40 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" 41 | } 42 | 43 | -------------------------------------------------------------------------------- /modules/network/public.tf: -------------------------------------------------------------------------------- 1 | resource "aws_subnet" "eks_subnet_public-1a" { 2 | vpc_id = aws_vpc.eks_vpc.id 3 | cidr_block = cidrsubnet(var.cidr_block, 8, 1) 4 | availability_zone = "${data.aws_region.current.name}a" 5 | map_public_ip_on_launch = true 6 | 7 | tags = merge( 8 | var.tags, 9 | { 10 | Name = "${var.project_name}-pub-subnet-1a" 11 | "kubernetes.io/role/elb" = 1 12 | } 13 | ) 14 | } 15 | 16 | resource "aws_subnet" "eks_subnet_public-1b" { 17 | vpc_id = aws_vpc.eks_vpc.id 18 | cidr_block = cidrsubnet(var.cidr_block, 8, 2) 19 | availability_zone = "${data.aws_region.current.name}b" 20 | map_public_ip_on_launch = true 21 | 22 | tags = merge( 23 | var.tags, 24 | { 25 | Name = "${var.project_name}-pub-subnet-1b" 26 | "kubernetes.io/role/elb" = 1 27 | } 28 | ) 29 | } 30 | 31 | resource "aws_route_table_association" "eks_rtb_assoc_1a" { 32 | subnet_id = aws_subnet.eks_subnet_public-1a.id 33 | route_table_id = aws_route_table.eks_public_route_table.id 34 | } 35 | 36 | resource "aws_route_table_association" "eks_rtb_assoc_1b" { 37 | subnet_id = aws_subnet.eks_subnet_public-1b.id 38 | route_table_id = aws_route_table.eks_public_route_table.id 39 | } 40 | -------------------------------------------------------------------------------- /provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~> 5.0" 6 | } 7 | kubernetes = { 8 | source = "hashicorp/kubernetes" 9 | version = "2.29.0" 10 | } 11 | helm = { 12 | source = "hashicorp/helm" 13 | version = "2.13.1" 14 | } 15 | 16 | } 17 | 18 | } 19 | 20 | # Configure the AWS Provider 21 | provider "aws" { 22 | region = var.region 23 | } 24 | 25 | # Configure the Kubernetes 26 | provider "kubernetes" { 27 | host = module.eks_cluster.cluster_endpoint 28 | cluster_ca_certificate = base64decode(module.eks_cluster.certificate_authority) 29 | exec { 30 | api_version = "client.authentication.k8s.io/v1beta1" 31 | args = ["eks", "get-token", "--cluster-name", module.eks_cluster.cluster_name] 32 | command = "aws" 33 | } 34 | } 35 | 36 | # Configure the Helm 37 | provider "helm" { 38 | kubernetes { 39 | host = module.eks_cluster.cluster_endpoint 40 | cluster_ca_certificate = base64decode(module.eks_cluster.certificate_authority) 41 | exec { 42 | api_version = "client.authentication.k8s.io/v1beta1" 43 | args = ["eks", "get-token", "--cluster-name", module.eks_cluster.cluster_name] 44 | command = "aws" 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/iam.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "eks_controller_role" { 2 | name = "${var.project_name}-aws-load-balancer-controller" 3 | 4 | assume_role_policy = < 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | 5.47.0 | 11 | 12 | ## Modules 13 | 14 | No modules. 15 | 16 | ## Resources 17 | 18 | | Name | Type | 19 | |------|------| 20 | | [aws_eks_node_group.eks_managed_node_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group) | resource | 21 | | [aws_iam_role.eks_mng_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 22 | | [aws_iam_role_policy_attachment.eks_mng_role_attachment_cni](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 23 | | [aws_iam_role_policy_attachment.eks_mng_role_attachment_ecr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 24 | | [aws_iam_role_policy_attachment.eks_mng_role_attachment_worker](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 25 | 26 | ## Inputs 27 | 28 | | Name | Description | Type | Default | Required | 29 | |------|-------------|------|---------|:--------:| 30 | | [cluster\_name](#input\_cluster\_name) | EKS cluster name to create MNG | `string` | n/a | yes | 31 | | [project\_name](#input\_project\_name) | Project name to be used to name the resources (Name tag) | `string` | n/a | yes | 32 | | [subnet\_private\_1a](#input\_subnet\_private\_1a) | Subnet ID from AZ 1a | `string` | n/a | yes | 33 | | [subnet\_private\_1b](#input\_subnet\_private\_1b) | Subnet ID from AZ 1b | `string` | n/a | yes | 34 | | [tags](#input\_tags) | Tags to be added to AWS resources | `map(any)` | n/a | yes | 35 | 36 | ## Outputs 37 | 38 | No outputs. 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-eks 2 | 3 | ## Requirements 4 | 5 | | Name | Version | 6 | |------|---------| 7 | | [aws](#requirement\_aws) | ~> 5.0 | 8 | | [helm](#requirement\_helm) | 2.13.1 | 9 | | [kubernetes](#requirement\_kubernetes) | 2.29.0 | 10 | 11 | ## Providers 12 | 13 | No providers. 14 | 15 | ## Modules 16 | 17 | | Name | Source | Version | 18 | |------|--------|---------| 19 | | [eks\_aws\_load\_balancer\_controller](#module\_eks\_aws\_load\_balancer\_controller) | ./modules/aws-load-balancer-controller | n/a | 20 | | [eks\_cluster](#module\_eks\_cluster) | ./modules/cluster | n/a | 21 | | [eks\_managed\_node\_group](#module\_eks\_managed\_node\_group) | ./modules/managed-node-group | n/a | 22 | | [eks\_network](#module\_eks\_network) | ./modules/network | n/a | 23 | 24 | ## Resources 25 | 26 | No resources. 27 | 28 | ## Inputs 29 | 30 | | Name | Description | Type | Default | Required | 31 | |------|-------------|------|---------|:--------:| 32 | | [cidr\_block](#input\_cidr\_block) | Networking CIDR block to be used for the VPC | `string` | n/a | yes | 33 | | [project\_name](#input\_project\_name) | Project name to be used to name the resources (Name tag) | `string` | n/a | yes | 34 | | [region](#input\_region) | AWS regiton to create the resources | `string` | n/a | yes | 35 | | [tags](#input\_tags) | A map of tags to add to all AWS resources | `map(any)` | n/a | yes | 36 | 37 | ## Outputs 38 | 39 | | Name | Description | 40 | |------|-------------| 41 | | [certificate\_authority](#output\_certificate\_authority) | n/a | 42 | | [cluster\_endpoint](#output\_cluster\_endpoint) | n/a | 43 | | [oidc](#output\_oidc) | n/a | 44 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | 5.47.0 | 11 | | [helm](#provider\_helm) | 2.13.1 | 12 | | [kubernetes](#provider\_kubernetes) | 2.29.0 | 13 | 14 | ## Modules 15 | 16 | No modules. 17 | 18 | ## Resources 19 | 20 | | Name | Type | 21 | |------|------| 22 | | [aws_iam_policy.eks_controller_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | 23 | | [aws_iam_role.eks_controller_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 24 | | [aws_iam_role_policy_attachment.eks_controller_role_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 25 | | [helm_release.eks_helm_controller](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | 26 | | [kubernetes_service_account.example](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/service_account) | resource | 27 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 28 | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | 29 | 30 | ## Inputs 31 | 32 | | Name | Description | Type | Default | Required | 33 | |------|-------------|------|---------|:--------:| 34 | | [cluster\_name](#input\_cluster\_name) | EKS cluster name | `string` | n/a | yes | 35 | | [oidc](#input\_oidc) | HTTPS URL from OIDC provider of the EKS cluster | `string` | n/a | yes | 36 | | [project\_name](#input\_project\_name) | Project name to be used to name the resources (Name tag) | `string` | n/a | yes | 37 | | [tags](#input\_tags) | Tags to be added to AWS resources | `map(any)` | n/a | yes | 38 | 39 | ## Outputs 40 | 41 | No outputs. 42 | -------------------------------------------------------------------------------- /modules/cluster/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | 5.47.0 | 11 | | [tls](#provider\_tls) | 4.0.5 | 12 | 13 | ## Modules 14 | 15 | No modules. 16 | 17 | ## Resources 18 | 19 | | Name | Type | 20 | |------|------| 21 | | [aws_eks_cluster.eks_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster) | resource | 22 | | [aws_iam_openid_connect_provider.eks_oidc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_openid_connect_provider) | resource | 23 | | [aws_iam_role.eks_cluster_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 24 | | [aws_iam_role_policy_attachment.eks_cluster_role_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 25 | | [aws_security_group_rule.eks_cluster_sg_rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | 26 | | [tls_certificate.eks_oidc_tls_certificate](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate) | data source | 27 | 28 | ## Inputs 29 | 30 | | Name | Description | Type | Default | Required | 31 | |------|-------------|------|---------|:--------:| 32 | | [project\_name](#input\_project\_name) | Project name to be used to name the resources (Name tag) | `string` | n/a | yes | 33 | | [public\_subnet\_1a](#input\_public\_subnet\_1a) | Subnet to create EKS cluster AZ 1a | `string` | n/a | yes | 34 | | [public\_subnet\_1b](#input\_public\_subnet\_1b) | Subnet to create EKS cluster AZ 1b | `string` | n/a | yes | 35 | | [tags](#input\_tags) | Tags to be added to AWS resources | `map(any)` | n/a | yes | 36 | 37 | ## Outputs 38 | 39 | | Name | Description | 40 | |------|-------------| 41 | | [certificate\_authority](#output\_certificate\_authority) | n/a | 42 | | [cluster\_endpoint](#output\_cluster\_endpoint) | n/a | 43 | | [cluster\_name](#output\_cluster\_name) | n/a | 44 | | [oidc](#output\_oidc) | n/a | 45 | -------------------------------------------------------------------------------- /modules/network/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | No requirements. 5 | 6 | ## Providers 7 | 8 | | Name | Version | 9 | |------|---------| 10 | | [aws](#provider\_aws) | 5.47.0 | 11 | 12 | ## Modules 13 | 14 | No modules. 15 | 16 | ## Resources 17 | 18 | | Name | Type | 19 | |------|------| 20 | | [aws_eip.eks_ngw_eip_1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | 21 | | [aws_eip.eks_ngw_eip_1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | 22 | | [aws_internet_gateway.eks_igw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource | 23 | | [aws_nat_gateway.eks_ngw_1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | 24 | | [aws_nat_gateway.eks_ngw_1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | 25 | | [aws_route_table.eks_private_route_table_1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 26 | | [aws_route_table.eks_private_route_table_1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 27 | | [aws_route_table.eks_public_route_table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 28 | | [aws_route_table_association.eks_rtb_assoc_1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 29 | | [aws_route_table_association.eks_rtb_assoc_1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 30 | | [aws_route_table_association.eks_rtb_assoc_priv_1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 31 | | [aws_route_table_association.eks_rtb_assoc_priv_1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 32 | | [aws_subnet.eks_subnet_private-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 33 | | [aws_subnet.eks_subnet_private-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 34 | | [aws_subnet.eks_subnet_public-1a](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 35 | | [aws_subnet.eks_subnet_public-1b](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 36 | | [aws_vpc.eks_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | 37 | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | 38 | 39 | ## Inputs 40 | 41 | | Name | Description | Type | Default | Required | 42 | |------|-------------|------|---------|:--------:| 43 | | [cidr\_block](#input\_cidr\_block) | Networking CIDR block to be used for the VPC | `string` | n/a | yes | 44 | | [project\_name](#input\_project\_name) | Project name to be used to name the resources (Name tag) | `string` | n/a | yes | 45 | | [tags](#input\_tags) | Tags to be added to AWS resources | `map(any)` | n/a | yes | 46 | 47 | ## Outputs 48 | 49 | | Name | Description | 50 | |------|-------------| 51 | | [subnet\_priv\_1a](#output\_subnet\_priv\_1a) | n/a | 52 | | [subnet\_priv\_1b](#output\_subnet\_priv\_1b) | n/a | 53 | | [subnet\_pub\_1a](#output\_subnet\_pub\_1a) | n/a | 54 | | [subnet\_pub\_1b](#output\_subnet\_pub\_1b) | n/a | 55 | -------------------------------------------------------------------------------- /modules/aws-load-balancer-controller/iam_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "iam:CreateServiceLinkedRole" 8 | ], 9 | "Resource": "*", 10 | "Condition": { 11 | "StringEquals": { 12 | "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com" 13 | } 14 | } 15 | }, 16 | { 17 | "Effect": "Allow", 18 | "Action": [ 19 | "ec2:DescribeAccountAttributes", 20 | "ec2:DescribeAddresses", 21 | "ec2:DescribeAvailabilityZones", 22 | "ec2:DescribeInternetGateways", 23 | "ec2:DescribeVpcs", 24 | "ec2:DescribeVpcPeeringConnections", 25 | "ec2:DescribeSubnets", 26 | "ec2:DescribeSecurityGroups", 27 | "ec2:DescribeInstances", 28 | "ec2:DescribeNetworkInterfaces", 29 | "ec2:DescribeTags", 30 | "ec2:GetCoipPoolUsage", 31 | "ec2:DescribeCoipPools", 32 | "elasticloadbalancing:DescribeLoadBalancers", 33 | "elasticloadbalancing:DescribeLoadBalancerAttributes", 34 | "elasticloadbalancing:DescribeListeners", 35 | "elasticloadbalancing:DescribeListenerCertificates", 36 | "elasticloadbalancing:DescribeSSLPolicies", 37 | "elasticloadbalancing:DescribeRules", 38 | "elasticloadbalancing:DescribeTargetGroups", 39 | "elasticloadbalancing:DescribeTargetGroupAttributes", 40 | "elasticloadbalancing:DescribeTargetHealth", 41 | "elasticloadbalancing:DescribeTags", 42 | "elasticloadbalancing:DescribeTrustStores" 43 | ], 44 | "Resource": "*" 45 | }, 46 | { 47 | "Effect": "Allow", 48 | "Action": [ 49 | "cognito-idp:DescribeUserPoolClient", 50 | "acm:ListCertificates", 51 | "acm:DescribeCertificate", 52 | "iam:ListServerCertificates", 53 | "iam:GetServerCertificate", 54 | "waf-regional:GetWebACL", 55 | "waf-regional:GetWebACLForResource", 56 | "waf-regional:AssociateWebACL", 57 | "waf-regional:DisassociateWebACL", 58 | "wafv2:GetWebACL", 59 | "wafv2:GetWebACLForResource", 60 | "wafv2:AssociateWebACL", 61 | "wafv2:DisassociateWebACL", 62 | "shield:GetSubscriptionState", 63 | "shield:DescribeProtection", 64 | "shield:CreateProtection", 65 | "shield:DeleteProtection" 66 | ], 67 | "Resource": "*" 68 | }, 69 | { 70 | "Effect": "Allow", 71 | "Action": [ 72 | "ec2:AuthorizeSecurityGroupIngress", 73 | "ec2:RevokeSecurityGroupIngress" 74 | ], 75 | "Resource": "*" 76 | }, 77 | { 78 | "Effect": "Allow", 79 | "Action": [ 80 | "ec2:CreateSecurityGroup" 81 | ], 82 | "Resource": "*" 83 | }, 84 | { 85 | "Effect": "Allow", 86 | "Action": [ 87 | "ec2:CreateTags" 88 | ], 89 | "Resource": "arn:aws:ec2:*:*:security-group/*", 90 | "Condition": { 91 | "StringEquals": { 92 | "ec2:CreateAction": "CreateSecurityGroup" 93 | }, 94 | "Null": { 95 | "aws:RequestTag/elbv2.k8s.aws/cluster": "false" 96 | } 97 | } 98 | }, 99 | { 100 | "Effect": "Allow", 101 | "Action": [ 102 | "ec2:CreateTags", 103 | "ec2:DeleteTags" 104 | ], 105 | "Resource": "arn:aws:ec2:*:*:security-group/*", 106 | "Condition": { 107 | "Null": { 108 | "aws:RequestTag/elbv2.k8s.aws/cluster": "true", 109 | "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" 110 | } 111 | } 112 | }, 113 | { 114 | "Effect": "Allow", 115 | "Action": [ 116 | "ec2:AuthorizeSecurityGroupIngress", 117 | "ec2:RevokeSecurityGroupIngress", 118 | "ec2:DeleteSecurityGroup" 119 | ], 120 | "Resource": "*", 121 | "Condition": { 122 | "Null": { 123 | "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" 124 | } 125 | } 126 | }, 127 | { 128 | "Effect": "Allow", 129 | "Action": [ 130 | "elasticloadbalancing:CreateLoadBalancer", 131 | "elasticloadbalancing:CreateTargetGroup" 132 | ], 133 | "Resource": "*", 134 | "Condition": { 135 | "Null": { 136 | "aws:RequestTag/elbv2.k8s.aws/cluster": "false" 137 | } 138 | } 139 | }, 140 | { 141 | "Effect": "Allow", 142 | "Action": [ 143 | "elasticloadbalancing:CreateListener", 144 | "elasticloadbalancing:DeleteListener", 145 | "elasticloadbalancing:CreateRule", 146 | "elasticloadbalancing:DeleteRule" 147 | ], 148 | "Resource": "*" 149 | }, 150 | { 151 | "Effect": "Allow", 152 | "Action": [ 153 | "elasticloadbalancing:AddTags", 154 | "elasticloadbalancing:RemoveTags" 155 | ], 156 | "Resource": [ 157 | "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", 158 | "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", 159 | "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" 160 | ], 161 | "Condition": { 162 | "Null": { 163 | "aws:RequestTag/elbv2.k8s.aws/cluster": "true", 164 | "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" 165 | } 166 | } 167 | }, 168 | { 169 | "Effect": "Allow", 170 | "Action": [ 171 | "elasticloadbalancing:AddTags", 172 | "elasticloadbalancing:RemoveTags" 173 | ], 174 | "Resource": [ 175 | "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", 176 | "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", 177 | "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", 178 | "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" 179 | ] 180 | }, 181 | { 182 | "Effect": "Allow", 183 | "Action": [ 184 | "elasticloadbalancing:ModifyLoadBalancerAttributes", 185 | "elasticloadbalancing:SetIpAddressType", 186 | "elasticloadbalancing:SetSecurityGroups", 187 | "elasticloadbalancing:SetSubnets", 188 | "elasticloadbalancing:DeleteLoadBalancer", 189 | "elasticloadbalancing:ModifyTargetGroup", 190 | "elasticloadbalancing:ModifyTargetGroupAttributes", 191 | "elasticloadbalancing:DeleteTargetGroup" 192 | ], 193 | "Resource": "*", 194 | "Condition": { 195 | "Null": { 196 | "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" 197 | } 198 | } 199 | }, 200 | { 201 | "Effect": "Allow", 202 | "Action": [ 203 | "elasticloadbalancing:AddTags" 204 | ], 205 | "Resource": [ 206 | "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", 207 | "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", 208 | "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" 209 | ], 210 | "Condition": { 211 | "StringEquals": { 212 | "elasticloadbalancing:CreateAction": [ 213 | "CreateTargetGroup", 214 | "CreateLoadBalancer" 215 | ] 216 | }, 217 | "Null": { 218 | "aws:RequestTag/elbv2.k8s.aws/cluster": "false" 219 | } 220 | } 221 | }, 222 | { 223 | "Effect": "Allow", 224 | "Action": [ 225 | "elasticloadbalancing:RegisterTargets", 226 | "elasticloadbalancing:DeregisterTargets" 227 | ], 228 | "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" 229 | }, 230 | { 231 | "Effect": "Allow", 232 | "Action": [ 233 | "elasticloadbalancing:SetWebAcl", 234 | "elasticloadbalancing:ModifyListener", 235 | "elasticloadbalancing:AddListenerCertificates", 236 | "elasticloadbalancing:RemoveListenerCertificates", 237 | "elasticloadbalancing:ModifyRule" 238 | ], 239 | "Resource": "*" 240 | } 241 | ] 242 | } 243 | --------------------------------------------------------------------------------