Skip to content

Commit

Permalink
adding support for VPC module v3.x and ANFW module
Browse files Browse the repository at this point in the history
  • Loading branch information
pablo19sc committed Oct 27, 2022
1 parent c8e954a commit 1fe30a1
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 168 deletions.
5 changes: 2 additions & 3 deletions .header.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AWS Hub and Spoke Architecture with an Inspection VPC - Terraform Sample

This repository contains terraform code to deploy a sample AWS Hub and Spoke architecture with an Inspection VPC using AWS Network Firewall. The resources deployed and the architectural pattern they follow is purely for demonstration/testing purposes.
This repository contains terraform code to deploy a sample AWS Hub and Spoke architecture with an Inspection VPC using AWS Network Firewall. The resources deployed and the architectural pattern they follow is purely for demonstration/testing purposes.

## Prerequisites
- An AWS account with an IAM user with the appropriate permissions
Expand All @@ -15,8 +15,7 @@ This repository contains terraform code to deploy a sample AWS Hub and Spoke arc

The variables.tf file contains the variables that are used to configure the Terraform code.

**** Note **** If the ec2_multi_subnet variable is set to true, an EC2 compute instance will be deployed into every Spoke Private subnet, with 2 x Spokes and 3 x Availablity Zones this means 6 EC2 instances. **Please** leave as false to avoid costs unless you are happy to deploy more instances and accept additional costs.
VPC endpoints (for SSM connection) and AWS Network Firewall endpoints will be deployed in all the Availability Zones you indicate in the *vpcs* variable.
**Note** EC2 instances, VPC endpoints, and AWS Network Firewall endpoints will be deployed in all the Availability Zones configured for each VPC. Keep this in mind when testing this environment from a cost perspective - for production environments, we recommend the use of at least 2 AZs for high-availability.

## Deployment

Expand Down
23 changes: 11 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!-- BEGIN_TF_DOCS -->
# AWS Hub and Spoke Architecture with an Inspection VPC - Terraform Sample

This repository contains terraform code to deploy a sample AWS Hub and Spoke architecture with an Inspection VPC using AWS Network Firewall. The resources deployed and the architectural pattern they follow is purely for demonstration/testing purposes.
This repository contains terraform code to deploy a sample AWS Hub and Spoke architecture with an Inspection VPC using AWS Network Firewall. The resources deployed and the architectural pattern they follow is purely for demonstration/testing purposes.

## Prerequisites
- An AWS account with an IAM user with the appropriate permissions
Expand All @@ -16,8 +16,7 @@ This repository contains terraform code to deploy a sample AWS Hub and Spoke arc

The variables.tf file contains the variables that are used to configure the Terraform code.

**** Note **** If the ec2\_multi\_subnet variable is set to true, an EC2 compute instance will be deployed into every Spoke Private subnet, with 2 x Spokes and 3 x Availablity Zones this means 6 EC2 instances. **Please** leave as false to avoid costs unless you are happy to deploy more instances and accept additional costs.
VPC endpoints (for SSM connection) and AWS Network Firewall endpoints will be deployed in all the Availability Zones you indicate in the *vpcs* variable.
**Note** EC2 instances, VPC endpoints, and AWS Network Firewall endpoints will be deployed in all the Availability Zones configured for each VPC. Keep this in mind when testing this environment from a cost perspective - for production environments, we recommend the use of at least 2 AZs for high-availability.

## Deployment

