├── .gitignore
├── LICENSE
├── Nguyen Huu Ty - DevOps Assessment.pdf
├── README.md
├── add-ons
├── .terraform.lock.hcl
├── cluster-autoscaler-iam-policy-and-role.tf
├── cluster-autoscaler-install.tf
├── cluster-autoscaler-outputs.tf
├── ebs-csi-datasources.tf
├── ebs-csi-iam-policy-and-role.tf
├── ebs-csi-install-using-helm.tf
├── ebs-csi-outputs.tf
├── externaldns-iam-policy-and-role.tf
├── externaldns-install.tf
├── externaldns-outputs.tf
├── generic-variables.tf
├── ingress-class.tf
├── kubernetes-provider.tf
├── lbc-datasources.tf
├── lbc-helm-provider.tf
├── lbc-iam-policy-and-role.tf
├── lbc-install.tf
├── lbc-outputs.tf
├── local-values.tf
├── remote-state-datasource.tf
└── versions.tf
├── docs
├── 2022-08-07-12-57-11-image.png
├── 2022-08-07-12-57-28-image.png
├── 2022-08-07-12-59-23-image.png
├── 2022-08-07-12-59-50-image.png
├── 2022-08-07-13-00-37-image.png
├── 2022-08-07-13-00-44-image.png
├── 2022-08-07-13-02-49-image.png
├── 2022-08-07-13-03-06-image.png
├── devops.drawio
├── devops.drawio.png
└── ~$devops.drawio.bkp
├── helm-values
└── gitlab-runner-values.yaml
└── infrastructure
├── .terraform.lock.hcl
├── main.tf
├── modules
├── eks
│ ├── eks-cluster.tf
│ ├── eks-node-group-private.tf
│ ├── eks-outputs.tf
│ ├── eks-variables.tf
│ ├── iam-oidc-connect-provider-variables.tf
│ └── iam-oidc-connect-provider.tf
├── iam
│ ├── iamrole-for-eks-cluster.tf
│ ├── iamrole-for-eks-nodegroup.tf
│ ├── outputs.tf
│ └── variables.tf
├── k8s
│ ├── kubernetes-configmap.tf
│ ├── mysql-clusterip-service.tf
│ ├── mysql-deployment.tf
│ ├── persistent-volume-claim.tf
│ ├── storage-class.tf
│ ├── variables.tf
│ └── webappdb.sql
└── vpc
│ ├── vpc-outputs.tf
│ ├── vpc-variables.tf
│ └── vpc.tf
├── outputs.tf
└── variables.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
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Nguyen Huu Ty
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 |
--------------------------------------------------------------------------------
/Nguyen Huu Ty - DevOps Assessment.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/Nguyen Huu Ty - DevOps Assessment.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevOps Assessment
2 |
3 | ---
4 |
5 | - [DevOps Assessment](#devops-assessment)
6 | - [Context](#context)
7 | - [Tech Stack](#tech-stack)
8 | - [Tasks](#tasks)
9 | - [Architecture Overview](#architecture-overview)
10 | - [AWS Well-Architected review](#aws-well-architected-review)
11 | - [Operational Excellence Pillar](#operational-excellence-pillar)
12 | - [Security Pillar](#security-pillar)
13 | - [Reliability Pillar](#reliability-pillar)
14 | - [Performance Efficiency Pillar](#performance-efficiency-pillar)
15 | - [Cost Optimization Pillar](#cost-optimization-pillar)
16 | - [Sustainability Pillar](#sustainability-pillar)
17 | - [Results](#results)
18 | - [References](#references)
19 |
20 | ---
21 |
22 | ## Context
23 |
24 | 1. Build a secure and small dockerized hello world Laravel app which can be successfully connected to a MySQL server.
25 | 2. Automate the process of building the app and pushing to a container registry using GitLab.
26 | 3. Bring up an autoscale EC2 cluster as a worker node group of an EKS cluster (For this IaC is enough, no need to apply on real infra)
27 | 4. Automate the deployment of built app on K8s cluster (locally you can use `minikube` or `kind` for K8s)
28 | 5. Add documentation of the whole procedure and how you made it well architected.
29 |
30 | ## Tech Stack
31 |
32 | - **GitLab**: Code Repository for Laravel Application and CI/CD using self hosted runner in EKS (Autoscaling with Kubernetes)
33 | - **Helm**: Package and deploy application in K8S.
34 | - **Terraform**: Setup Network, provision AWS EKS Kubernetes Cluster, install EKS add-ons, managed some workloads in K8S.
35 | - **AWS Services**:
36 | - Route 53
37 | - EKS
38 | - ACM
39 | - ALB
40 | - VPC
41 | - IAM
42 |
43 | ## Tasks
44 |
45 | - [x] Setup EKS Cluster Terraform, structure module, install Helm, EKS add-ons.
46 | - [x] Clone source code https://github.com/nahidulhasan/laravel-docker-k8s and running local test.
47 | - [x] Install MySQL K8S, prepare script migrate DB for Laravel, automate pipeline migrate if necessary at the end stage.
48 | - [x] Setup Helm repository in S3 using Terraform module, base helm chart application.
49 | - [x] Using Helm app to deploy Dockerfile locally.
50 | - [x] Using https://github.com/GoogleContainerTools/kaniko to Build Docker in Gitlab CI and publish to ECR.
51 | - [x] Deploy and manage GitLab Runner in cluster EKS, make Gitlab Pipeline runnable.
52 | - [x] Using Autoscaler to scale the cluster's worker nodes by number of pods and resources needed.
53 | - [x] Document, draw architecture, explain how it work.
54 |
55 | ## Architecture Overview
56 |
57 | 
58 |
59 | ## AWS Well-Architected review
60 |
61 | ### Operational Excellence Pillar
62 |
63 | - Almost workloads using Infrastructure as code, automate all tasks managed AWS resources via **Terraform** tool instead of change manual.
64 |
65 | - Containerize application using Docker, make consistent environment as much as possible, convenient to development and operation.
66 |
67 | ### Security Pillar
68 |
69 | - Database layer deploy in **K8S** Private Subnet, data store in persistent **EBS** volumes, avoid missing data when MySQL workload shutdown.
70 |
71 | - Using **RBAC** to avoid leak AWS IAM access key.
72 |
73 | ### Reliability Pillar
74 |
75 | - Using **Helm** with **Gitlab CI**, make manage application workload become fully automated, easy to deploy application with adapting to changing or recreating resources, make consistent between multiple enviroment.
76 |
77 | ### Performance Efficiency Pillar
78 |
79 | - Allocate and utilize resources efficiently based on needed with K8S.
80 |
81 | ### Cost Optimization Pillar
82 |
83 | - Autoscale based on workloads with **Kubernetes Cluster Autoscaler**.
84 | - Using spot instances for EKS worker node.
85 |
86 | ### Sustainability Pillar
87 |
88 | - Using EKS managed, reduce task relative to master node K8S.
89 |
90 | - Using Add-ons/Plugin EKS to automatic create resources necessary, for example create Route53, create ALB, EBS...
91 |
92 | ## Results
93 |
94 | **Link**: https://bebi.store/
95 |
96 | **Account**: typrone1@gmail.com | 123123
97 |
98 | **Repository**:
99 |
100 | - [tycloud / devops-laravel · GitLab](https://gitlab.com/tycloud/devops-laravel/)
101 |
102 | - [GitHub - tycloud97/devops-exercise](https://github.com/tycloud97/devops-exercise)
103 |
104 | **Screenshot**:
105 |
106 | 
107 |
108 | 
109 |
110 | 
111 |
112 | 
113 |
114 | 
115 |
116 | 
117 |
118 | ## References
119 |
120 | - https://docs.aws.amazon.com/prescriptive-guidance/latest/patterns/set-up-a-helm-v3-chart-repository-in-amazon-s3.html
121 | - https://github.com/nahidulhasan/laravel-docker-k8s
122 | - https://github.com/stacksimplify/terraform-on-aws-eks
123 | - https://www.weave.works/blog/running-dockerized-laravel-applications-on-top-of-kubernetes
124 |
125 | _Useful CLI_
126 |
127 | ```bash
128 | helm s3 init s3://ty-helm/stable/myapp
129 | helm repo add stable-myapp s3://ty-helm/stable/myapp/
130 | helm repo add gitlab https://charts.gitlab.io
131 | aws eks --region ap-southeast-1 update-kubeconfig --name ty-dev-eksdemo
132 | kubectl get pods --all-namespaces | grep -i running | wc -l
133 | helm upgrade --namespace default gitlab-runner -f gitlab-runner-values.yaml gitlab/gitlab-runner
134 | php artisan key:generate
135 | php artisan migrate
136 | helm s3 push --force ./app-0.0.1.tgz stable-myapp
137 | docker build -t laraveldemo . --platform=linux/amd64\ndocker tag laraveldemo:latest 827539266883.dkr.ecr.ap-southeast-1.amazonaws.com/laraveldemo:latest\ndocker push 827539266883.dkr.ecr.ap-southeast-1.amazonaws.com/laraveldemo:latest
138 | helm upgrade devops-laravel devops/app --install --force --namespace devops-laravel -f deployment/dev.yaml --set image.repository=${DOCKER_IMAGE},image.tag=${DOCKER_TAG} -->
139 | ```
140 |
--------------------------------------------------------------------------------
/add-ons/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/hashicorp/aws" {
5 | version = "4.25.0"
6 | constraints = "~> 4.12"
7 | hashes = [
8 | "h1:JyQAQ3YrE4utVAQsLGy1LjMbAzzRI/X2XsrY7CFBGxw=",
9 | "zh:51fddc33f289108f60c2de78537f758ae913b2614187abfc3f560f9dd277bc1a",
10 | "zh:5a2bfa0725a8941f12e775eb9c44582ec237a664321a740d8283e9b56452f2ad",
11 | "zh:6ca73a9f11c2a9ff8f55433c00a12c1b69c22131251cb0698d32c682229b1233",
12 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
13 | "zh:aeafec22947a7be418adc3c6d1eddb719ed02b5e41b6e2cc9cbdca991e2140b8",
14 | "zh:b043563789e32f6935bf51c3b4344482487c03cb084673f6181ce3443f956a3d",
15 | "zh:b0693f4295d35ae6ce3656ee2294fd69eb732f601ba7d6eb28b7fded4471c3d2",
16 | "zh:bccb9ec142aa11350a52142b71fd8f0332d36a94332207f45bd93ceb7297b922",
17 | "zh:c353fd5060cf6d86e4505d0ade84a37f91d4d8774b17eaa1290a191d9da43729",
18 | "zh:d07848da6940b2882b884fc24144741f7ce0442865c9833df26751c48429e11f",
19 | "zh:d4feeb5c394ec9528d1633e2e2c133632d8d099f6c99654e2bbd2aa112b6a08e",
20 | "zh:fb0a75edb943847354c759a665edb93fd7945b892be7d0511c6708785abf090c",
21 | ]
22 | }
23 |
24 | provider "registry.terraform.io/hashicorp/helm" {
25 | version = "2.6.0"
26 | constraints = "~> 2.5"
27 | hashes = [
28 | "h1:i+fbwv8Vk8n5kQc+spEtzvCNF4yo2exzSAZhL0ipFuo=",
29 | "zh:0ac248c28acc1a4fd11bd26a85e48ab78dd6abf0f7ac842bf1cd7edd05ac6cf8",
30 | "zh:3d32c8deae3740d8c5310136cc11c8afeffc350fbf88afaca0c34a223a5246f5",
31 | "zh:4055a27489733d19ca7fa2dfce14d323fe99ae9dede7d0fea21ee6db0b9ca74b",
32 | "zh:58a8ed39653fd4c874a2ecb128eccfa24c94266a00e349fd7fb13e22ad81f381",
33 | "zh:6c81508044913f25083de132d0ff81d083732aba07c506cc2db05aa0cefcde2c",
34 | "zh:7db5d18093047bfc4fe597f79610c0a281b21db0d61b0bacb3800585e976f814",
35 | "zh:8269207b7422db99e7be80a5352d111966c3dfc7eb98511f11c8ff7b2e813456",
36 | "zh:b1d7ababfb2374e72532308ff442cc906b79256b66b3fe7a98d42c68c4ddf9c5",
37 | "zh:ca63e226cbdc964a5d63ef21189f059ce45c3fa4a5e972204d6916a9177d2b44",
38 | "zh:d205a72d60e8cc362943d66f5bcdd6b6aaaa9aab2b89fd83bf6f1978ac0b1e4c",
39 | "zh:db47dc579a0e68e5bfe3a61f2e950e6e2af82b1f388d1069de014a937962b56a",
40 | "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
41 | ]
42 | }
43 |
44 | provider "registry.terraform.io/hashicorp/http" {
45 | version = "2.2.0"
46 | constraints = "~> 2.1"
47 | hashes = [
48 | "h1:EiuCPEHueILwdgK4hnWuLyT/XdB5ZbEY8ALZdCJYcYM=",
49 | "zh:159add5739a597c08439318f67c440a90ce8444a009e7b8aabbcb9279da9191f",
50 | "zh:1e5fbe9a4b8d3d9f167effc03bd5324ad6ef721c23a174e98c7eb2e8b85e34e8",
51 | "zh:4b150790ac5948ceec4f97df4deaff835e4798049d858c20413cbdff6e610c4d",
52 | "zh:4f85c6130249f45ff0dccdcfe78296382c930c288e2f8ec844d73fa48ab3c4ef",
53 | "zh:74a1270db30043d9601ed70fecea568693552758f912a37b423dec1530a6f390",
54 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
55 | "zh:8125231d0b16283130bac7cb4b0c4972a596af10e1a7348ff905dcb02ea61dc9",
56 | "zh:83f78277025d276ee6f4fd1ae93cf69b748c6601e7cfc7e30f07beca9ce4dfdd",
57 | "zh:abca2c2e14ce0984a1353f03fd13e9dc19312ab7844f64129ec09628e3d5d472",
58 | "zh:b5d0f58057c730aab9a0bf348a9143e8a0ae18f2a3ddfb9f56c603aa62212601",
59 | "zh:bc6054404263c1d7faaffe4c27d1f93dd5a9848d515a6eae42d43828c3e10447",
60 | "zh:cb9d4a0aeebd25cbbae5b7c726deb285c007079191bc43a6a8d6b951b7ef928a",
61 | ]
62 | }
63 |
64 | provider "registry.terraform.io/hashicorp/kubernetes" {
65 | version = "2.12.1"
66 | constraints = "~> 2.11"
67 | hashes = [
68 | "h1:YdDA370JByM9HT5GdLpt34z3BvcVW4BnVXqdgB/vZ6I=",
69 | "zh:1ecb2adff52754fb4680c7cfe6143d1d8c264b00bb0c44f07f5583b1c7f978b8",
70 | "zh:1fbd155088cd5818ad5874e4d59ccf1801e4e1961ac0711442b963315f1967ab",
71 | "zh:29e927c7c8f112ee0e8ab70e71b498f2f2ae6f47df1a14e6fd0fdb6f14b57c00",
72 | "zh:42c2f421da6b5b7c997e42aa04ca1457fceb13dd66099a057057a0812b680836",
73 | "zh:522a7bccd5cd7acbb4ec3ef077d47f4888df7e59ff9f3d598b717ad3ee4fe9c9",
74 | "zh:b45d8dc5dcbc5e30ae570d0c2e198505f47d09098dfd5f004871be8262e6ec1e",
75 | "zh:c3ea0943f2050001c7d6a7115b9b990f148b082ebfc4ff3c2ff3463a8affcc4a",
76 | "zh:f111833a64e06659d2e21864de39b7b7dec462615294d02f04c777956742a930",
77 | "zh:f182dba5707b90b0952d5984c23f7a2da3baa62b4d71e78df7759f16cc88d957",
78 | "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
79 | "zh:f76655a68680887daceabd947b2f68e2103f5bbec49a2bc29530f82ab8e3bca3",
80 | "zh:fadb77352caa570bd3259dfb59c31db614d55bc96df0ff15a3c0cd2e685678b9",
81 | ]
82 | }
83 |
--------------------------------------------------------------------------------
/add-ons/cluster-autoscaler-iam-policy-and-role.tf:
--------------------------------------------------------------------------------
1 | # Resource: IAM Policy for Cluster Autoscaler
2 | resource "aws_iam_policy" "cluster_autoscaler_iam_policy" {
3 | name = "${local.name}-AmazonEKSClusterAutoscalerPolicy"
4 | path = "/"
5 | description = "EKS Cluster Autoscaler Policy"
6 |
7 | # Terraform's "jsonencode" function converts a
8 | # Terraform expression result to valid JSON syntax.
9 | policy = jsonencode({
10 | "Version" : "2012-10-17",
11 | "Statement" : [
12 | {
13 | "Action" : [
14 | "autoscaling:DescribeAutoScalingGroups",
15 | "autoscaling:DescribeAutoScalingInstances",
16 | "autoscaling:DescribeInstances",
17 | "autoscaling:DescribeLaunchConfigurations",
18 | "autoscaling:DescribeTags",
19 | "autoscaling:SetDesiredCapacity",
20 | "autoscaling:TerminateInstanceInAutoScalingGroup",
21 | "ec2:DescribeLaunchTemplateVersions",
22 | "ec2:DescribeInstanceTypes"
23 | ],
24 | "Resource" : "*",
25 | "Effect" : "Allow"
26 | }
27 | ]
28 | })
29 | }
30 |
31 | # Resource: IAM Role for Cluster Autoscaler
32 | ## Create IAM Role and associate it with Cluster Autoscaler IAM Policy
33 | resource "aws_iam_role" "cluster_autoscaler_iam_role" {
34 | name = "${local.name}-cluster-autoscaler"
35 |
36 | # Terraform's "jsonencode" function converts a Terraform expression result to valid JSON syntax.
37 | assume_role_policy = jsonencode({
38 | Version = "2012-10-17"
39 | Statement = [
40 | {
41 | Action = "sts:AssumeRoleWithWebIdentity"
42 | Effect = "Allow"
43 | Sid = ""
44 | Principal = {
45 | Federated = "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_arn}"
46 | }
47 | Condition = {
48 | StringEquals = {
49 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:sub" : "system:serviceaccount:kube-system:cluster-autoscaler"
50 | }
51 | }
52 | },
53 | ]
54 | })
55 |
56 | tags = {
57 | tag-key = "cluster-autoscaler"
58 | }
59 | }
60 |
61 |
62 | # Associate IAM Policy to IAM Role
63 | resource "aws_iam_role_policy_attachment" "cluster_autoscaler_iam_role_policy_attach" {
64 | policy_arn = aws_iam_policy.cluster_autoscaler_iam_policy.arn
65 | role = aws_iam_role.cluster_autoscaler_iam_role.name
66 | }
67 |
68 | output "cluster_autoscaler_iam_role_arn" {
69 | description = "Cluster Autoscaler IAM Role ARN"
70 | value = aws_iam_role.cluster_autoscaler_iam_role.arn
71 | }
72 |
--------------------------------------------------------------------------------
/add-ons/cluster-autoscaler-install.tf:
--------------------------------------------------------------------------------
1 | # Install Cluster Autoscaler using HELM
2 |
3 | # Resource: Helm Release
4 | resource "helm_release" "cluster_autoscaler_release" {
5 | depends_on = [aws_iam_role.cluster_autoscaler_iam_role]
6 | name = "${local.name}-ca"
7 |
8 | repository = "https://kubernetes.github.io/autoscaler"
9 | chart = "cluster-autoscaler"
10 |
11 | namespace = "kube-system"
12 |
13 | set {
14 | name = "cloudProvider"
15 | value = "aws"
16 | }
17 |
18 | set {
19 | name = "autoDiscovery.clusterName"
20 | value = data.terraform_remote_state.eks.outputs.cluster_id
21 | }
22 |
23 | set {
24 | name = "awsRegion"
25 | value = var.aws_region
26 | }
27 |
28 | set {
29 | name = "rbac.serviceAccount.create"
30 | value = "true"
31 | }
32 |
33 | set {
34 | name = "rbac.serviceAccount.name"
35 | value = "cluster-autoscaler"
36 | }
37 |
38 | set {
39 | name = "rbac.serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
40 | value = aws_iam_role.cluster_autoscaler_iam_role.arn
41 | }
42 | # Additional Arguments (Optional) - To Test How to pass Extra Args for Cluster Autoscaler
43 | #set {
44 | # name = "extraArgs.scan-interval"
45 | # value = "20s"
46 | #}
47 |
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/add-ons/cluster-autoscaler-outputs.tf:
--------------------------------------------------------------------------------
1 | # Helm Release Outputs
2 | output "cluster_autoscaler_helm_metadata" {
3 | description = "Metadata Block outlining status of the deployed release."
4 | value = helm_release.cluster_autoscaler_release.metadata
5 | }
6 |
--------------------------------------------------------------------------------
/add-ons/ebs-csi-datasources.tf:
--------------------------------------------------------------------------------
1 | # Datasource: AWS Caller Identity
2 | data "aws_caller_identity" "current" {}
3 |
4 | output "aws_account_id" {
5 | value = data.aws_caller_identity.current.account_id
6 | }
7 |
8 | # Datasource: EBS CSI IAM Policy get from EBS GIT Repo (latest)
9 | data "http" "ebs_csi_iam_policy" {
10 | url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-ebs-csi-driver/master/docs/example-iam-policy.json"
11 |
12 | # Optional request headers
13 | request_headers = {
14 | Accept = "application/json"
15 | }
16 | }
17 |
18 | output "ebs_csi_iam_policy" {
19 | value = data.http.ebs_csi_iam_policy.body
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/add-ons/ebs-csi-iam-policy-and-role.tf:
--------------------------------------------------------------------------------
1 | #data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_arn
2 | #data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn
3 |
4 | # Resource: Create EBS CSI IAM Policy
5 | resource "aws_iam_policy" "ebs_csi_iam_policy" {
6 | name = "${local.name}-AmazonEKS_EBS_CSI_Driver_Policy"
7 | path = "/"
8 | description = "EBS CSI IAM Policy"
9 | policy = data.http.ebs_csi_iam_policy.body
10 | }
11 |
12 | output "ebs_csi_iam_policy_arn" {
13 | value = aws_iam_policy.ebs_csi_iam_policy.arn
14 | }
15 |
16 | # Resource: Create IAM Role and associate the EBS IAM Policy to it
17 | resource "aws_iam_role" "ebs_csi_iam_role" {
18 | name = "${local.name}-ebs-csi-iam-role"
19 |
20 | # Terraform's "jsonencode" function converts a Terraform expression result to valid JSON syntax.
21 | assume_role_policy = jsonencode({
22 | Version = "2012-10-17"
23 | Statement = [
24 | {
25 | Action = "sts:AssumeRoleWithWebIdentity"
26 | Effect = "Allow"
27 | Sid = ""
28 | Principal = {
29 | Federated = "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_arn}"
30 | }
31 | Condition = {
32 | StringEquals = {
33 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:sub" : "system:serviceaccount:kube-system:ebs-csi-controller-sa"
34 | }
35 | }
36 |
37 | },
38 | ]
39 | })
40 |
41 | tags = {
42 | tag-key = "${local.name}-ebs-csi-iam-role"
43 | }
44 | }
45 |
46 | # Associate EBS CSI IAM Policy to EBS CSI IAM Role
47 | resource "aws_iam_role_policy_attachment" "ebs_csi_iam_role_policy_attach" {
48 | policy_arn = aws_iam_policy.ebs_csi_iam_policy.arn
49 | role = aws_iam_role.ebs_csi_iam_role.name
50 | }
51 |
52 | output "ebs_csi_iam_role_arn" {
53 | description = "EBS CSI IAM Role ARN"
54 | value = aws_iam_role.ebs_csi_iam_role.arn
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/add-ons/ebs-csi-install-using-helm.tf:
--------------------------------------------------------------------------------
1 | # Install EBS CSI Driver using HELM
2 | # Resource: Helm Release
3 | resource "helm_release" "ebs_csi_driver" {
4 | depends_on = [
5 | #aws_eks_node_group.eks_ng_1,
6 | #aws_iam_openid_connect_provider.oidc_provider,
7 | aws_iam_role.ebs_csi_iam_role
8 | ]
9 | name = "${local.name}-aws-ebs-csi-driver"
10 |
11 | repository = "https://kubernetes-sigs.github.io/aws-ebs-csi-driver"
12 | chart = "aws-ebs-csi-driver"
13 |
14 | namespace = "kube-system"
15 |
16 | set {
17 | name = "image.repository"
18 | value = "602401143452.dkr.ecr.ap-southeast-1.amazonaws.com/eks/aws-ebs-csi-driver" # Changes based on Region - This is for ap-southeast-1 Additional Reference: https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html
19 | }
20 |
21 | set {
22 | name = "controller.serviceAccount.create"
23 | value = "true"
24 | }
25 |
26 | set {
27 | name = "controller.serviceAccount.name"
28 | value = "ebs-csi-controller-sa"
29 | }
30 |
31 | set {
32 | name = "controller.serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
33 | value = aws_iam_role.ebs_csi_iam_role.arn
34 | }
35 |
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/add-ons/ebs-csi-outputs.tf:
--------------------------------------------------------------------------------
1 | # EBS CSI Helm Release Outputs
2 | output "ebs_csi_helm_metadata" {
3 | description = "Metadata Block outlining status of the deployed release."
4 | value = helm_release.ebs_csi_driver.metadata
5 | }
--------------------------------------------------------------------------------
/add-ons/externaldns-iam-policy-and-role.tf:
--------------------------------------------------------------------------------
1 | # Resource: Create External DNS IAM Policy
2 | resource "aws_iam_policy" "externaldns_iam_policy" {
3 | name = "${local.name}-AllowExternalDNSUpdates"
4 | path = "/"
5 | description = "External DNS IAM Policy"
6 | policy = jsonencode({
7 | "Version" : "2012-10-17",
8 | "Statement" : [
9 | {
10 | "Effect" : "Allow",
11 | "Action" : [
12 | "route53:ChangeResourceRecordSets"
13 | ],
14 | "Resource" : [
15 | "arn:aws:route53:::hostedzone/*"
16 | ]
17 | },
18 | {
19 | "Effect" : "Allow",
20 | "Action" : [
21 | "route53:ListHostedZones",
22 | "route53:ListResourceRecordSets"
23 | ],
24 | "Resource" : [
25 | "*"
26 | ]
27 | }
28 | ]
29 | })
30 | }
31 |
32 | output "externaldns_iam_policy_arn" {
33 | value = aws_iam_policy.externaldns_iam_policy.arn
34 | }
35 |
36 | # Resource: Create IAM Role
37 | resource "aws_iam_role" "externaldns_iam_role" {
38 | name = "${local.name}-externaldns-iam-role"
39 |
40 | # Terraform's "jsonencode" function converts a Terraform expression result to valid JSON syntax.
41 | assume_role_policy = jsonencode({
42 | Version = "2012-10-17"
43 | Statement = [
44 | {
45 | Action = "sts:AssumeRoleWithWebIdentity"
46 | Effect = "Allow"
47 | Sid = ""
48 | Principal = {
49 | Federated = "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_arn}"
50 | }
51 | Condition = {
52 | StringEquals = {
53 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:aud" : "sts.amazonaws.com",
54 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:sub" : "system:serviceaccount:default:external-dns"
55 | }
56 | }
57 | },
58 | ]
59 | })
60 |
61 | tags = {
62 | tag-key = "AllowExternalDNSUpdates"
63 | }
64 | }
65 |
66 | # Associate External DNS IAM Policy to IAM Role
67 | resource "aws_iam_role_policy_attachment" "externaldns_iam_role_policy_attach" {
68 | policy_arn = aws_iam_policy.externaldns_iam_policy.arn
69 | role = aws_iam_role.externaldns_iam_role.name
70 | }
71 |
72 | output "externaldns_iam_role_arn" {
73 | description = "External DNS IAM Role ARN"
74 | value = aws_iam_role.externaldns_iam_role.arn
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/add-ons/externaldns-install.tf:
--------------------------------------------------------------------------------
1 | # Resource: Helm Release
2 | resource "helm_release" "external_dns" {
3 | depends_on = [aws_iam_role.externaldns_iam_role]
4 | name = "external-dns"
5 |
6 | repository = "https://kubernetes-sigs.github.io/external-dns/"
7 | chart = "external-dns"
8 |
9 | namespace = "default"
10 |
11 | set {
12 | name = "image.repository"
13 | value = "k8s.gcr.io/external-dns/external-dns"
14 | }
15 |
16 | set {
17 | name = "serviceAccount.create"
18 | value = "true"
19 | }
20 |
21 | set {
22 | name = "serviceAccount.name"
23 | value = "external-dns"
24 | }
25 |
26 | set {
27 | name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
28 | value = aws_iam_role.externaldns_iam_role.arn
29 | }
30 |
31 | set {
32 | name = "provider" # Default is aws (https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns)
33 | value = "aws"
34 | }
35 |
36 | set {
37 | name = "policy" # Default is "upsert-only" which means DNS records will not get deleted even equivalent Ingress resources are deleted (https://github.com/kubernetes-sigs/external-dns/tree/master/charts/external-dns)
38 | value = "sync" # "sync" will ensure that when ingress resource is deleted, equivalent DNS record in Route53 will get deleted
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/add-ons/externaldns-outputs.tf:
--------------------------------------------------------------------------------
1 | # Helm Release Outputs
2 | output "externaldns_helm_metadata" {
3 | description = "Metadata Block outlining status of the deployed release."
4 | value = helm_release.external_dns.metadata
5 | }
--------------------------------------------------------------------------------
/add-ons/generic-variables.tf:
--------------------------------------------------------------------------------
1 | # Input Variables - Placeholder file
2 | # AWS Region
3 | variable "aws_region" {
4 | description = "Region in which AWS Resources to be created"
5 | type = string
6 | default = "ap-southeast-1"
7 | }
8 | # Environment Variable
9 | variable "environment" {
10 | description = "Environment Variable used as a prefix"
11 | type = string
12 | default = "dev"
13 | }
14 | # Business Division
15 | variable "business_division" {
16 | description = "Business Division in the large organization this Infrastructure belongs"
17 | type = string
18 | default = "ty"
19 | }
20 |
--------------------------------------------------------------------------------
/add-ons/ingress-class.tf:
--------------------------------------------------------------------------------
1 | # Resource: Kubernetes Ingress Class
2 | resource "kubernetes_ingress_class_v1" "ingress_class_default" {
3 | depends_on = [helm_release.loadbalancer_controller]
4 | metadata {
5 | name = "my-aws-ingress-class"
6 | annotations = {
7 | "ingressclass.kubernetes.io/is-default-class" = "true"
8 | }
9 | }
10 | spec {
11 | controller = "ingress.k8s.aws/alb"
12 | }
13 | }
14 |
15 | ## Additional Note
16 | # 1. You can mark a particular IngressClass as the default for your cluster.
17 | # 2. Setting the ingressclass.kubernetes.io/is-default-class annotation to true on an IngressClass resource will ensure that new Ingresses without an ingressClassName field specified will be assigned this default IngressClass.
18 | # 3. Reference: https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/ingress_class/
--------------------------------------------------------------------------------
/add-ons/kubernetes-provider.tf:
--------------------------------------------------------------------------------
1 | # Terraform Kubernetes Provider
2 | provider "kubernetes" {
3 | host = data.terraform_remote_state.eks.outputs.cluster_endpoint
4 | cluster_ca_certificate = base64decode(data.terraform_remote_state.eks.outputs.cluster_certificate_authority_data)
5 | token = data.aws_eks_cluster_auth.cluster.token
6 | }
--------------------------------------------------------------------------------
/add-ons/lbc-datasources.tf:
--------------------------------------------------------------------------------
1 | # Datasource: AWS Load Balancer Controller IAM Policy get from aws-load-balancer-controller/ GIT Repo (latest)
2 | data "http" "lbc_iam_policy" {
3 | url = "https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json"
4 |
5 | # Optional request headers
6 | request_headers = {
7 | Accept = "application/json"
8 | }
9 | }
10 |
11 | output "lbc_iam_policy" {
12 | value = data.http.lbc_iam_policy.body
13 | }
14 |
--------------------------------------------------------------------------------
/add-ons/lbc-helm-provider.tf:
--------------------------------------------------------------------------------
1 | # Datasource: EKS Cluster Auth
2 | data "aws_eks_cluster_auth" "cluster" {
3 | name = data.terraform_remote_state.eks.outputs.cluster_id
4 | }
5 |
6 | # HELM Provider
7 | provider "helm" {
8 | kubernetes {
9 | host = data.terraform_remote_state.eks.outputs.cluster_endpoint
10 | cluster_ca_certificate = base64decode(data.terraform_remote_state.eks.outputs.cluster_certificate_authority_data)
11 | token = data.aws_eks_cluster_auth.cluster.token
12 | }
13 | }
--------------------------------------------------------------------------------
/add-ons/lbc-iam-policy-and-role.tf:
--------------------------------------------------------------------------------
1 |
2 | # Resource: Create AWS Load Balancer Controller IAM Policy
3 | resource "aws_iam_policy" "lbc_iam_policy" {
4 | name = "${local.name}-AWSLoadBalancerControllerIAMPolicy"
5 | path = "/"
6 | description = "AWS Load Balancer Controller IAM Policy"
7 | policy = data.http.lbc_iam_policy.body
8 | }
9 |
10 | output "lbc_iam_policy_arn" {
11 | value = aws_iam_policy.lbc_iam_policy.arn
12 | }
13 |
14 | # Resource: Create IAM Role
15 | resource "aws_iam_role" "lbc_iam_role" {
16 | name = "${local.name}-lbc-iam-role"
17 |
18 | # Terraform's "jsonencode" function converts a Terraform expression result to valid JSON syntax.
19 | assume_role_policy = jsonencode({
20 | Version = "2012-10-17"
21 | Statement = [
22 | {
23 | Action = "sts:AssumeRoleWithWebIdentity"
24 | Effect = "Allow"
25 | Sid = ""
26 | Principal = {
27 | Federated = "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_arn}"
28 | }
29 | Condition = {
30 | StringEquals = {
31 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:aud" : "sts.amazonaws.com",
32 | "${data.terraform_remote_state.eks.outputs.aws_iam_openid_connect_provider_extract_from_arn}:sub" : "system:serviceaccount:kube-system:aws-load-balancer-controller"
33 | }
34 | }
35 | },
36 | ]
37 | })
38 |
39 | tags = {
40 | tag-key = "AWSLoadBalancerControllerIAMPolicy"
41 | }
42 | }
43 |
44 | # Associate Load Balanacer Controller IAM Policy to IAM Role
45 | resource "aws_iam_role_policy_attachment" "lbc_iam_role_policy_attach" {
46 | policy_arn = aws_iam_policy.lbc_iam_policy.arn
47 | role = aws_iam_role.lbc_iam_role.name
48 | }
49 |
50 | output "lbc_iam_role_arn" {
51 | description = "AWS Load Balancer Controller IAM Role ARN"
52 | value = aws_iam_role.lbc_iam_role.arn
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/add-ons/lbc-install.tf:
--------------------------------------------------------------------------------
1 | # Install AWS Load Balancer Controller using HELM
2 |
3 | # Resource: Helm Release
4 | resource "helm_release" "loadbalancer_controller" {
5 | depends_on = [aws_iam_role.lbc_iam_role]
6 | name = "aws-load-balancer-controller"
7 |
8 | repository = "https://aws.github.io/eks-charts"
9 | chart = "aws-load-balancer-controller"
10 |
11 | namespace = "kube-system"
12 |
13 | set {
14 | name = "image.repository"
15 | value = "602401143452.dkr.ecr.ap-southeast-1.amazonaws.com/amazon/aws-load-balancer-controller" # Changes based on Region - This is for ap-southeast-1 Additional Reference: https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html
16 | }
17 |
18 | set {
19 | name = "serviceAccount.create"
20 | value = "true"
21 | }
22 |
23 | set {
24 | name = "serviceAccount.name"
25 | value = "aws-load-balancer-controller"
26 | }
27 |
28 | set {
29 | name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
30 | value = aws_iam_role.lbc_iam_role.arn
31 | }
32 |
33 | set {
34 | name = "vpcId"
35 | value = data.terraform_remote_state.eks.outputs.vpc_id
36 | }
37 |
38 | set {
39 | name = "region"
40 | value = var.aws_region
41 | }
42 |
43 | set {
44 | name = "clusterName"
45 | value = data.terraform_remote_state.eks.outputs.cluster_id
46 | }
47 |
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/add-ons/lbc-outputs.tf:
--------------------------------------------------------------------------------
1 | # Helm Release Outputs
2 | output "lbc_helm_metadata" {
3 | description = "Metadata Block outlining status of the deployed release."
4 | value = helm_release.loadbalancer_controller.metadata
5 | }
--------------------------------------------------------------------------------
/add-ons/local-values.tf:
--------------------------------------------------------------------------------
1 | # Define Local Values in Terraform
2 | locals {
3 | owners = var.business_division
4 | environment = var.environment
5 | name = "${var.business_division}-${var.environment}"
6 | common_tags = {
7 | owners = local.owners
8 | environment = local.environment
9 | }
10 | eks_cluster_name = data.terraform_remote_state.eks.outputs.cluster_id
11 | }
--------------------------------------------------------------------------------
/add-ons/remote-state-datasource.tf:
--------------------------------------------------------------------------------
1 | # Terraform Remote State Datasource - Remote Backend AWS S3
2 | data "terraform_remote_state" "eks" {
3 | backend = "s3"
4 | config = {
5 | bucket = "terraform-on-aws-eks-ty"
6 | key = "dev/eks-cluster/terraform.tfstate"
7 | region = var.aws_region
8 | }
9 | }
--------------------------------------------------------------------------------
/add-ons/versions.tf:
--------------------------------------------------------------------------------
1 | # Terraform Settings Block
2 | terraform {
3 | required_version = ">= 1.0.0"
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = "~> 4.12"
8 | }
9 | helm = {
10 | source = "hashicorp/helm"
11 | #version = "2.5.1"
12 | version = "~> 2.5"
13 | }
14 | http = {
15 | source = "hashicorp/http"
16 | #version = "2.1.0"
17 | version = "~> 2.1"
18 | }
19 | kubernetes = {
20 | source = "hashicorp/kubernetes"
21 | version = "~> 2.11"
22 | }
23 | }
24 | # Adding Backend as S3 for Remote State Storage
25 | backend "s3" {
26 | bucket = "terraform-on-aws-eks-ty"
27 | key = "dev/aws-lbc/terraform.tfstate"
28 | region = "ap-southeast-1"
29 | }
30 | }
31 |
32 | # Terraform AWS Provider Block
33 | provider "aws" {
34 | region = var.aws_region
35 | }
36 |
37 | # Terraform HTTP Provider Block
38 | provider "http" {
39 | # Configuration options
40 | }
--------------------------------------------------------------------------------
/docs/2022-08-07-12-57-11-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-12-57-11-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-12-57-28-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-12-57-28-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-12-59-23-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-12-59-23-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-12-59-50-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-12-59-50-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-13-00-37-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-13-00-37-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-13-00-44-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-13-00-44-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-13-02-49-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-13-02-49-image.png
--------------------------------------------------------------------------------
/docs/2022-08-07-13-03-06-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/2022-08-07-13-03-06-image.png
--------------------------------------------------------------------------------
/docs/devops.drawio:
--------------------------------------------------------------------------------
1 | 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
--------------------------------------------------------------------------------
/docs/devops.drawio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tycloud97/devops-exercise/2e1dcf684c1845cc37366e858e70ea9912d0080c/docs/devops.drawio.png
--------------------------------------------------------------------------------
/docs/~$devops.drawio.bkp:
--------------------------------------------------------------------------------
1 | 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
--------------------------------------------------------------------------------
/helm-values/gitlab-runner-values.yaml:
--------------------------------------------------------------------------------
1 | checkInterval: 3
2 | concurrent: 4
3 | gitlabUrl: https://gitlab.com/
4 | runnerRegistrationToken: "GR1348941D7v1hp6EwKuudPURjrXw"
5 | rbac:
6 | clusterWideAccess: false
7 | create: true
8 | enabled: true
9 | resources:
10 | limits:
11 | memory: 2048Mi
12 | cpu: 1000m
13 | requests:
14 | memory: 1024Mi
15 | cpu: 500m
16 | runners:
17 | image: ubuntu:16.04
18 | privileged: true
19 | builds:
20 | cpuLimit: 200m
21 | memoryLimit: 1024Mi
22 | cpuRequests: 100m
23 | memoryRequests: 128Mi
24 | services:
25 | cpuLimit: 200m
26 | memoryLimit: 512Mi
27 | cpuRequests: 100m
28 | memoryRequests: 128Mi
29 | helpers:
30 | cpuLimit: 200m
31 | memoryLimit: 512Mi
32 | cpuRequests: 100m
33 | memoryRequests: 128Mi
34 |
--------------------------------------------------------------------------------
/infrastructure/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/hashicorp/aws" {
5 | version = "4.24.0"
6 | constraints = "~> 4.14"
7 | hashes = [
8 | "h1:+wJiCQKLEgY8a1ILFbebLgFX6q2xPJVV9wWp7eU2dsI=",
9 | "zh:3b58916e93cab4249bef6fcf6fb2ae3bbf0cb67a876e669205e1f785ffce88a4",
10 | "zh:5a51329c4d91ecdc2879a7d4acbc1dfd521ca6cd9a64f0d6f8c01d99a23fc98d",
11 | "zh:5c65414467db9b4bbf2f83fb1188543d1015514bab8a2336b38fcccb507fc7ca",
12 | "zh:65fc1514f0f1a06463b70694add57589c31debba625d78e25a9434e521a7a290",
13 | "zh:71b357f85d47cdb806df850b950193abae7ed14201edeba184be4c1672631f50",
14 | "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
15 | "zh:a1a89a7fb35fa6160963dae13861033493bd5f3e6bc5fd18a0fd745a066378be",
16 | "zh:a9482369470168f3830a4a688506426769e1beb09fbdae25633acc508c0a9457",
17 | "zh:bf93cb9d15a822bbb0510d3333f763d3d117ca56da350a30ff769049c6851b4c",
18 | "zh:c17a405fe50bb16947b189a30e2c6e5983105023fa0c45bb57fb5e63232b316d",
19 | "zh:d0c2a0bec642444fd2eb1ecc13e5716bcfe30c80aae5622c8a5692b7af143a57",
20 | "zh:dd469fa460f4ce8ebd6a107babf13b1aebee9b2e274f216155f62c23df67c228",
21 | ]
22 | }
23 |
24 | provider "registry.terraform.io/hashicorp/kubernetes" {
25 | version = "2.12.1"
26 | constraints = "~> 2.11"
27 | hashes = [
28 | "h1:YdDA370JByM9HT5GdLpt34z3BvcVW4BnVXqdgB/vZ6I=",
29 | "zh:1ecb2adff52754fb4680c7cfe6143d1d8c264b00bb0c44f07f5583b1c7f978b8",
30 | "zh:1fbd155088cd5818ad5874e4d59ccf1801e4e1961ac0711442b963315f1967ab",
31 | "zh:29e927c7c8f112ee0e8ab70e71b498f2f2ae6f47df1a14e6fd0fdb6f14b57c00",
32 | "zh:42c2f421da6b5b7c997e42aa04ca1457fceb13dd66099a057057a0812b680836",
33 | "zh:522a7bccd5cd7acbb4ec3ef077d47f4888df7e59ff9f3d598b717ad3ee4fe9c9",
34 | "zh:b45d8dc5dcbc5e30ae570d0c2e198505f47d09098dfd5f004871be8262e6ec1e",
35 | "zh:c3ea0943f2050001c7d6a7115b9b990f148b082ebfc4ff3c2ff3463a8affcc4a",
36 | "zh:f111833a64e06659d2e21864de39b7b7dec462615294d02f04c777956742a930",
37 | "zh:f182dba5707b90b0952d5984c23f7a2da3baa62b4d71e78df7759f16cc88d957",
38 | "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
39 | "zh:f76655a68680887daceabd947b2f68e2103f5bbec49a2bc29530f82ab8e3bca3",
40 | "zh:fadb77352caa570bd3259dfb59c31db614d55bc96df0ff15a3c0cd2e685678b9",
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/infrastructure/main.tf:
--------------------------------------------------------------------------------
1 | # Terraform Settings Block
2 | terraform {
3 | required_version = ">= 1.0.0"
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = "~> 4.14"
8 | }
9 | kubernetes = {
10 | source = "hashicorp/kubernetes"
11 | version = "~> 2.11"
12 | }
13 | }
14 | # Adding Backend as S3 for Remote State Storage
15 | backend "s3" {
16 | bucket = "terraform-on-aws-eks-ty"
17 | key = "dev/eks-cluster/terraform.tfstate"
18 | region = "ap-southeast-1"
19 |
20 | # For State Locking
21 | dynamodb_table = "dev-ekscluster"
22 | }
23 | }
24 |
25 | # Terraform Provider Block
26 | provider "aws" {
27 | region = var.aws_region
28 | }
29 |
30 |
31 | # Define Local Values in Terraform
32 | locals {
33 | owners = var.business_division
34 | environment = var.environment
35 | name = "${var.business_division}-${var.environment}"
36 | common_tags = {
37 | owners = local.owners
38 | environment = local.environment
39 | }
40 | eks_cluster_name = "${local.name}-${var.cluster_name}"
41 | }
42 |
43 | // Setup VPC network
44 | module "vpc" {
45 | source = "./modules/vpc"
46 | eks_cluster_name = local.eks_cluster_name
47 | common_tags = local.common_tags
48 | }
49 |
50 | module "iam" {
51 | source = "./modules/iam"
52 | name = local.name
53 | }
54 |
55 | // Setup EKS Cluster
56 | module "eks" {
57 | source = "./modules/eks"
58 | eks_cluster_name = local.eks_cluster_name
59 | name = local.name
60 | public_subnets = module.vpc.public_subnets
61 | private_subnets = module.vpc.private_subnets
62 |
63 | eks_master_role_arn = module.iam.eks_master_role_arn
64 | eks_nodegroup_role_arn = module.iam.eks_nodegroup_role_arn
65 | common_tags = local.common_tags
66 | }
67 |
68 | # Datasource
69 | data "aws_eks_cluster_auth" "cluster" {
70 | name = module.eks.cluster_id
71 | }
72 |
73 | # Terraform Kubernetes Provider
74 | provider "kubernetes" {
75 | host = module.eks.cluster_endpoint
76 | cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
77 | token = data.aws_eks_cluster_auth.cluster.token
78 | }
79 |
80 |
81 | // Kubernetes Workloads
82 | module "k8s" {
83 | source = "./modules/k8s"
84 | eks_nodegroup_role_arn = module.iam.eks_nodegroup_role_arn
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------
/infrastructure/modules/eks/eks-cluster.tf:
--------------------------------------------------------------------------------
1 | # Create AWS EKS Cluster
2 | resource "aws_eks_cluster" "eks_cluster" {
3 | name = "${var.name}-${var.cluster_name}"
4 | role_arn = var.eks_master_role_arn
5 | version = var.cluster_version
6 |
7 | vpc_config {
8 | subnet_ids = var.public_subnets
9 | endpoint_private_access = var.cluster_endpoint_private_access
10 | endpoint_public_access = var.cluster_endpoint_public_access
11 | public_access_cidrs = var.cluster_endpoint_public_access_cidrs
12 | }
13 |
14 | kubernetes_network_config {
15 | service_ipv4_cidr = var.cluster_service_ipv4_cidr
16 | }
17 |
18 | # Enable EKS Cluster Control Plane Logging
19 | enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
20 |
21 | # Ensure that IAM Role permissions are created before and deleted after EKS Cluster handling.
22 | # Otherwise, EKS will not be able to properly delete EKS managed EC2 infrastructure such as Security Groups.
23 | # depends_on = [
24 | # aws_iam_role_policy_attachment.eks-AmazonEKSClusterPolicy,
25 | # aws_iam_role_policy_attachment.eks-AmazonEKSVPCResourceController,
26 | # ]
27 | }
28 |
--------------------------------------------------------------------------------
/infrastructure/modules/eks/eks-node-group-private.tf:
--------------------------------------------------------------------------------
1 | # Create AWS EKS Node Group - Private
2 | resource "aws_eks_node_group" "eks_ng_private" {
3 | cluster_name = aws_eks_cluster.eks_cluster.name
4 |
5 | node_group_name = "${var.name}-eks-ng-private"
6 | node_role_arn = var.eks_nodegroup_role_arn
7 | subnet_ids = var.private_subnets
8 | version = var.cluster_version #(Optional: Defaults to EKS Cluster Kubernetes version)
9 |
10 | ami_type = "AL2_x86_64"
11 | capacity_type = "ON_DEMAND"
12 | disk_size = 20
13 | instance_types = ["t3.medium"]
14 |
15 |
16 | remote_access {
17 | ec2_ssh_key = "eks-terraform-key"
18 | }
19 |
20 | scaling_config {
21 | desired_size = 2
22 | min_size = 2
23 | max_size = 3
24 | }
25 |
26 | # Desired max percentage of unavailable worker nodes during node group update.
27 | update_config {
28 | max_unavailable = 1
29 | #max_unavailable_percentage = 50 # ANY ONE TO USE
30 | }
31 |
32 | # Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
33 | # Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
34 | # depends_on = [
35 | # aws_iam_role_policy_attachment.eks-AmazonEKSWorkerNodePolicy,
36 | # aws_iam_role_policy_attachment.eks-AmazonEKS_CNI_Policy,
37 | # aws_iam_role_policy_attachment.eks-AmazonEC2ContainerRegistryReadOnly,
38 | # kubernetes_config_map_v1.aws_auth
39 | # ]
40 | tags = {
41 | Name = "Private-Node-Group"
42 | # Cluster Autoscaler Tags
43 | "k8s.io/cluster-autoscaler/${var.eks_cluster_name}" = "owned"
44 | "k8s.io/cluster-autoscaler/enabled" = "TRUE"
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/infrastructure/modules/eks/eks-outputs.tf:
--------------------------------------------------------------------------------
1 | # EKS Cluster Outputs
2 | output "cluster_id" {
3 | description = "The name/id of the EKS cluster."
4 | value = aws_eks_cluster.eks_cluster.id
5 | }
6 |
7 | output "cluster_arn" {
8 | description = "The Amazon Resource Name (ARN) of the cluster."
9 | value = aws_eks_cluster.eks_cluster.arn
10 | }
11 |
12 | output "cluster_certificate_authority_data" {
13 | description = "Nested attribute containing certificate-authority-data for your cluster. This is the base64 encoded certificate data required to communicate with your cluster."
14 | value = aws_eks_cluster.eks_cluster.certificate_authority[0].data
15 | }
16 |
17 | output "cluster_endpoint" {
18 | description = "The endpoint for your EKS Kubernetes API."
19 | value = aws_eks_cluster.eks_cluster.endpoint
20 | }
21 |
22 | output "cluster_version" {
23 | description = "The Kubernetes server version for the EKS cluster."
24 | value = aws_eks_cluster.eks_cluster.version
25 | }
26 |
27 | # output "cluster_iam_role_name" {
28 | # description = "IAM role name of the EKS cluster."
29 | # value = aws_iam_role.eks_master_role.name
30 | # }
31 |
32 | # output "cluster_iam_role_arn" {
33 | # description = "IAM role ARN of the EKS cluster."
34 | # value = aws_iam_role.eks_master_role.arn
35 | # }
36 |
37 | output "cluster_oidc_issuer_url" {
38 | description = "The URL on the EKS cluster OIDC Issuer"
39 | value = aws_eks_cluster.eks_cluster.identity[0].oidc[0].issuer
40 | }
41 |
42 | output "cluster_primary_security_group_id" {
43 | description = "The cluster primary security group ID created by the EKS cluster on 1.14 or later. Referred to as 'Cluster security group' in the EKS console."
44 | value = aws_eks_cluster.eks_cluster.vpc_config[0].cluster_security_group_id
45 | }
46 |
47 | /*
48 | # EKS Node Group Outputs - Public
49 |
50 | output "node_group_public_id" {
51 | description = "Public Node Group ID"
52 | value = aws_eks_node_group.eks_ng_public.id
53 | }
54 |
55 | output "node_group_public_arn" {
56 | description = "Public Node Group ARN"
57 | value = aws_eks_node_group.eks_ng_public.arn
58 | }
59 |
60 | output "node_group_public_status" {
61 | description = "Public Node Group status"
62 | value = aws_eks_node_group.eks_ng_public.status
63 | }
64 |
65 | output "node_group_public_version" {
66 | description = "Public Node Group Kubernetes Version"
67 | value = aws_eks_node_group.eks_ng_public.version
68 | }
69 | */
70 |
71 | # EKS Node Group Outputs - Private
72 |
73 | output "node_group_private_id" {
74 | description = "Node Group 1 ID"
75 | value = aws_eks_node_group.eks_ng_private.id
76 | }
77 |
78 | output "node_group_private_arn" {
79 | description = "Private Node Group ARN"
80 | value = aws_eks_node_group.eks_ng_private.arn
81 | }
82 |
83 | output "node_group_private_status" {
84 | description = "Private Node Group status"
85 | value = aws_eks_node_group.eks_ng_private.status
86 | }
87 |
88 | output "node_group_private_version" {
89 | description = "Private Node Group Kubernetes Version"
90 | value = aws_eks_node_group.eks_ng_private.version
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/infrastructure/modules/eks/eks-variables.tf:
--------------------------------------------------------------------------------
1 | # EKS Cluster Input Variables
2 | variable "cluster_name" {
3 | description = "Name of the EKS cluster. Also used as a prefix in names of related resources."
4 | type = string
5 | default = "eksdemo"
6 | }
7 |
8 | variable "cluster_service_ipv4_cidr" {
9 | description = "service ipv4 cidr for the kubernetes cluster"
10 | type = string
11 | default = "172.20.0.0/16"
12 | }
13 |
14 | variable "cluster_version" {
15 | description = "Kubernetes minor version to use for the EKS cluster (for example 1.21)"
16 | type = string
17 | default = "1.22"
18 | }
19 | variable "cluster_endpoint_private_access" {
20 | description = "Indicates whether or not the Amazon EKS private API server endpoint is enabled."
21 | type = bool
22 | default = false
23 | }
24 |
25 | variable "cluster_endpoint_public_access" {
26 | description = "Indicates whether or not the Amazon EKS public API server endpoint is enabled. When it's set to `false` ensure to have a proper private access with `cluster_endpoint_private_access = true`."
27 | type = bool
28 | default = true
29 | }
30 |
31 | variable "cluster_endpoint_public_access_cidrs" {
32 | description = "List of CIDR blocks which can access the Amazon EKS public API server endpoint."
33 | type = list(string)
34 | default = ["0.0.0.0/0"]
35 | }
36 |
37 | variable "name" {
38 | type = string
39 | }
40 |
41 | variable "eks_cluster_name" {
42 | type = string
43 | }
44 |
45 |
46 | variable "public_subnets" {
47 | type = list(string)
48 | }
49 |
50 |
51 |
52 | variable "private_subnets" {
53 | type = list(string)
54 | }
55 |
56 | variable "eks_master_role_arn" {
57 | type = string
58 | }
59 |
60 |
61 | variable "eks_nodegroup_role_arn" {
62 | type = string
63 | }
64 | variable "common_tags" {}
65 |
66 |
67 | # EKS Node Group Variables
68 | ## Placeholder space you can create if required
69 |
70 |
--------------------------------------------------------------------------------
/infrastructure/modules/eks/iam-oidc-connect-provider-variables.tf:
--------------------------------------------------------------------------------
1 | # Input Variables - AWS IAM OIDC Connect Provider
2 |
3 |
4 | # EKS OIDC ROOT CA Thumbprint - valid until 2037
5 | variable "eks_oidc_root_ca_thumbprint" {
6 | type = string
7 | description = "Thumbprint of Root CA for EKS OIDC, Valid until 2037"
8 | default = "9e99a48a9960b14926bb7f3b02e22da2b0ab7280"
9 | }
--------------------------------------------------------------------------------
/infrastructure/modules/eks/iam-oidc-connect-provider.tf:
--------------------------------------------------------------------------------
1 | # Datasource: AWS Partition
2 | # Use this data source to lookup information about the current AWS partition in which Terraform is working
3 | data "aws_partition" "current" {}
4 |
5 | # Resource: AWS IAM Open ID Connect Provider
6 | resource "aws_iam_openid_connect_provider" "oidc_provider" {
7 | client_id_list = ["sts.${data.aws_partition.current.dns_suffix}"]
8 | thumbprint_list = [var.eks_oidc_root_ca_thumbprint]
9 | url = aws_eks_cluster.eks_cluster.identity[0].oidc[0].issuer
10 |
11 | tags = merge(
12 | {
13 | Name = "${var.cluster_name}-eks-irsa"
14 | },
15 | var.common_tags
16 | )
17 | }
18 |
19 | # Output: AWS IAM Open ID Connect Provider ARN
20 | output "aws_iam_openid_connect_provider_arn" {
21 | description = "AWS IAM Open ID Connect Provider ARN"
22 | value = aws_iam_openid_connect_provider.oidc_provider.arn
23 | }
24 |
25 | # Extract OIDC Provider from OIDC Provider ARN
26 | locals {
27 | aws_iam_oidc_connect_provider_extract_from_arn = element(split("oidc-provider/", "${aws_iam_openid_connect_provider.oidc_provider.arn}"), 1)
28 | }
29 | # Output: AWS IAM Open ID Connect Provider
30 | output "aws_iam_openid_connect_provider_extract_from_arn" {
31 | description = "AWS IAM Open ID Connect Provider extract from ARN"
32 | value = local.aws_iam_oidc_connect_provider_extract_from_arn
33 | }
34 |
35 | # Sample Outputs for Reference
36 | /*
37 | aws_iam_openid_connect_provider_arn = "arn:aws:iam::180789647333:oidc-provider/oidc.eks.ap-southeast-1.amazonaws.com/id/A9DED4A4FA341C2A5D985A260650F232"
38 | aws_iam_openid_connect_provider_extract_from_arn = "oidc.eks.ap-southeast-1.amazonaws.com/id/A9DED4A4FA341C2A5D985A260650F232"
39 | */
--------------------------------------------------------------------------------
/infrastructure/modules/iam/iamrole-for-eks-cluster.tf:
--------------------------------------------------------------------------------
1 | # Create IAM Role
2 | resource "aws_iam_role" "eks_master_role" {
3 | name = "${var.name}-eks-master-role"
4 |
5 | assume_role_policy = < 3.11"
11 |
12 | # VPC Basic Details
13 | name = var.eks_cluster_name
14 | cidr = var.vpc_cidr_block
15 | azs = data.aws_availability_zones.available.names
16 | public_subnets = var.vpc_public_subnets
17 | private_subnets = var.vpc_private_subnets
18 |
19 | # Database Subnets
20 | database_subnets = var.vpc_database_subnets
21 | create_database_subnet_group = var.vpc_create_database_subnet_group
22 | create_database_subnet_route_table = var.vpc_create_database_subnet_route_table
23 | # create_database_internet_gateway_route = true
24 | # create_database_nat_gateway_route = true
25 |
26 | # NAT Gateways - Outbound Communication
27 | enable_nat_gateway = var.vpc_enable_nat_gateway
28 | single_nat_gateway = var.vpc_single_nat_gateway
29 |
30 | # VPC DNS Parameters
31 | enable_dns_hostnames = true
32 | enable_dns_support = true
33 |
34 |
35 | tags = var.common_tags
36 | vpc_tags = var.common_tags
37 |
38 | # Additional Tags to Subnets
39 | public_subnet_tags = {
40 | Type = "Public Subnets"
41 | "kubernetes.io/role/elb" = 1
42 | "kubernetes.io/cluster/${var.eks_cluster_name}" = "shared"
43 | }
44 | private_subnet_tags = {
45 | Type = "private-subnets"
46 | "kubernetes.io/role/internal-elb" = 1
47 | "kubernetes.io/cluster/${var.eks_cluster_name}" = "shared"
48 | }
49 |
50 | database_subnet_tags = {
51 | Type = "database-subnets"
52 | }
53 | }
--------------------------------------------------------------------------------
/infrastructure/outputs.tf:
--------------------------------------------------------------------------------
1 | # EKS Cluster Outputs
2 | output "cluster_id" {
3 | description = "The name/id of the EKS cluster."
4 | value = module.eks.cluster_id
5 | }
6 |
7 | output "cluster_certificate_authority_data" {
8 | description = "Nested attribute containing certificate-authority-data for your cluster. This is the base64 encoded certificate data required to communicate with your cluster."
9 | value = module.eks.cluster_certificate_authority_data
10 | }
11 |
12 | output "aws_iam_openid_connect_provider_arn" {
13 | description = "AWS IAM Open ID Connect Provider ARN"
14 | value = module.eks.aws_iam_openid_connect_provider_arn
15 | }
16 |
17 | output "aws_iam_openid_connect_provider_extract_from_arn" {
18 | description = "AWS IAM Open ID Connect Provider extract from ARN"
19 | value = module.eks.aws_iam_openid_connect_provider_extract_from_arn
20 | }
21 |
22 | output "cluster_endpoint" {
23 | description = "The endpoint for your EKS Kubernetes API."
24 | value = module.eks.cluster_endpoint
25 | }
26 |
27 | output "vpc_id" {
28 | description = "The ID of the VPC"
29 | value = module.vpc.vpc_id
30 | }
31 |
--------------------------------------------------------------------------------
/infrastructure/variables.tf:
--------------------------------------------------------------------------------
1 | # Input Variables
2 | # AWS Region
3 | variable "aws_region" {
4 | description = "Region in which AWS Resources to be created"
5 | type = string
6 | default = "ap-southeast-1"
7 | }
8 | # Environment Variable
9 | variable "environment" {
10 | description = "Environment Variable used as a prefix"
11 | type = string
12 | default = "dev"
13 | }
14 | # Business Division
15 | variable "business_division" {
16 | description = "Business Division in the large organization this Infrastructure belongs"
17 | type = string
18 | default = "ty"
19 | }
20 |
21 | # EKS Cluster Input Variables
22 | variable "cluster_name" {
23 | description = "Name of the EKS cluster. Also used as a prefix in names of related resources."
24 | type = string
25 | default = "eksdemo"
26 | }
--------------------------------------------------------------------------------