I put this as a module, creates a VPC with 3 public and 3 private subnets, IGW, 1 Nat gateway for each private subnet, and a seperate routing table for each private subnet. It also creates a flowlog, and KMS key for encryption, otherwise it wouldn't pass security checks :)
Put code below as your module, and change the "source" line to whereever you put main.tf, inputs.tf and outputs.tf.
This was written around terraform version 1.3
#terraform plan ; terraform apply
module "vpc-3az-plus-secondary" {
source="../modules/platform/vpc-3az-secondary-cidr/"
EnvironmentName="whatever-you-need-dev-stage-or-prod"
VpcRegion="us-east-1"
VpcCIDR="22.125.106.0/24"
SecondaryVpcCIDR="100.64.0.0/20"
PublicSubnet1CIDR = "22.125.106.192/28"
PublicSubnet2CIDR = "22.125.106.208/28"
PublicSubnet3CIDR = "22.125.106.224/28"
PrivateSubnet1CIDR = "22.125.106.0/26"
PrivateSubnet2CIDR = "22.125.106.64/26"
PrivateSubnet3CIDR = "22.125.106.128/26"
SecondaryPrivateSubnet1CIDR = "100.64.0.0/23"
SecondaryPrivateSubnet2CIDR = "100.64.2.0/23"
SecondaryPrivateSubnet3CIDR = "100.64.4.0/23"
}
here are the files:
Main.tf:
data "aws_availability_zones" "AZ" { state = "available" } resource "random_uuid" ""bm2023 { } resource "aws_vpc" "main" { cidr_block = var.VpcCIDR tags = { Name = var.EnvironmentName } } resource "aws_default_security_group" "default" { vpc_id = aws_vpc.main.id } resource "aws_flow_log" "flowlogs" { iam_role_arn = aws_iam_role.vpcflowlogrole.arn log_destination = aws_cloudwatch_log_group.vpcflowloggroup.arn traffic_type = "ALL" vpc_id = aws_vpc.main.id } data "aws_caller_identity" "current" {} locals { account_id = data.aws_caller_identity.current.account_id } resource "aws_cloudwatch_log_group" "vpcflowloggroup" { name = "vpcflowlog-${var.EnvironmentName}-${random_uuid.bm2023.result}" retention_in_days = 14 depends_on = [ aws_kms_key.kmskey_cw_forloggroup] kms_key_id= aws_kms_key.kmskey_cw_forloggroup.arn } resource "aws_kms_key" "kmskey_cw_forloggroup" { description = "KMS key for ${var.EnvironmentName} cloudwatch log group" enable_key_rotation = true deletion_window_in_days = 10 tags = { Name = "${var.EnvironmentName}-cloudwatch-loggroup" } policy = <<EOF { "Id": "key-consolepolicy-3", "Version": "2012-10-17", "Statement": [ { "Sid": "Enable IAM User Permissions", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::${local.account_id}:root" }, "Action": "kms:*", "Resource": "*" }, { "Sid": "Enable Cloud watch log group access", "Effect": "Allow", "Principal": { "Service": "logs.${var.vpcRegion}.amazonaws.com" }, "Action": [ "kms:Encrypt*", "kms:Decrypt*", "kms:ReEncrypt*", "kms:GenerateDataKey*", "kms:Describe*" ], "Resource": "*", "Condition": { "ArnEquals": { "kms:EncryptionContext:aws:logs:arn": "arn:aws:logs:${var.vpcRegion}:${local.account_id}:log-group:*" } } } ] } EOF } resource "aws_iam_role" "vpcflowlogrole" { name = "vpcflowlogrole-${var.EnvironmentName}" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "vpc-flow-logs.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF } resource "aws_iam_role_policy" "vpcflowlogrolepolicy" { name = "vpcflowlogrole-${var.EnvironmentName}" role = aws_iam_role.vpcflowlogrole.id policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Effect": "Allow", "Resource": "${aws_cloudwatch_log_group.vpcflowloggroup.arn}" } ] } EOF } resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.main.id tags = { Name = var.EnvironmentName } } resource "aws_subnet" "PublicSubnet1" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,0) map_public_ip_on_launch = false cidr_block = var.PublicSubnet1CIDR tags = { Name = "${var.EnvironmentName} Public Subnet (AZ1)" subnet_type = "public" } } resource "aws_subnet" "PublicSubnet2" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,1) map_public_ip_on_launch = false cidr_block = var.PublicSubnet2CIDR tags = { Name = "${var.EnvironmentName} Public Subnet (AZ2)" subnet_type = "public" } } resource "aws_subnet" "PublicSubnet3" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,2) map_public_ip_on_launch = false cidr_block = var.PublicSubnet3CIDR tags = { Name = "${var.EnvironmentName} Public Subnet (AZ3)" subnet_type = "public" } } resource "aws_subnet" "PrivateSubnet1" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,0) cidr_block = var.PrivateSubnet1CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ1)" subnet_type = "private" } } resource "aws_subnet" "PrivateSubnet2" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,1) cidr_block = var.PrivateSubnet2CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ2)" subnet_type = "private" } } resource "aws_subnet" "PrivateSubnet3" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,2) cidr_block = var.PrivateSubnet3CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ3)" subnet_type = "private" } } resource "aws_vpc_ipv4_cidr_block_association" "secondary_cidr" { vpc_id = aws_vpc.main.id cidr_block = var.SecondaryVpcCIDR } resource "aws_subnet" "SecondaryPrivateSubnet1" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,0) cidr_block = var.SecondaryPrivateSubnet1CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ1) Secondary" } } resource "aws_subnet" "SecondaryPrivateSubnet2" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,1) cidr_block = var.SecondaryPrivateSubnet2CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ2) Secondary" } } resource "aws_subnet" "SecondaryPrivateSubnet3" { vpc_id = aws_vpc.main.id availability_zone = element(data.aws_availability_zones.AZ.names,2) cidr_block = var.SecondaryPrivateSubnet3CIDR tags = { Name = "${var.EnvironmentName} Private Subnet (AZ3) Secondary" } } resource "aws_eip" "NatGateway1EIP" { vpc = true depends_on = [aws_internet_gateway.igw] } resource "aws_eip" "NatGateway2EIP" { vpc = true depends_on = [aws_internet_gateway.igw] } resource "aws_eip" "NatGateway3EIP" { vpc = true depends_on = [aws_internet_gateway.igw] } resource "aws_nat_gateway" "NatGateway1" { allocation_id = aws_eip.NatGateway1EIP.id subnet_id = aws_subnet.PublicSubnet1.id depends_on = [aws_internet_gateway.igw] tags = { Name = var.EnvironmentName } } resource "aws_nat_gateway" "NatGateway2" { allocation_id = aws_eip.NatGateway2EIP.id subnet_id = aws_subnet.PublicSubnet2.id depends_on = [aws_internet_gateway.igw] tags = { Name = var.EnvironmentName } } resource "aws_nat_gateway" "NatGateway3" { allocation_id = aws_eip.NatGateway3EIP.id subnet_id = aws_subnet.PublicSubnet3.id depends_on = [aws_internet_gateway.igw] tags = { Name = var.EnvironmentName } } resource "aws_route_table" "PublicRouteTable" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Public Routes" } } resource "aws_route_table" "PrivateRouteTable1" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ1)" } } resource "aws_route_table" "PrivateRouteTable2" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ2)" } } resource "aws_route_table" "PrivateRouteTable3" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ3)" } } resource "aws_route_table" "SecondaryPrivateRouteTable1" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ1)" } } resource "aws_route_table" "SecondaryPrivateRouteTable2" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ2)" } } resource "aws_route_table" "SecondaryPrivateRouteTable3" { vpc_id = aws_vpc.main.id tags = { Name = "${var.EnvironmentName} Private Routes (AZ3)" } } resource "aws_route" "DefaultPublicRoute" { route_table_id = aws_route_table.PublicRouteTable.id destination_cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id depends_on = [aws_internet_gateway.igw] } resource "aws_route_table_association" "PublicSubnet1RouteTableAssociation" { route_table_id = aws_route_table.PublicRouteTable.id subnet_id = aws_subnet.PublicSubnet1.id } resource "aws_route_table_association" "PublicSubnet2RouteTableAssociation" { route_table_id = aws_route_table.PublicRouteTable.id subnet_id = aws_subnet.PublicSubnet2.id } resource "aws_route_table_association" "PublicSubnet3RouteTableAssociation" { route_table_id = aws_route_table.PublicRouteTable.id subnet_id = aws_subnet.PublicSubnet3.id } resource "aws_route" "DefaultPrivateRoute1" { route_table_id = aws_route_table.PrivateRouteTable1.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway1.id } resource "aws_route" "DefaultPrivateRoute2" { route_table_id = aws_route_table.PrivateRouteTable2.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway2.id } resource "aws_route" "DefaultPrivateRoute3" { route_table_id = aws_route_table.PrivateRouteTable3.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway3.id } resource "aws_route" "SecondaryDefaultPrivateRoute1" { route_table_id = aws_route_table.SecondaryPrivateRouteTable1.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway1.id } resource "aws_route" "SecondaryDefaultPrivateRoute2" { route_table_id = aws_route_table.SecondaryPrivateRouteTable2.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway2.id } resource "aws_route" "SecondaryDefaultPrivateRoute3" { route_table_id = aws_route_table.SecondaryPrivateRouteTable3.id destination_cidr_block = "0.0.0.0/0" nat_gateway_id = aws_nat_gateway.NatGateway3.id } resource "aws_route_table_association" "PrivateSubnet1RouteTableAssociation" { route_table_id = aws_route_table.PrivateRouteTable1.id subnet_id = aws_subnet.PrivateSubnet1.id } resource "aws_route_table_association" "PrivateSubnet2RouteTableAssociation" { route_table_id = aws_route_table.PrivateRouteTable2.id subnet_id = aws_subnet.PrivateSubnet2.id } resource "aws_route_table_association" "PrivateSubnet3RouteTableAssociation" { route_table_id = aws_route_table.PrivateRouteTable3.id subnet_id = aws_subnet.PrivateSubnet3.id } resource "aws_route_table_association" "SecondaryPrivateSubnet1RouteTableAssociation" { route_table_id = aws_route_table.SecondaryPrivateRouteTable1.id subnet_id = aws_subnet.SecondaryPrivateSubnet1.id } resource "aws_route_table_association" "SecondaryPrivateSubnet2RouteTableAssociation" { route_table_id = aws_route_table.SecondaryPrivateRouteTable2.id subnet_id = aws_subnet.SecondaryPrivateSubnet2.id } resource "aws_route_table_association" "SecondaryPrivateSubnet3RouteTableAssociation" { route_table_id = aws_route_table.SecondaryPrivateRouteTable3.id subnet_id = aws_subnet.SecondaryPrivateSubnet3.id }
Outputs.tf:
output "EnvironmentName" { value = var.EnvironmentName } output "vpcId" { value = aws_vpc.main.id } output "vpc_cidr" { value = var.VpcCIDR } output "aws_cloudwatch_log_group" { value = aws_cloudwatch_log_group.vpcflowloggroup } output "kms_key" { value = aws_kms_key.kmskey_cw_forloggroup } output "aws_flow_log" { value = aws_flow_log.flowlogs } output "Secondary_vpc_cidr" { value = var.SecondaryVpcCIDR } output "PublicSubnet1" { value = aws_subnet.PublicSubnet1.id } output "PublicSubnet2" { value = aws_subnet.PublicSubnet2.id } output "PublicSubnet3" { value = aws_subnet.PublicSubnet3.id } output "public_subnet_route_table_id" { value = aws_route_table.PublicRouteTable.id } output "PrivateSubnet1" { value = aws_subnet.PrivateSubnet1.id } output "private_subnet1_route_table_id" { value = aws_route_table.PrivateRouteTable1.id } output "NatGatewayip_public_cidr1" { value = aws_nat_gateway.NatGateway1.id } output "PrivateSubnet2" { value = aws_subnet.PrivateSubnet2.id } output "private_subnet2_route_table_id" { value = aws_route_table.PrivateRouteTable2.id } output "NatGatewayip_public_cidr2" { value = aws_nat_gateway.NatGateway2.id } output "PrivateSubnet3" { value = aws_subnet.PrivateSubnet3.id } output "private_subnet3_route_table_id" { value = aws_route_table.PrivateRouteTable3.id } output "NatGatewayip_public_cidr3" { value = aws_nat_gateway.NatGateway3.id } output "SecondaryPrivateSubnet1" { value = aws_subnet.SecondaryPrivateSubnet1.id } output "SecondaryPrivateSubnet2" { value = aws_subnet.SecondaryPrivateSubnet2.id } output "SecondaryPrivateSubnet3" { value = aws_subnet.SecondaryPrivateSubnet3.id }
*** This assumes you have a pipeline, that has something along the following in the git/repo directory for that pipeline:terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } } } provider "aws" { region = "us-east-1" # Role in remote account: assume_role { role_arn = "arn:aws:iam::00000000000:role/yourrole-terraform-automation" } default_tags { tags = { automation_provider = "codepipeline" automation_account_number = "11111111111111" automation_account_name = "Deployment-Acct" automation_github_url = "https://github.com/tree/terraform/" automation_github_env = "11111111111111-us-east-1" automation_pipeline = "11111111111111-us-east-1" automation_region = "us-east-1" department = "Cloud DevOPS" } } }