Skip to content

Commit e704c86

Browse files
author
Arnel Jan Sarmiento
committed
feat: Implement VPC module for AWS, including configuration for public and private subnets, NAT gateways, and outputs for VPC resources
1 parent 637a671 commit e704c86

11 files changed

Lines changed: 378 additions & 0 deletions

File tree

modules/aws/vpc/main.tf

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
terraform {
2+
required_version = ">= 1.14.0"
3+
required_providers {
4+
aws = {
5+
source = "hashicorp/aws"
6+
version = ">= 5.65.0"
7+
}
8+
}
9+
}
10+
11+
locals {
12+
az_keys = { for i, az in var.availability_zones : az => i }
13+
14+
# When single_nat_gateway is true, all private subnets route through the first AZ's NAT.
15+
# Otherwise, each AZ gets its own NAT gateway.
16+
nat_az_keys = var.enable_nat_gateway ? (
17+
var.single_nat_gateway ? { (var.availability_zones[0]) = 0 } : local.az_keys
18+
) : {}
19+
}
20+
21+
# ------------------------------------------------------------------------------
22+
# VPC
23+
# ------------------------------------------------------------------------------
24+
25+
resource "aws_vpc" "this" {
26+
cidr_block = var.cidr_block
27+
enable_dns_support = true
28+
enable_dns_hostnames = true
29+
30+
tags = {
31+
Name = var.name
32+
}
33+
}
34+
35+
# ------------------------------------------------------------------------------
36+
# Internet Gateway
37+
# ------------------------------------------------------------------------------
38+
39+
resource "aws_internet_gateway" "this" {
40+
vpc_id = aws_vpc.this.id
41+
42+
tags = {
43+
Name = "${var.name}-igw"
44+
}
45+
}
46+
47+
# ------------------------------------------------------------------------------
48+
# Public Subnets
49+
# ------------------------------------------------------------------------------
50+
51+
resource "aws_subnet" "public" {
52+
for_each = local.az_keys
53+
54+
vpc_id = aws_vpc.this.id
55+
cidr_block = var.public_subnet_cidrs[each.value]
56+
availability_zone = each.key
57+
map_public_ip_on_launch = true
58+
59+
tags = {
60+
Name = "${var.name}-public-${each.key}"
61+
}
62+
}
63+
64+
resource "aws_route_table" "public" {
65+
vpc_id = aws_vpc.this.id
66+
67+
tags = {
68+
Name = "${var.name}-public"
69+
}
70+
}
71+
72+
resource "aws_route" "public_internet" {
73+
route_table_id = aws_route_table.public.id
74+
destination_cidr_block = "0.0.0.0/0"
75+
gateway_id = aws_internet_gateway.this.id
76+
}
77+
78+
resource "aws_route_table_association" "public" {
79+
for_each = aws_subnet.public
80+
81+
subnet_id = each.value.id
82+
route_table_id = aws_route_table.public.id
83+
}
84+
85+
# ------------------------------------------------------------------------------
86+
# Private Subnets
87+
# ------------------------------------------------------------------------------
88+
89+
resource "aws_subnet" "private" {
90+
for_each = local.az_keys
91+
92+
vpc_id = aws_vpc.this.id
93+
cidr_block = var.private_subnet_cidrs[each.value]
94+
availability_zone = each.key
95+
96+
tags = {
97+
Name = "${var.name}-private-${each.key}"
98+
}
99+
}
100+
101+
resource "aws_route_table" "private" {
102+
for_each = local.az_keys
103+
104+
vpc_id = aws_vpc.this.id
105+
106+
tags = {
107+
Name = "${var.name}-private-${each.key}"
108+
}
109+
}
110+
111+
resource "aws_route_table_association" "private" {
112+
for_each = aws_subnet.private
113+
114+
subnet_id = each.value.id
115+
route_table_id = aws_route_table.private[each.key].id
116+
}
117+
118+
# ------------------------------------------------------------------------------
119+
# NAT Gateway (optional)
120+
# ------------------------------------------------------------------------------
121+
122+
resource "aws_eip" "nat" {
123+
for_each = local.nat_az_keys
124+
125+
domain = "vpc"
126+
127+
tags = {
128+
Name = "${var.name}-nat-${each.key}"
129+
}
130+
}
131+
132+
resource "aws_nat_gateway" "this" {
133+
for_each = local.nat_az_keys
134+
135+
allocation_id = aws_eip.nat[each.key].id
136+
subnet_id = aws_subnet.public[each.key].id
137+
138+
tags = {
139+
Name = "${var.name}-nat-${each.key}"
140+
}
141+
}
142+
143+
resource "aws_route" "private_nat" {
144+
for_each = var.enable_nat_gateway ? local.az_keys : {}
145+
146+
route_table_id = aws_route_table.private[each.key].id
147+
destination_cidr_block = "0.0.0.0/0"
148+
nat_gateway_id = var.single_nat_gateway ? (
149+
aws_nat_gateway.this[var.availability_zones[0]].id
150+
) : aws_nat_gateway.this[each.key].id
151+
}

