diff --git a/README.md b/README.md
index 350fdcd..42bf14e 100644
--- a/README.md
+++ b/README.md
@@ -25,20 +25,31 @@ This project creates and manages resources within an AWS account for infrastruct
|------|------|
| [aws_athena_workgroup.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/athena_workgroup) | resource |
| [aws_cloudwatch_log_group.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
+| [aws_eip.infrastructure_nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_flow_log.infrastructure_vpc_flow_logs_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
| [aws_flow_log.infrastructure_vpc_flow_logs_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
| [aws_glue_catalog_database.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_database) | resource |
| [aws_glue_catalog_table.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/glue_catalog_table) | resource |
| [aws_iam_role.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.infrastructure_vpc_flow_logs_allow_cloudwatch_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
+| [aws_internet_gateway.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
| [aws_kms_alias.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
| [aws_kms_key.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
+| [aws_nat_gateway.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource |
+| [aws_route.infrustructure_public_internet_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
+| [aws_route.private_nat_gateway](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
+| [aws_route_table.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
+| [aws_route_table.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
+| [aws_route_table_association.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
+| [aws_route_table_association.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
| [aws_s3_bucket.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket_lifecycle_configuration.logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_lifecycle_configuration) | resource |
| [aws_s3_bucket_policy.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource |
| [aws_s3_bucket_public_access_block.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
| [aws_s3_bucket_versioning.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |
+| [aws_subnet.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
+| [aws_subnet.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
| [aws_vpc.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
@@ -63,6 +74,9 @@ This project creates and manages resources within an AWS account for infrastruct
| [infrastructure\_vpc\_flow\_logs\_s3\_with\_athena](#input\_infrastructure\_vpc\_flow\_logs\_s3\_with\_athena) | Enable VPC flow logs in infrastructure VPC to the S3 logs bucket. A compatible Glue table/database and Athena workgroup will also be created to allow querying the logs. | `bool` | n/a | yes |
| [infrastructure\_vpc\_flow\_logs\_traffic\_type](#input\_infrastructure\_vpc\_flow\_logs\_traffic\_type) | Infrastructure VPC flow logs traffic type | `string` | n/a | yes |
| [infrastructure\_vpc\_instance\_tenancy](#input\_infrastructure\_vpc\_instance\_tenancy) | Infrastructure VPC instance tenancy | `string` | n/a | yes |
+| [infrastructure\_vpc\_network\_availability\_zones](#input\_infrastructure\_vpc\_network\_availability\_zones) | A list of availability zone characters (eg. ["a", "b", "c"]) | `list(string)` | n/a | yes |
+| [infrastructure\_vpc\_network\_enable\_private](#input\_infrastructure\_vpc\_network\_enable\_private) | Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled) | `bool` | n/a | yes |
+| [infrastructure\_vpc\_network\_enable\_public](#input\_infrastructure\_vpc\_network\_enable\_public) | Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway | `bool` | n/a | yes |
| [project\_name](#input\_project\_name) | Project name to be used as a prefix for all resources | `string` | n/a | yes |
## Outputs
diff --git a/locals.tf b/locals.tf
index 41d4f13..bd5731a 100644
--- a/locals.tf
+++ b/locals.tf
@@ -25,6 +25,15 @@ locals {
infrastructure_vpc_instance_tenancy = var.infrastructure_vpc_instance_tenancy
infrastructure_vpc_enable_network_address_usage_metrics = var.infrastructure_vpc_enable_network_address_usage_metrics
infrastructure_vpc_assign_generated_ipv6_cidr_block = var.infrastructure_vpc_assign_generated_ipv6_cidr_block
+ infrastructure_vpc_network_enable_public = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_public
+ infrastructure_vpc_network_enable_private = local.infrastructure_vpc && var.infrastructure_vpc_network_enable_private
+ infrastructure_vpc_network_availability_zones = sort(var.infrastructure_vpc_network_availability_zones)
+ infrastructure_vpc_network_public_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 0)
+ infrastructure_vpc_network_public_cidr_prefix = basename(local.infrastructure_vpc_network_public_cidr)
+ infrastructure_vpc_network_public_cidr_newbits = 24 - local.infrastructure_vpc_network_public_cidr_prefix
+ infrastructure_vpc_network_private_cidr = cidrsubnet(local.infrastructure_vpc_cidr_block, 1, 1)
+ infrastructure_vpc_network_private_cidr_prefix = basename(local.infrastructure_vpc_network_private_cidr)
+ infrastructure_vpc_network_private_cidr_newbits = 24 - local.infrastructure_vpc_network_private_cidr_prefix
infrastructure_vpc_flow_logs_cloudwatch_logs = var.infrastructure_vpc_flow_logs_cloudwatch_logs && local.infrastructure_vpc
infrastructure_vpc_flow_logs_s3_with_athena = var.infrastructure_vpc_flow_logs_s3_with_athena && local.infrastructure_vpc
infrastructure_vpc_flow_logs_s3_key_prefix = trim(var.infrastructure_vpc_flow_logs_s3_key_prefix, "/")
diff --git a/variables.tf b/variables.tf
index cd214fc..ecc1141 100644
--- a/variables.tf
+++ b/variables.tf
@@ -87,3 +87,18 @@ variable "infrastructure_vpc_flow_logs_s3_key_prefix" {
description = "Flow Logs by default will go into the infrastructure S3 logs bucket. This is the key prefix used to isolate them from other logs"
type = string
}
+
+variable "infrastructure_vpc_network_enable_public" {
+ description = "Enable public networking on Infrastructure VPC. This will create subnets with a route to an Internet Gateway"
+ type = bool
+}
+
+variable "infrastructure_vpc_network_enable_private" {
+ description = "Enable private networking on Infrastructure VPC. This will create subnets with a route to a NAT Gateway (If Public networking has been enabled)"
+ type = bool
+}
+
+variable "infrastructure_vpc_network_availability_zones" {
+ description = "A list of availability zone characters (eg. [\"a\", \"b\", \"c\"])"
+ type = list(string)
+}
diff --git a/vpc-infrastructure-flow-logs-cloudwatch.tf b/vpc-infrastructure-flow-logs-cloudwatch.tf
index db2764d..23f0aef 100644
--- a/vpc-infrastructure-flow-logs-cloudwatch.tf
+++ b/vpc-infrastructure-flow-logs-cloudwatch.tf
@@ -19,7 +19,7 @@ resource "aws_iam_role" "infrastructure_vpc_flow_logs" {
resource "aws_iam_role_policy" "infrastructure_vpc_flow_logs_allow_cloudwatch_rw" {
count = local.infrastructure_vpc_flow_logs_cloudwatch_logs ? 1 : 0
- name = "${local.resource_prefix}-ecs-vpc-flow-logs-cloudwatch-logs-rw"
+ name = "${local.resource_prefix}-vpc-flow-logs-cloudwatch-logs-rw"
role = aws_iam_role.infrastructure_vpc_flow_logs[0].id
policy = templatefile("${path.root}/policies/cloudwatch-logs-rw.json.tpl", {})
}
diff --git a/vpc-infrastructure-network-private.tf b/vpc-infrastructure-network-private.tf
new file mode 100644
index 0000000..5863d50
--- /dev/null
+++ b/vpc-infrastructure-network-private.tf
@@ -0,0 +1,59 @@
+resource "aws_route_table" "infrastructure_private" {
+ count = local.infrastructure_vpc_network_enable_private ? 1 : 0
+
+ vpc_id = aws_vpc.infrastructure[0].id
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-private"
+ }
+}
+
+resource "aws_subnet" "infrastructure_private" {
+ for_each = local.infrastructure_vpc_network_enable_private ? local.infrastructure_vpc_network_availability_zones : []
+
+ vpc_id = aws_vpc.infrastructure[0].id
+ availability_zone = "${local.aws_region}-${each.value}"
+
+ cidr_block = cidrsubnet(
+ local.infrastructure_vpc_network_private_cidr,
+ local.infrastructure_vpc_network_private_cidr_newbits,
+ index(local.infrastructure_vpc_network_availability_zones, each.value)
+ )
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-private-${each.value}"
+ }
+}
+
+resource "aws_route_table_association" "infrastructure_private" {
+ for_each = local.infrastructure_vpc_network_enable_private ? local.infrastructure_vpc_network_availability_zones : []
+
+ subnet_id = aws_subnet.infrastructure_private[each.value].id
+ route_table_id = aws_route_table.infrastructure_private[0]
+}
+
+resource "aws_eip" "infrastructure_nat" {
+ count = local.infrastructure_vpc_network_enable_private && local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ domain = "vpc"
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-nat"
+ }
+}
+
+resource "aws_nat_gateway" "infrastructure" {
+ count = local.infrastructure_vpc_network_enable_private && local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ allocation_id = aws_eip.infrastructure_nat[0].id
+ subnet_id = aws_subnet.infrastructure_public[0].id
+ depends_on = [aws_internet_gateway.infrastructure_public]
+}
+
+resource "aws_route" "private_nat_gateway" {
+ count = local.infrastructure_vpc_network_enable_private && local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ route_table_id = aws_route_table.infrastructure_private[0]
+ destination_cidr_block = "0.0.0.0/0"
+ nat_gateway_id = aws_nat_gateway.infrastructure[0].id
+}
diff --git a/vpc-infrastructure-network-public.tf b/vpc-infrastructure-network-public.tf
new file mode 100644
index 0000000..506606c
--- /dev/null
+++ b/vpc-infrastructure-network-public.tf
@@ -0,0 +1,51 @@
+resource "aws_route_table" "infrastructure_public" {
+ count = local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ vpc_id = aws_vpc.infrastructure[0].id
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-public"
+ }
+}
+
+resource "aws_internet_gateway" "infrastructure_public" {
+ count = local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ vpc_id = aws_vpc.infrastructure[0].id
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-public"
+ }
+}
+
+resource "aws_route" "infrustructure_public_internet_gateway" {
+ count = local.infrastructure_vpc_network_enable_public ? 1 : 0
+
+ route_table_id = aws_route_table.infrastructure_public[0].id
+ destination_cidr_block = "0.0.0.0/0"
+ gateway_id = aws_internet_gateway.infrastructure_public[0].id
+}
+
+resource "aws_subnet" "infrastructure_public" {
+ for_each = local.infrastructure_vpc_network_enable_public ? local.infrastructure_vpc_network_availability_zones : []
+
+ vpc_id = aws_vpc.infrastructure[0].id
+ availability_zone = "${local.aws_region}-${each.value}"
+
+ cidr_block = cidrsubnet(
+ local.infrastructure_vpc_network_public_cidr,
+ local.infrastructure_vpc_network_public_cidr_newbits,
+ index(local.infrastructure_vpc_network_availability_zones, each.value)
+ )
+
+ tags = {
+ Name = "${local.resource_prefix}-infrastructure-public-${each.value}"
+ }
+}
+
+resource "aws_route_table_association" "infrastructure_public" {
+ for_each = local.infrastructure_vpc_network_enable_public ? local.infrastructure_vpc_network_availability_zones : []
+
+ subnet_id = aws_subnet.infrastructure_public[each.value].id
+ route_table_id = aws_route_table.infrastructure_public[0]
+}