Expand Down Expand Up @@ -62,31 +61,33 @@ This library is licensed under the MIT-0 License. See the [LICENSE](https://gith

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | ~> 1.1.2 |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.73.0 |
| <a name="requirement_awscc"></a> [awscc](#requirement\_awscc) | >= 0.15.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 4.19.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 4.36.1 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_aws_network_firewall"></a> [aws\_network\_firewall](#module\_aws\_network\_firewall) | ./modules/network_firewall | n/a |
| <a name="module_aws_network_firewall"></a> [aws\_network\_firewall](#module\_aws\_network\_firewall) | aws-ia/networkfirewall/aws | 0.0.2 |
| <a name="module_compute"></a> [compute](#module\_compute) | ./modules/compute | n/a |
| <a name="module_iam_kms"></a> [iam\_kms](#module\_iam\_kms) | ./modules/iam_kms | n/a |
| <a name="module_inspection_vpc"></a> [inspection\_vpc](#module\_inspection\_vpc) | aws-ia/vpc/aws | = 1.4.1 |
| <a name="module_spoke_vpcs"></a> [spoke\_vpcs](#module\_spoke\_vpcs) | aws-ia/vpc/aws | = 1.4.1 |
| <a name="module_inspection_vpc"></a> [inspection\_vpc](#module\_inspection\_vpc) | aws-ia/vpc/aws | = 3.0.1 |
| <a name="module_spoke_vpcs"></a> [spoke\_vpcs](#module\_spoke\_vpcs) | aws-ia/vpc/aws | = 3.0.1 |
| <a name="module_vpc_endpoints"></a> [vpc\_endpoints](#module\_vpc\_endpoints) | ./modules/endpoints | n/a |

## Resources

| Name | Type |
|------|------|
| [aws_ec2_managed_prefix_list.prefix_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_managed_prefix_list) | resource |
| [aws_ec2_managed_prefix_list_entry.pl_entry](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_managed_prefix_list_entry) | resource |
| [aws_ec2_transit_gateway.tgw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway) | resource |
| [aws_ec2_transit_gateway_route.default_route_spoke_to_inspection](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource |
| [aws_ec2_transit_gateway_route_table.post_inspection_vpc_route_table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table) | resource |
Expand All @@ -103,12 +104,10 @@ This library is licensed under the MIT-0 License. See the [LICENSE](https://gith

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_ec2_multi_subnet"></a> [ec2\_multi\_subnet](#input\_ec2\_multi\_subnet) | Multi subnet Instance Deployment. | `bool` | `true` | no |
| <a name="input_inspection_vpc"></a> [inspection\_vpc](#input\_inspection\_vpc) | Inspection VPC definition. | `any` | <pre>{<br> "cidr_block": "10.129.0.0/24",<br> "flow_log_config": {<br> "log_destination_type": "cloud-watch-logs",<br> "retention_in_days": 7<br> },<br> "number_azs": 2,<br> "private_subnet_netmask": 28,<br> "public_subnet_netmask": 28,<br> "tgw_subnet_netmask": 28<br>}</pre> | no |
| <a name="input_project_name"></a> [project\_name](#input\_project\_name) | Name of the project. | `string` | `"aws-hub-and-spoke-demo"` | no |
| <a name="input_region"></a> [region](#input\_region) | AWS Region. | `string` | `"us-east-1"` | no |
| <a name="input_spoke_vpcs"></a> [spoke\_vpcs](#input\_spoke\_vpcs) | Spoke VPCs definition. | `any` | <pre>{<br> "spoke-vpc-1": {<br> "cidr_block": "10.0.0.0/16",<br> "flow_log_config": {<br> "log_destination_type": "cloud-watch-logs",<br> "retention_in_days": 7<br> },<br> "instance_type": "t2.micro",<br> "number_azs": 2,<br> "private_subnet_netmask": 28,<br> "tgw_subnet_netmask": 28<br> },<br> "spoke-vpc-2": {<br> "cidr_block": "10.1.0.0/16",<br> "flow_log_config": {<br> "log_destination_type": "cloud-watch-logs",<br> "retention_in_days": 7<br> },<br> "instance_type": "t2.micro",<br> "number_azs": 2,<br> "private_subnet_netmask": 24,<br> "tgw_subnet_netmask": 28<br> }<br>}</pre> | no |
| <a name="input_supernet"></a> [supernet](#input\_supernet) | Hub and Spoke Supernet. | `string` | `"10.0.0.0/8"` | no |
| <a name="input_region"></a> [region](#input\_region) | AWS Region. | `string` | `"eu-west-1"` | no |
| <a name="input_spoke_vpcs"></a> [spoke\_vpcs](#input\_spoke\_vpcs) | Spoke VPCs definition. | `any` | <pre>{<br> "spoke-vpc-1": {<br> "cidr_block": "10.0.0.0/24",<br> "endpoint_subnet_netmask": 28,<br> "flow_log_config": {<br> "log_destination_type": "cloud-watch-logs",<br> "retention_in_days": 7<br> },<br> "instance_type": "t2.micro",<br> "number_azs": 2,<br> "tgw_subnet_netmask": 28,<br> "workload_subnet_netmask": 28<br> },<br> "spoke-vpc-2": {<br> "cidr_block": "10.0.1.0/24",<br> "endpoint_subnet_netmask": 28,<br> "flow_log_config": {<br> "log_destination_type": "cloud-watch-logs",<br> "retention_in_days": 7<br> },<br> "instance_type": "t2.micro",<br> "number_azs": 2,<br> "tgw_subnet_netmask": 28,<br> "workload_subnet_netmask": 28<br> }<br>}</pre> | no |

## Outputs

Expand Down
111 changes: 66 additions & 45 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,33 @@
SPDX-License-Identifier: MIT-0 */

/* The VPC module will deploy a VPC for each resoruce defined in the variables.tf file defined as a spoke
Additional resources such as NAT Gateways will be deploeyed according to the value set in the variables file */
Additional resources such as NAT Gateways will be deployed according to the value set in the variables file */

# Inspection VPC. Module - https://github.com/aws-ia/terraform-aws-vpc
# Inspection VPC. Module - https://registry.terraform.io/modules/aws-ia/vpc/aws/latest
module "inspection_vpc" {
source = "aws-ia/vpc/aws"
version = "= 1.4.1"
version = "= 3.0.1"

name = "inspection-vpc"
cidr_block = var.inspection_vpc.cidr_block
az_count = var.inspection_vpc.number_azs

transit_gateway_id = aws_ec2_transit_gateway.tgw.id
transit_gateway_routes = {
inspection = aws_ec2_managed_prefix_list.prefix_list.id
}

subnets = {
public = {
name_prefix = "public"
netmask = var.inspection_vpc.public_subnet_netmask
nat_gateway_configuration = "all_azs"
}

private = {
name_prefix = "inspection"
netmask = var.inspection_vpc.private_subnet_netmask
route_to_nat = true
route_to_transit_gateway = [var.supernet]
inspection = {
netmask = var.inspection_vpc.private_subnet_netmask
connect_to_public_natgw = true
}
transit_gateway = {
name_prefix = "tgw"
netmask = var.inspection_vpc.tgw_subnet_netmask
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
transit_gateway_appliance_mode_support = "enable"
Expand All @@ -44,27 +43,26 @@ module "inspection_vpc" {
}
}

# Spoke VPCs. Module - https://github.com/aws-ia/terraform-aws-vpc
# Spoke VPCs. Module - https://registry.terraform.io/modules/aws-ia/vpc/aws/latest
module "spoke_vpcs" {
for_each = var.spoke_vpcs
source = "aws-ia/vpc/aws"
version = "= 1.4.1"
version = "= 3.0.1"

name = each.key
cidr_block = each.value.cidr_block
az_count = each.value.number_azs

transit_gateway_id = aws_ec2_transit_gateway.tgw.id
transit_gateway_routes = {
workload = "0.0.0.0/0"
}

subnets = {
private = {
name_prefix = "private"
netmask = each.value.private_subnet_netmask
route_to_nat = false
route_to_transit_gateway = ["0.0.0.0/0"]
}
workload = { netmask = each.value.workload_subnet_netmask }
endpoints = { netmask = each.value.endpoint_subnet_netmask }
transit_gateway = {
name_prefix = "tgw"
netmask = each.value.tgw_subnet_netmask
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
}
Expand All @@ -89,6 +87,22 @@ resource "aws_ec2_transit_gateway" "tgw" {
}
}

# MANAGED PREFIX LIST (with the Spoke VPCs CIDRs)
# Managed Prefix List resource
resource "aws_ec2_managed_prefix_list" "prefix_list" {
name = "Spoke VPCs"
address_family = "IPv4"
max_entries = length(var.spoke_vpcs)
}

resource "aws_ec2_managed_prefix_list_entry" "pl_entry" {
for_each = var.spoke_vpcs

cidr = each.value.cidr_block
description = each.key
prefix_list_id = aws_ec2_managed_prefix_list.prefix_list.id
}

# TRANSIT GATEWAY ROUTING
# Spoke Transit Gateway Route Table
resource "aws_ec2_transit_gateway_route_table" "spoke_vpc_route_table" {
Expand Down Expand Up @@ -137,6 +151,27 @@ resource "aws_ec2_transit_gateway_route" "default_route_spoke_to_inspection" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.spoke_vpc_route_table.id
}

# AWS Network Firewall module - https://registry.terraform.io/modules/aws-ia/networkfirewall/aws/latest
module "aws_network_firewall" {
source = "aws-ia/networkfirewall/aws"
version = "0.0.2"

network_firewall_name = "anfw-${var.project_name}"
network_firewall_policy = aws_networkfirewall_firewall_policy.anfw_policy.arn

number_azs = var.inspection_vpc.number_azs
vpc_id = module.inspection_vpc.vpc_attributes.id
vpc_subnets = { for k, v in module.inspection_vpc.private_subnet_attributes_by_az : split("/", k)[1] => v.id if split("/", k)[0] == "inspection" }

routing_configuration = {
centralized_inspection_with_egress = {
tgw_subnet_route_tables = { for k, v in module.inspection_vpc.rt_attributes_by_type_by_az.transit_gateway : k => v.id }
public_subnet_route_tables = { for k, v in module.inspection_vpc.rt_attributes_by_type_by_az.public : k => v.id }
network_cidr_blocks = values({ for k, v in var.spoke_vpcs : k => v.cidr_block })
}
}
}

# The VPC Endpoint module deploys the necessary AWS VPC Endpoints to allow SSM (information of the endpoints to create in locals.tf)
# VPC Endpoints are only deployed into Spoke VPCs
module "vpc_endpoints" {
Expand All @@ -146,20 +181,11 @@ module "vpc_endpoints" {
project_name = var.project_name
vpc_name = each.key
vpc_id = each.value.vpc_attributes.id
vpc_subnets = values({ for k, v in each.value.private_subnet_attributes_by_az : k => v.id })
vpc_subnets = values({ for k, v in each.value.private_subnet_attributes_by_az : split("/", k)[1] => v.id if split("/", k)[0] == "endpoints" })
endpoints_security_group = local.security_groups.endpoints
endpoints_service_names = local.endpoint_service_names
}


# The IAM role creates the nessesary policies for the VPC Flow logs and the EC2 instance
module "iam_kms" {
source = "./modules/iam_kms"

project_name = var.project_name
aws_region = var.region
}

# The Compute module deployes EC2 instances into Spoke VPCs only, the number of instances are defined in variables.tf
module "compute" {
for_each = module.spoke_vpcs
Expand All @@ -168,22 +194,17 @@ module "compute" {
project_name = var.project_name
vpc_name = each.key
vpc_id = each.value.vpc_attributes.id
vpc_subnets = var.ec2_multi_subnet ? values({ for k, v in each.value.private_subnet_attributes_by_az : k => v.id }) : slice(values({ for k, v in each.value.private_subnet_attributes_by_az : k => v.id }), 0, 1)
number_azs = var.ec2_multi_subnet ? var.spoke_vpcs[each.key].number_azs : 1
vpc_subnets = values({ for k, v in each.value.private_subnet_attributes_by_az : split("/", k)[1] => v.id if split("/", k)[0] == "workload" })
number_azs = var.spoke_vpcs[each.key].number_azs
instance_type = var.spoke_vpcs[each.key].instance_type
ec2_iam_instance_profile = module.iam_kms.ec2_iam_instance_profile
ec2_security_group = local.security_groups.instance
}

/* Module to the AWS Network Firewall
The ANFW policy is defined in the policy.tf file in the aws_network_firewall module directory */
module "aws_network_firewall" {
source = "./modules/network_firewall"

project_name = var.project_name
vpc_name = "inspection-vpc"
vpc_info = module.inspection_vpc
policy_document = aws_networkfirewall_firewall_policy.anfw_policy.arn
supernet = var.supernet
number_azs = var.inspection_vpc.number_azs
# The IAM role creates the nessesary policies for the VPC Flow logs and the EC2 instance
module "iam_kms" {
source = "./modules/iam_kms"

project_name = var.project_name
aws_region = var.region
}
42 changes: 0 additions & 42 deletions modules/network_firewall/main.tf

This file was deleted.

7 changes: 0 additions & 7 deletions modules/network_firewall/outputs.tf

This file was deleted.

32 changes: 0 additions & 32 deletions modules/network_firewall/variables.tf

This file was deleted.

2 changes: 1 addition & 1 deletion outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ output "instances" {

output "network_firewall" {
description = "AWS Network Firewall ID."
value = module.aws_network_firewall.anfw.id
value = module.aws_network_firewall.aws_network_firewall.id
}
2 changes: 1 addition & 1 deletion policy.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ resource "aws_networkfirewall_rule_group" "allow_icmp" {
ip_sets {
key = "SUPERNET"
ip_set {
definition = [var.supernet]
definition = ["10.0.0.0/8"]
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
SPDX-License-Identifier: MIT-0 */

terraform {
required_version = ">= 0.15.3"
experiments = [module_variable_optional_attrs]
required_version = ">= 1.3.0"
required_providers {
aws = {
source = "hashicorp/aws"
Expand Down
Loading

0 comments on commit 1fe30a1

Please sign in to comment.