{"id":51507953,"url":"https://github.com/explicit-logic/terraform-module-12.3","last_synced_at":"2026-07-08T02:30:43.058Z","repository":{"id":353209319,"uuid":"1217403899","full_name":"explicit-logic/terraform-module-12.3","owner":"explicit-logic","description":"Terraform \u0026 AWS EKS","archived":false,"fork":false,"pushed_at":"2026-04-22T22:01:45.000Z","size":10799,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-23T00:06:37.872Z","etag":null,"topics":["aws","aws-eks","devops","devops-bootcamp","docker","eks","git","kubernetes","linux","terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/explicit-logic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T21:12:48.000Z","updated_at":"2026-04-22T22:01:49.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/explicit-logic/terraform-module-12.3","commit_stats":null,"previous_names":["explicit-logic/terraform-module-12.3"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/explicit-logic/terraform-module-12.3","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fterraform-module-12.3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fterraform-module-12.3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fterraform-module-12.3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fterraform-module-12.3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/explicit-logic","download_url":"https://codeload.github.com/explicit-logic/terraform-module-12.3/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fterraform-module-12.3/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35249883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-eks","devops","devops-bootcamp","docker","eks","git","kubernetes","linux","terraform"],"created_at":"2026-07-08T02:30:42.357Z","updated_at":"2026-07-08T02:30:43.041Z","avatar_url":"https://github.com/explicit-logic.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Module 12 - Infrastructure as Code with Terraform\n\nThis repository contains a demo project created as part of my **DevOps studies** in the [TechWorld with Nana – DevOps Bootcamp](https://www.techworld-with-nana.com/devops-bootcamp).\n\n**Demo Project:** Terraform \u0026 AWS EKS\n\n**Technologies used:** Terraform, AWS EKS, Docker, Linux, Git\n\n**Project Description:**\n\n- Automate provisioning EKS cluster with Terraform\n\n---\n\n## Architecture Overview\n\n![](./images/intro.png)\n\nThe project provisions a production-style AWS infrastructure:\n- A **VPC** with public and private subnets spread across multiple Availability Zones\n- An **EKS cluster** with managed worker nodes running in private subnets\n- A **NAT Gateway** so private nodes can reach the internet without being publicly exposed\n- An **nginx application** deployed into the cluster, exposed via an AWS Load Balancer\n\n---\n\n## Project Structure\n\n| File | Purpose |\n|------|---------|\n| [vpc.tf](./vpc.tf) | VPC, subnets, NAT gateway, and subnet tagging for EKS |\n| [eks-cluster.tf](./eks-cluster.tf) | EKS control plane, addons, and managed node groups |\n| [terraform.tfvars](./terraform.tfvars) | Variable values (region, CIDRs) — not committed |\n| [terraform.tfvars.example](./terraform.tfvars.example) | Template for the vars file |\n| [nginx.yaml](./nginx.yaml) | Kubernetes Deployment + LoadBalancer Service for nginx |\n\n---\n\n## Prerequisites\n\nCopy and fill in the variables file:\n\n```sh\ncp terraform.tfvars.example terraform.tfvars\n```\n\nEdit `terraform.tfvars` to set your AWS region and desired CIDR blocks.\n\n---\n\n## VPC — [vpc.tf](./vpc.tf)\n\nSee VPC module: https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest\n\n**Best practice:** 1 private + 1 public subnet per Availability Zone for high availability.\n\n![](./images/vpc-subnet-bp.png)\n\n### Key configuration explained\n\n```hcl\ndata \"aws_availability_zones\" \"azs\" {}\n```\nDynamically fetches the list of AZs in the configured region — no hardcoding required.\n\n```hcl\nazs             = data.aws_availability_zones.azs.names\nprivate_subnets = var.private_subnet_cidr_blocks\npublic_subnets  = var.public_subnet_cidr_blocks\n```\nCreates one private and one public subnet in each AZ using CIDRs from your vars file.\n\n```hcl\nenable_nat_gateway = true\nsingle_nat_gateway = true\n```\nPlaces a single NAT Gateway in the public subnet. Worker nodes in private subnets route outbound traffic through it (e.g., to pull container images). `single_nat_gateway = true` keeps costs low for non-production; set to `false` for one NAT per AZ in production.\n\n```hcl\nenable_dns_hostnames = true\n```\nRequired for EKS — nodes need DNS resolution to communicate with the control plane endpoint.\n\n```hcl\ntags = {\n  \"kubernetes.io/cluster/myapp-eks-cluster\" = \"shared\"\n}\n```\nApplied to the VPC itself. EKS uses this tag to discover which VPC belongs to the cluster.\n\n```hcl\npublic_subnet_tags = {\n  \"kubernetes.io/cluster/myapp-eks-cluster\" = \"shared\"\n  \"kubernetes.io/role/elb\"                  = 1\n}\n```\n`kubernetes.io/role/elb = 1` tells the AWS Load Balancer Controller to provision **internet-facing** load balancers in these subnets.\n\n```hcl\nprivate_subnet_tags = {\n  \"kubernetes.io/cluster/myapp-eks-cluster\" = \"shared\"\n  \"kubernetes.io/role/internal-elb\"         = 1\n}\n```\n`kubernetes.io/role/internal-elb = 1` tags private subnets for **internal** load balancers. Worker nodes run here — isolated from direct internet access.\n\n### Commands\n\n```sh\nterraform init\n```\n![](./images/vpc-terraform-init.png)\n\n```sh\nterraform plan\n```\n![](./images/vpc-terraform-plan.png)\n\n---\n\n## EKS Cluster \u0026 Worker Nodes — [eks-cluster.tf](./eks-cluster.tf)\n\nSee EKS module: https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest\n\nWorker node types overview:\n\n![](./images/worker-nodes-types.png)\n\n### Key configuration explained\n\n```hcl\nname               = \"myapp-eks-cluster\"\nkubernetes_version = \"1.33\"\n```\nSets the cluster name (referenced in VPC tags above) and the Kubernetes control plane version.\n\n```hcl\naddons = {\n  coredns                = {}\n  eks-pod-identity-agent = { before_compute = true }\n  kube-proxy             = {}\n  vpc-cni                = { before_compute = true }\n}\n```\nManaged EKS addons installed on the cluster:\n- **coredns** — in-cluster DNS for service discovery between pods\n- **eks-pod-identity-agent** — allows pods to assume IAM roles without access keys; `before_compute = true` ensures it is ready before worker nodes join\n- **kube-proxy** — maintains network routing rules on each node\n- **vpc-cni** — AWS VPC CNI plugin; gives each pod a real VPC IP address from the subnet; `before_compute = true` ensures networking is ready before nodes register\n\n```hcl\nsubnet_ids = module.myapp-vpc.private_subnets\nvpc_id     = module.myapp-vpc.vpc_id\n```\nPlaces worker nodes in the **private** subnets created by the VPC module. The control plane is managed by AWS and lives in its own VPC; nodes communicate with it via the VPC endpoint.\n\n```hcl\nendpoint_public_access = true\n```\nMakes the Kubernetes API server reachable from your local machine (e.g., via `kubectl`). In production you would restrict this with `public_access_cidrs`.\n\n```hcl\nenable_cluster_creator_admin_permissions = true\n```\nAutomatically grants the IAM identity running Terraform full admin access to the cluster — so `kubectl` works immediately after `terraform apply` without manual aws-auth configmap editing.\n\n```hcl\neks_managed_node_groups = {\n  dev = {\n    ami_type       = \"AL2023_x86_64_STANDARD\"\n    instance_types = [\"t2.small\"]\n    min_size       = 1\n    max_size       = 3\n    desired_size   = 3\n  }\n}\n```\nDefines a **managed node group** (AWS handles OS patching and node lifecycle):\n- `ami_type` — uses Amazon Linux 2023, the current recommended EKS-optimized AMI\n- `instance_types` — `t2.small` is cost-effective for development; use `t3.medium` or larger for production workloads\n- `min/max/desired_size` — the Auto Scaling Group runs 3 nodes by default, scaling down to 1 if needed\n\n### Commands\n\n```sh\nterraform init\n```\n![](./images/eks-terraform-init.png)\n\n```sh\nterraform plan\n```\n![](./images/eks-terraform-plan.png)\n\n```sh\nterraform apply --auto-approve\n```\n![](./images/eks-terraform-apply.png)\n\nAfter apply, verify the cluster:\n\n![](./images/cluster-info.png)\n\n![](./images/workload-pods.png)\n\n![](./images/cluster-role.png)\n\n![](./images/ec2-instances.png)\n\nPrivate route table uses NAT Gateway to allow worker nodes in private subnets to reach the internet (e.g., pull images from Docker Hub):\n\n![](./images/private-route-table.png)\n\n![](./images/subnets.png)\n\n![](./images/security-groups.png)\n\n---\n\n## Deploy nginx App into the Cluster\n\n**1. Configure kubectl to talk to your cluster:**\n\n```sh\naws eks update-kubeconfig --name myapp-eks-cluster --region eu-central-1\n```\n\n**2. Verify nodes are ready:**\n\n```sh\nkubectl get nodes\n```\n\n**3. Deploy the nginx application:**\n\n```sh\nkubectl apply -f nginx.yaml\n```\n\n![](./images/kubectl.png)\n\n**4. Get the Load Balancer DNS name:**\n\nNavigate to **EC2 → Load Balancers** in the AWS Console and copy the DNS name.\n\n![](./images/load-balancer.png)\n\n**5. Open the app in your browser:**\n\nPaste the DNS name into your browser — nginx should respond.\n\n![](./images/open-app.png)\n\n---\n\n## Destroy All Components\n\n```sh\nterraform destroy --auto-approve\n```\n\nVerify everything is removed:\n\n```sh\nterraform state list\n```\n\n\u003e If the state list is empty, all resources have been successfully destroyed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexplicit-logic%2Fterraform-module-12.3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexplicit-logic%2Fterraform-module-12.3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexplicit-logic%2Fterraform-module-12.3/lists"}