modules/aws/vpc/outputs.tf

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
output "vpc_id" {
2+
description = "ID of the VPC."
3+
value = aws_vpc.this.id
4+
}
5+
6+
output "vpc_cidr_block" {
7+
description = "CIDR block of the VPC."
8+
value = aws_vpc.this.cidr_block
9+
}
10+
11+
output "public_subnet_ids" {
12+
description = "List of public subnet IDs."
13+
value = [for s in aws_subnet.public : s.id]
14+
}
15+
16+
output "private_subnet_ids" {
17+
description = "List of private subnet IDs."
18+
value = [for s in aws_subnet.private : s.id]
19+
}
20+
21+
output "public_subnet_cidrs" {
22+
description = "List of public subnet CIDR blocks."
23+
value = [for s in aws_subnet.public : s.cidr_block]
24+
}
25+
26+
output "private_subnet_cidrs" {
27+
description = "List of private subnet CIDR blocks."
28+
value = [for s in aws_subnet.private : s.cidr_block]
29+
}
30+
31+
output "internet_gateway_id" {
32+
description = "ID of the internet gateway."
33+
value = aws_internet_gateway.this.id
34+
}
35+
36+
output "nat_gateway_ids" {
37+
description = "List of NAT gateway IDs. Empty when enable_nat_gateway is false."
38+
value = [for ng in aws_nat_gateway.this : ng.id]
39+
}
40+
41+
output "public_route_table_id" {
42+
description = "ID of the public route table."
43+
value = aws_route_table.public.id
44+
}
45+
46+
output "private_route_table_ids" {
47+
description = "List of private route table IDs."
48+
value = [for rt in aws_route_table.private : rt.id]
49+
}

modules/aws/vpc/variables.tf

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
variable "name" {
2+
description = "Name prefix for all VPC resources."
3+
type = string
4+
}
5+
6+
variable "cidr_block" {
7+
description = "CIDR block for the VPC (e.g. 10.10.0.0/16)."
8+
type = string
9+
}
10+
11+
variable "availability_zones" {
12+
description = "List of availability zones for subnet placement."
13+
type = list(string)
14+
}
15+
16+
variable "public_subnet_cidrs" {
17+
description = "CIDR blocks for public subnets, one per availability zone."
18+
type = list(string)
19+
}
20+
21+
variable "private_subnet_cidrs" {
22+
description = "CIDR blocks for private subnets, one per availability zone."
23+
type = list(string)
24+
}
25+
26+
variable "enable_nat_gateway" {
27+
description = "Create a NAT gateway for private subnet internet access."
28+
type = bool
29+
default = false
30+
}
31+
32+
variable "single_nat_gateway" {
33+
description = "Use a single NAT gateway instead of one per AZ. Only applies when enable_nat_gateway is true."
34+
type = bool
35+
default = true
36+
}

workspaces/nonprod/main.tf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,21 @@ module "github_oidc" {
1212
role_name = "github_oidc_role"
1313
allowed_repos = var.allowed_github_repos
1414
}
15+
16+
module "vpc" {
17+
source = "../../modules/aws/vpc"
18+
19+
name = "durianpy-nonprod"
20+
cidr_block = "10.30.0.0/16"
21+
availability_zones = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
22+
public_subnet_cidrs = [
23+
"10.30.0.0/20",
24+
"10.30.16.0/20",
25+
"10.30.32.0/20",
26+
]
27+
private_subnet_cidrs = [
28+
"10.30.48.0/20",
29+
"10.30.64.0/20",
30+
"10.30.80.0/20",
31+
]
32+
}

workspaces/nonprod/outputs.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,18 @@ output "budget_name" {
77
description = "Name of the nonprod account cost budget."
88
value = module.budget.budget_name
99
}
10+
11+
output "vpc_id" {
12+
description = "ID of the nonprod account VPC."
13+
value = module.vpc.vpc_id
14+
}
15+
16+
output "vpc_public_subnet_ids" {
17+
description = "Public subnet IDs in the nonprod account VPC."
18+
value = module.vpc.public_subnet_ids
19+
}
20+
21+
output "vpc_private_subnet_ids" {
22+
description = "Private subnet IDs in the nonprod account VPC."
23+
value = module.vpc.private_subnet_ids
24+
}

