├── provider.tf
├── .gitignore
├── versions.tf
├── .vscode
└── settings.json
├── README.md
├── k8s
└── app.yaml
├── main.tf
├── output.tf
└── vpc.tf
/provider.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | profile = "default"
3 | region = "eu-west-1"
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | terraform.tfstate
3 | terraform.tfstate.backup
4 | .terraform
5 | .terrafor*
6 |
--------------------------------------------------------------------------------
/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 0.13.1"
3 |
4 | required_providers {
5 | aws = {
6 | source = "hashicorp/aws"
7 | version = ">= 3.71"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "workbench.colorCustomizations": {
3 | "editor.lineHighlightBackground": "#1073cf2d",
4 | "editor.lineHighlightBorder": "#9fced11f",
5 | "activityBar.background": "#4E2001",
6 | "titleBar.activeBackground": "#6E2D01",
7 | "titleBar.activeForeground": "#FFFBF8"
8 | }
9 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Requirements
2 |
3 | | Name | Version |
4 | |------|---------|
5 | | [terraform](#requirement\_terraform) | >= 0.13.1 |
6 | | [aws](#requirement\_aws) | >= 3.71 |
7 |
8 | ## Providers
9 |
10 | | Name | Version |
11 | |------|---------|
12 | | [aws](#provider\_aws) | >= 3.71 |
13 |
14 | # How to configure VPC and EKS from scratch
15 |
16 | with this package you can have VPC and EKS from scratch. just clone it and then put the following commands. please be sure about your aws cli profile.
17 |
18 | `terraform init`
19 |
20 | `terraform fmt`
21 |
22 | `terraform validate`
23 |
24 | `terraform apply`
25 |
26 | ### create kub config
27 | check your kube config first
28 |
29 | `cat ~/.kube/config`
30 |
31 | create your context
32 |
33 | `aws eks --region eu-west-1 update-kubeconfig --name eks --profile default`
34 |
35 | ### you can find the k8s configuration on k8s folder
36 | k8s -> app.yaml
37 | you have to apply it with kubectl command
38 | and know you check your cluster
--------------------------------------------------------------------------------
/k8s/app.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: apps/v1
3 | kind: Deployment
4 | metadata:
5 | name: nginx
6 | labels:
7 | app: nginx
8 | spec:
9 | replicas: 1
10 | selector:
11 | matchLabels:
12 | app: nginx
13 | template:
14 | metadata:
15 | labels:
16 | app: nginx
17 | spec:
18 | containers:
19 | - name: nginx
20 | image: nginx:1.14.2
21 | ports:
22 | - containerPort: 80
23 | ---
24 | apiVersion: v1
25 | kind: Service
26 | metadata:
27 | name: internal-nginx-service
28 | annotations:
29 | service.beta.kubernetes.io/aws-load-balancer-type: nlb
30 | service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true'
31 | service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
32 | spec:
33 | selector:
34 | app: nginx
35 | type: LoadBalancer
36 | ports:
37 | - protocol: TCP
38 | port: 80
39 | ---
40 | apiVersion: v1
41 | kind: Service
42 | metadata:
43 | name: external-nginx-service
44 | annotations:
45 | service.beta.kubernetes.io/aws-load-balancer-type: nlb
46 | service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true'
47 | spec:
48 | selector:
49 | app: nginx
50 | type: LoadBalancer
51 | ports:
52 | - protocol: TCP
53 | port: 80
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | ################################
2 | # Eks cluster
3 | ################################
4 |
5 | resource "aws_eks_cluster" "eks" {
6 | name = "eks"
7 | role_arn = aws_iam_role.eks_cluster.arn
8 |
9 |
10 | vpc_config {
11 | endpoint_private_access = false
12 | endpoint_public_access = true
13 | subnet_ids = [aws_subnet.public_1.id, aws_subnet.public_2.id, aws_subnet.private_1.id, aws_subnet.private_2.id]
14 | }
15 |
16 | # Ensure that IAM Role permissions are created before and deleted after EKS Cluster handling.
17 | # Otherwise, EKS will not be able to properly delete EKS managed EC2 infrastructure such as Security Groups.
18 | depends_on = [
19 | aws_iam_role_policy_attachment.amazon_eks_cluster_policy,
20 |
21 | ]
22 | }
23 |
24 | ################################
25 | # Eks cluster iam role
26 | ################################
27 | resource "aws_iam_role" "eks_cluster" {
28 | name = "eks-cluster"
29 |
30 | # Terraform's "jsonencode" function converts a
31 | # Terraform expression result to valid JSON syntax.
32 | assume_role_policy = jsonencode({
33 | Version = "2012-10-17"
34 | Statement = [
35 | {
36 | Action = "sts:AssumeRole"
37 | Effect = "Allow"
38 | Sid = ""
39 | Principal = {
40 | Service = "eks.amazonaws.com"
41 | }
42 | },
43 | ]
44 | })
45 |
46 |
47 | }
48 |
49 |
50 | resource "aws_iam_role_policy_attachment" "amazon_eks_cluster_policy" {
51 | role = aws_iam_role.eks_cluster.name
52 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
53 | }
54 |
55 | ################################
56 | # Eks node group
57 | ################################
58 | resource "aws_eks_node_group" "node_general" {
59 | cluster_name = aws_eks_cluster.eks.name
60 | node_group_name = "node-general"
61 | node_role_arn = aws_iam_role.node_general.arn
62 | subnet_ids = [aws_subnet.private_1.id, aws_subnet.private_2.id]
63 |
64 | scaling_config {
65 | desired_size = 1
66 | max_size = 1
67 | min_size = 1
68 | }
69 |
70 | ami_type = "AL2_x86_64"
71 | #SPOT and ON_DEMAND are valid
72 | capacity_type = "ON_DEMAND"
73 | #disk size for worker node
74 | disk_size = 20
75 | force_update_version = false
76 | instance_types = ["t3.small"]
77 | labels = {
78 | role = "nodes-general"
79 | }
80 | # #kubernetes version
81 |
82 | # version = "1.8"
83 |
84 |
85 | # Ensure that IAM Role permissions are created before and deleted after EKS Node Group handling.
86 | # Otherwise, EKS will not be able to properly delete EC2 Instances and Elastic Network Interfaces.
87 | depends_on = [
88 | aws_iam_role_policy_attachment.amazon_eks_worker_node_policy_general,
89 | aws_iam_role_policy_attachment.amazon_eks_cni_policy_general,
90 | aws_iam_role_policy_attachment.amazon_ec2_container_registry_read_only,
91 | ]
92 | }
93 |
94 | ################################
95 | # Role and attachments
96 | ################################
97 |
98 | resource "aws_iam_role" "node_general" {
99 | name = "eks-node-group-general"
100 |
101 | # Terraform's "jsonencode" function converts a
102 | # Terraform expression result to valid JSON syntax.
103 | assume_role_policy = jsonencode({
104 | Version = "2012-10-17"
105 | Statement = [
106 | {
107 | Action = "sts:AssumeRole"
108 | Effect = "Allow"
109 | Sid = ""
110 | Principal = {
111 | Service = "ec2.amazonaws.com"
112 | }
113 | },
114 | ]
115 | })
116 |
117 | }
118 |
119 | resource "aws_iam_role_policy_attachment" "amazon_eks_worker_node_policy_general" {
120 | role = aws_iam_role.node_general.name
121 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
122 | }
123 |
124 |
125 | resource "aws_iam_role_policy_attachment" "amazon_eks_cni_policy_general" {
126 | role = aws_iam_role.node_general.name
127 | policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
128 | }
129 |
130 |
131 | resource "aws_iam_role_policy_attachment" "amazon_ec2_container_registry_read_only" {
132 | role = aws_iam_role.node_general.name
133 | policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
134 | }
135 |
--------------------------------------------------------------------------------
/output.tf:
--------------------------------------------------------------------------------
1 | ################################
2 | ## VPC
3 | ################################
4 |
5 | output "vpc_id" {
6 | value = aws_vpc.main.id
7 | description = "vpc id"
8 | sensitive = false
9 | }
10 | output "vpc_arn" {
11 | value = aws_vpc.main.arn
12 | description = "vpc arn"
13 | sensitive = false
14 | }
15 | output "vpc_instance_tenancy" {
16 | value = aws_vpc.main.instance_tenancy
17 | description = "vpc instance_tenancy"
18 | sensitive = false
19 | }
20 | output "vpc_enable_dns_support" {
21 | value = aws_vpc.main.enable_dns_support
22 | description = "vpc enable_dns_support"
23 | sensitive = false
24 | }
25 | output "vpc_enable_dns_hostnames" {
26 | value = aws_vpc.main.enable_dns_hostnames
27 | description = "vpc enable_dns_hostnames"
28 | sensitive = false
29 | }
30 | output "vpc_enable_classiclink" {
31 | value = aws_vpc.main.enable_classiclink
32 | description = "vpc enable_classiclink"
33 | sensitive = false
34 | }
35 | output "vpc_default_route_table_id" {
36 | value = aws_vpc.main.default_route_table_id
37 | description = "vpc default_route_table_id"
38 | sensitive = false
39 | }
40 | output "vpc_main_route_table_id" {
41 | value = aws_vpc.main.main_route_table_id
42 | description = "vpc main_route_table_id"
43 | sensitive = false
44 | }
45 | output "vpc_default_network_acl_id" {
46 | value = aws_vpc.main.default_network_acl_id
47 | description = "vpc default_network_acl_id"
48 | sensitive = false
49 | }
50 | output "vpc_default_security_group_id" {
51 | value = aws_vpc.main.default_security_group_id
52 | description = "vpc default_security_group_id"
53 | sensitive = false
54 | }
55 |
56 | ################################
57 | ## GW1
58 | ################################
59 |
60 | output "aws_nat_gateway_gw1_id" {
61 | value = aws_nat_gateway.gw1.id
62 | description = "internet gateway id"
63 | sensitive = false
64 | }
65 | output "aws_nat_gateway_gw1_allocation_id" {
66 | value = aws_nat_gateway.gw1.allocation_id
67 | description = "gateway_nat1_allocation_id"
68 | sensitive = false
69 | }
70 | output "aws_nat_gateway_gw1_subnet_id" {
71 | value = aws_nat_gateway.gw1.subnet_id
72 | description = "gateway_nat1_subnet_id"
73 | sensitive = false
74 | }
75 | output "aws_nat_gateway_gw1_private_ip" {
76 | value = aws_nat_gateway.gw1.private_ip
77 | description = "gateway_nat1_private_ip"
78 | sensitive = false
79 | }
80 | output "aws_nat_gateway_gw1_public_ip" {
81 | value = aws_nat_gateway.gw1.public_ip
82 | description = "gateway_nat1_public_ip"
83 | sensitive = false
84 | }
85 | output "aws_nat_gateway_gw1_tags_all" {
86 | value = aws_nat_gateway.gw1.tags_all
87 | description = "gateway_nat1_tags_all"
88 | sensitive = false
89 | }
90 |
91 | ################################
92 | ## GW2
93 | ################################
94 |
95 | output "aws_nat_gateway_gw2_id" {
96 | value = aws_nat_gateway.gw2.id
97 | description = "internet gateway id"
98 | sensitive = false
99 | }
100 | output "aws_nat_gateway_gw2_allocation_id" {
101 | value = aws_nat_gateway.gw2.allocation_id
102 | description = "gateway_gw2_allocation_id"
103 | sensitive = false
104 | }
105 | output "aws_nat_gateway_gw2_subnet_id" {
106 | value = aws_nat_gateway.gw2.subnet_id
107 | description = "gateway_gw2_subnet_id"
108 | sensitive = false
109 | }
110 | output "aws_nat_gateway_gw2_private_ip" {
111 | value = aws_nat_gateway.gw2.private_ip
112 | description = "gateway_gw2_private_ip"
113 | sensitive = false
114 | }
115 | output "aws_nat_gateway_gw2_public_ip" {
116 | value = aws_nat_gateway.gw2.public_ip
117 | description = "gateway_gw2_public_ip"
118 | sensitive = false
119 | }
120 | output "aws_nat_gateway_gw2_tags_all" {
121 | value = aws_nat_gateway.gw2.tags_all
122 | description = "gateway_gw2_tags_all"
123 | sensitive = false
124 | }
125 |
126 | ################################
127 | ## GW2
128 | ################################
129 |
130 | output "internet_gateway_id" {
131 | value = aws_internet_gateway.main.id
132 | description = "internet gateway id"
133 | sensitive = false
134 | }
135 | output "internet_gateway_arn" {
136 | value = aws_internet_gateway.main.arn
137 | description = "internet gateway arn"
138 | sensitive = false
139 | }
140 | output "internet_gateway_owner_id" {
141 | value = aws_internet_gateway.main.owner_id
142 | description = "internet gateway owner_id"
143 | sensitive = false
144 | }
145 | output "internet_gateway_tags_all" {
146 | value = aws_internet_gateway.main.tags_all
147 | description = "internet gateway tags_all"
148 | sensitive = false
149 | }
150 |
151 | ################################
152 | ## EKS
153 | ################################
154 |
155 | output "aws_eks_cluster_endpoint" {
156 | value = aws_eks_cluster.eks.endpoint
157 | }
158 | output "aws_eks_cluster_arn" {
159 | value = aws_eks_cluster.eks.arn
160 | }
161 | output "aws_eks_cluster_id" {
162 | value = aws_eks_cluster.eks.id
163 | }
164 | output "aws_eks_cluster_status" {
165 | value = aws_eks_cluster.eks.status
166 | }
167 | output "aws_eks_created_at" {
168 | value = aws_eks_cluster.eks.created_at
169 | }
170 |
--------------------------------------------------------------------------------
/vpc.tf:
--------------------------------------------------------------------------------
1 | ################################
2 | ## VPC
3 | ################################
4 |
5 | resource "aws_vpc" "main" {
6 | cidr_block = "192.168.0.0/16"
7 | instance_tenancy = "default"
8 |
9 | enable_dns_support = true
10 | enable_dns_hostnames = true
11 | enable_classiclink = false
12 | enable_classiclink_dns_support = false
13 | assign_generated_ipv6_cidr_block = false
14 | tags = {
15 | Name = "main"
16 | Terraform = "true"
17 | }
18 | }
19 |
20 | ################################
21 | ## Private Subnet
22 | ################################
23 |
24 | resource "aws_subnet" "private_1" {
25 | vpc_id = aws_vpc.main.id
26 | cidr_block = "192.168.128.0/18"
27 | #AZ availability zone
28 | availability_zone = "eu-west-1a"
29 |
30 |
31 | tags = {
32 | Name = "private-eu-west-1a"
33 | "kubernetes.io/cluster/eks" = "shared"
34 | "kubernetes.io/role/internal-elb" = 1
35 | Terraform = "true"
36 | }
37 | }
38 |
39 |
40 | resource "aws_subnet" "private_2" {
41 | vpc_id = aws_vpc.main.id
42 | cidr_block = "192.168.192.0/18"
43 | #AZ availability zone
44 | availability_zone = "eu-west-1b"
45 |
46 |
47 | tags = {
48 | Name = "private-eu-west-1b"
49 | "kubernetes.io/cluster/eks" = "shared"
50 | "kubernetes.io/role/internal-elb" = 1
51 | Terraform = "true"
52 | }
53 | }
54 |
55 | ################################
56 | ## Private routing table
57 | ################################
58 |
59 | resource "aws_route_table" "private1" {
60 | vpc_id = aws_vpc.main.id
61 |
62 | route {
63 | cidr_block = "0.0.0.0/0"
64 | nat_gateway_id = aws_nat_gateway.gw1.id
65 | }
66 |
67 | tags = {
68 | Name = "private1"
69 | }
70 | }
71 |
72 | resource "aws_route_table" "private2" {
73 | vpc_id = aws_vpc.main.id
74 |
75 | route {
76 | cidr_block = "0.0.0.0/0"
77 | nat_gateway_id = aws_nat_gateway.gw2.id
78 | }
79 |
80 | tags = {
81 | Name = "private2"
82 | }
83 | }
84 |
85 | ################################
86 | ## Private routing table association
87 | ################################
88 |
89 | resource "aws_route_table_association" "private1" {
90 | subnet_id = aws_subnet.private_1.id
91 | route_table_id = aws_route_table.private1.id
92 | }
93 | resource "aws_route_table_association" "private2" {
94 | subnet_id = aws_subnet.private_2.id
95 | route_table_id = aws_route_table.private2.id
96 | }
97 |
98 | ################################
99 | ## Public Subnet
100 | ################################
101 |
102 | resource "aws_subnet" "public_1" {
103 | vpc_id = aws_vpc.main.id
104 | cidr_block = "192.168.0.0/18"
105 | #AZ availability zone
106 | availability_zone = "eu-west-1a"
107 | map_public_ip_on_launch = true
108 |
109 | tags = {
110 | Name = "public-eu-west-1a"
111 | "kubernetes.io/cluster/eks" = "shared"
112 | "kubernetes.io/role/elb" = 1
113 | Terraform = "true"
114 | }
115 | }
116 |
117 |
118 | resource "aws_subnet" "public_2" {
119 | vpc_id = aws_vpc.main.id
120 | cidr_block = "192.168.64.0/18"
121 | #AZ availability zone
122 | availability_zone = "eu-west-1b"
123 | map_public_ip_on_launch = true
124 |
125 | tags = {
126 | Name = "public-eu-west-1b"
127 | "kubernetes.io/cluster/eks" = "shared"
128 | "kubernetes.io/role/elb" = 1
129 | Terraform = "true"
130 | }
131 | }
132 |
133 | ################################
134 | ## Public routing table
135 | ################################
136 | resource "aws_route_table" "public" {
137 | vpc_id = aws_vpc.main.id
138 |
139 | route {
140 | cidr_block = "0.0.0.0/0"
141 | gateway_id = aws_internet_gateway.main.id
142 | }
143 |
144 |
145 | tags = {
146 | Name = "public"
147 | Terraform = "true"
148 | }
149 | }
150 |
151 | ################################
152 | ## Public routing table association
153 | ################################
154 |
155 | resource "aws_route_table_association" "public1" {
156 | subnet_id = aws_subnet.public_1.id
157 | route_table_id = aws_route_table.public.id
158 | }
159 | resource "aws_route_table_association" "public2" {
160 | subnet_id = aws_subnet.public_2.id
161 | route_table_id = aws_route_table.public.id
162 | }
163 |
164 | ################################
165 | ## NTGW 1
166 | ################################
167 |
168 | resource "aws_nat_gateway" "gw1" {
169 | allocation_id = aws_eip.nat1.id
170 | subnet_id = aws_subnet.public_1.id
171 |
172 | tags = {
173 | Name = "gw1 NAT1"
174 | }
175 |
176 | # To ensure proper ordering, it is recommended to add an explicit dependency
177 | # on the Internet Gateway for the VPC.
178 | depends_on = [aws_internet_gateway.main]
179 | }
180 |
181 | ################################
182 | ## NTGW 2
183 | ################################
184 |
185 | resource "aws_nat_gateway" "gw2" {
186 | allocation_id = aws_eip.nat2.id
187 | subnet_id = aws_subnet.public_2.id
188 |
189 | tags = {
190 | Name = "NAT2 gw2"
191 | }
192 |
193 | # To ensure proper ordering, it is recommended to add an explicit dependency
194 | # on the Internet Gateway for the VPC.
195 | depends_on = [aws_internet_gateway.main]
196 | }
197 |
198 | ################################
199 | ## IGW
200 | ################################
201 |
202 | resource "aws_internet_gateway" "main" {
203 | vpc_id = aws_vpc.main.id
204 |
205 | tags = {
206 | Name = "main"
207 | Terraform = "true"
208 | }
209 | }
210 |
211 | ################################
212 | ## EIP 1
213 | ################################
214 |
215 | resource "aws_eip" "nat1" {
216 | #for availablity zone 1 ( public1 and private1 )
217 | depends_on = [aws_internet_gateway.main]
218 |
219 | tags = {
220 | Terraform = "true"
221 | }
222 | }
223 |
224 | ################################
225 | ## EIP 2
226 | ################################
227 |
228 | resource "aws_eip" "nat2" {
229 | #for availablity zone 2 ( public2 and private2 )
230 | depends_on = [aws_internet_gateway.main]
231 |
232 | tags = {
233 | Terraform = "true"
234 | }
235 | }
236 |
--------------------------------------------------------------------------------