workspaces/prod/main.tf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,21 @@ module "github_oidc" {
2525
# enabled_apis = var.gcp_enabled_apis
2626
# iam_bindings = var.gcp_iam_bindings
2727
# }
28+
29+
module "vpc" {
30+
source = "../../modules/aws/vpc"
31+
32+
name = "durianpy-prod"
33+
cidr_block = "10.20.0.0/16"
34+
availability_zones = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
35+
public_subnet_cidrs = [
36+
"10.20.0.0/20",
37+
"10.20.16.0/20",
38+
"10.20.32.0/20",
39+
]
40+
private_subnet_cidrs = [
41+
"10.20.48.0/20",
42+
"10.20.64.0/20",
43+
"10.20.80.0/20",
44+
]
45+
}

workspaces/prod/outputs.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,18 @@ output "budget_name" {
1717
description = "Name of the prod account cost budget."
1818
value = module.budget.budget_name
1919
}
20+
21+
output "vpc_id" {
22+
description = "ID of the prod account VPC."
23+
value = module.vpc.vpc_id
24+
}
25+
26+
output "vpc_public_subnet_ids" {
27+
description = "Public subnet IDs in the prod account VPC."
28+
value = module.vpc.public_subnet_ids
29+
}
30+
31+
output "vpc_private_subnet_ids" {
32+
description = "Private subnet IDs in the prod account VPC."
33+
value = module.vpc.private_subnet_ids
34+
}

workspaces/root/main.tf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,21 @@ module "identity_center" {
5555
module "amplify" {
5656
source = "./amplify"
5757
}
58+
59+
module "vpc" {
60+
source = "../../modules/aws/vpc"
61+
62+
name = "durianpy-root"
63+
cidr_block = "10.10.0.0/16"
64+
availability_zones = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
65+
public_subnet_cidrs = [
66+
"10.10.0.0/20",
67+
"10.10.16.0/20",
68+
"10.10.32.0/20",
69+
]
70+
private_subnet_cidrs = [
71+
"10.10.48.0/20",
72+
"10.10.64.0/20",
73+
"10.10.80.0/20",
74+
]
75+
}

workspaces/root/outputs.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,18 @@ output "amplify_app_ids" {
4747
description = "Map of Amplify app key to app ID."
4848
value = module.amplify.app_ids
4949
}
50+
51+
output "vpc_id" {
52+
description = "ID of the root account VPC."
53+
value = module.vpc.vpc_id
54+
}
55+
56+
output "vpc_public_subnet_ids" {
57+
description = "Public subnet IDs in the root account VPC."
58+
value = module.vpc.public_subnet_ids
59+
}
60+
61+
output "vpc_private_subnet_ids" {
62+
description = "Private subnet IDs in the root account VPC."
63+
value = module.vpc.private_subnet_ids
64+
}

workspaces/sandbox/main.tf

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,31 @@ module "github_oidc" {
2121
# attendee_id_end = var.attendee_id_end
2222
# workshop_group_name = var.workshop_group_name
2323
# }
24+
25+
module "vpc" {
26+
source = "../../modules/aws/vpc"
27+
28+
name = "durianpy-sandbox"
29+
cidr_block = "10.40.0.0/16"
30+
availability_zones = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
31+
public_subnet_cidrs = [
32+
"10.40.0.0/20",
33+
"10.40.16.0/20",
34+
"10.40.32.0/20",
35+
]
36+
private_subnet_cidrs = [
37+
"10.40.48.0/20",
38+
"10.40.64.0/20",
39+
"10.40.80.0/20",
40+
]
41+
}
42+
43+
module "on_prem_vpc" {
44+
source = "../../modules/aws/vpc"
45+
46+
name = "on-prem-vpc"
47+
cidr_block = "172.16.0.0/16"
48+
availability_zones = ["${var.aws_region}a", "${var.aws_region}b", "${var.aws_region}c"]
49+
public_subnet_cidrs = ["172.16.0.0/20", "172.16.16.0/20", "172.16.32.0/20"]
50+
private_subnet_cidrs = ["172.16.48.0/20", "172.16.64.0/20", "172.16.80.0/20"]
51+
}

0 commit comments

Comments
 (0)