From 794161d647201d6c0b1087aa18d2631566642b14 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 11:51:28 -0800 Subject: [PATCH 01/22] staging network WIP --- infra/api/database/main.tf | 18 ++--- infra/api/service/main.tf | 8 ++- infra/frontend/service/main.tf | 8 ++- infra/modules/network/main.tf | 32 +++++++++ infra/modules/network/variables.tf | 31 +++++++++ infra/modules/network/vpc-endpoints.tf | 92 ++++++++++++++++++++++++++ infra/networks/main.tf | 11 --- infra/networks/staging.s3.tfbackend | 4 ++ infra/networks/subnet-backfill.tf | 92 -------------------------- 9 files changed, 179 insertions(+), 117 deletions(-) create mode 100644 infra/modules/network/main.tf create mode 100644 infra/modules/network/variables.tf create mode 100644 infra/modules/network/vpc-endpoints.tf create mode 100644 infra/networks/staging.s3.tfbackend delete mode 100644 infra/networks/subnet-backfill.tf diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index 3f671c26a..eabe718bf 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -1,17 +1,19 @@ -# TODO(https://github.com/navapbc/template-infra/issues/152) use non-default VPC -data "aws_vpc" "default" { - default = true +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc +data "aws_vpc" "network" { + filter { + name = "tag:Name" + values = [var.environment_name] + } } -# TODO(https://github.com/navapbc/template-infra/issues/152) use private subnets -data "aws_subnets" "default" { +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet +data "aws_subnets" "database" { filter { - name = "default-for-az" - values = [true] + name = "tag:subnet_type" + values = ["database"] } } - locals { # The prefix key/value pair is used for Terraform Workspaces, which is useful for projects with multiple infrastructure developers. # By default, Terraform creates a workspace named “default.” If a non-default workspace is not created this prefix will equal “default”, diff --git a/infra/api/service/main.tf b/infra/api/service/main.tf index b12ffce8b..ccc14ba0e 100644 --- a/infra/api/service/main.tf +++ b/infra/api/service/main.tf @@ -1,7 +1,9 @@ -# TODO(https://github.com/navapbc/template-infra/issues/152) use non-default VPC # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc -data "aws_vpc" "default" { - default = true +data "aws_vpc" "network" { + filter { + name = "tag:Name" + values = [var.environment_name] + } } # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet diff --git a/infra/frontend/service/main.tf b/infra/frontend/service/main.tf index 2b12724bf..ed7669e4d 100644 --- a/infra/frontend/service/main.tf +++ b/infra/frontend/service/main.tf @@ -1,7 +1,9 @@ -# TODO(https://github.com/navapbc/template-infra/issues/152) use non-default VPC # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc -data "aws_vpc" "default" { - default = true +data "aws_vpc" "network" { + filter { + name = "tag:Name" + values = [var.environment_name] + } } # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet diff --git a/infra/modules/network/main.tf b/infra/modules/network/main.tf new file mode 100644 index 000000000..9def582e4 --- /dev/null +++ b/infra/modules/network/main.tf @@ -0,0 +1,32 @@ +data "aws_availability_zones" "available" {} + +locals { + vpc_cidr = "10.${var.cidr_second_octet}.0.0/20" + num_availability_zones = 3 + availability_zones = slice(data.aws_availability_zones.available.names, 0, local.num_availability_zones) +} + +module "aws_vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "5.2.0" + + name = var.name + azs = local.availability_zones + cidr = local.vpc_cidr + + public_subnets = ["10.${var.cidr_second_octet}.10.0/24", "10.${var.cidr_second_octet}.11.0/24", "10.${var.cidr_second_octet}.12.0/24"] + private_subnets = ["10.${var.cidr_second_octet}.0.0/24", "10.${var.cidr_second_octet}.1.0/24", "10.${var.cidr_second_octet}.2.0/24"] + database_subnets = ["10.${var.cidr_second_octet}.5.0/24", "10.${var.cidr_second_octet}.6.0/24", "10.${var.cidr_second_octet}.7.0/24"] + public_subnet_tags = { subnet_type = "public" } + private_subnet_tags = { subnet_type = "private" } + database_subnet_tags = { subnet_type = "database" } + database_subnet_group_name = var.database_subnet_group_name + + # If application needs external services, then create one NAT gateway per availability zone + enable_nat_gateway = var.has_external_non_aws_service + single_nat_gateway = false + one_nat_gateway_per_az = var.has_external_non_aws_service + + enable_dns_hostnames = true + enable_dns_support = true +} diff --git a/infra/modules/network/variables.tf b/infra/modules/network/variables.tf new file mode 100644 index 000000000..e0637408f --- /dev/null +++ b/infra/modules/network/variables.tf @@ -0,0 +1,31 @@ +variable "name" { + type = string + description = "Name to give the VPC. Will be added to the VPC under the 'network_name' tag." +} + +variable "cidr_second_octet" { + type = string + description = "For a given example CIDR of 10.x.0.0/16, this variable would be 'x'." +} + +variable "aws_services_security_group_name_prefix" { + type = string + description = "Prefix for the name of the security group attached to VPC endpoints" +} + +variable "database_subnet_group_name" { + type = string + description = "Name of the database subnet group" +} + +variable "has_database" { + type = bool + description = "Whether the application(s) in this network have a database. Determines whether to create VPC endpoints needed by the database layer." + default = false +} + +variable "has_external_non_aws_service" { + type = bool + description = "Whether the application(s) in this network need to call external non-AWS services. Determines whether or not to create NAT gateways." + default = false +} diff --git a/infra/modules/network/vpc-endpoints.tf b/infra/modules/network/vpc-endpoints.tf new file mode 100644 index 000000000..701d57d37 --- /dev/null +++ b/infra/modules/network/vpc-endpoints.tf @@ -0,0 +1,92 @@ +locals { + # List of AWS services used by this VPC + # This list is used to create VPC endpoints so that the AWS services can + # be accessed without network traffic ever leaving the VPC's private network + # For a list of AWS services that integrate with AWS PrivateLink + # see https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.html + # + # The database module requires VPC access from private networks to SSM, KMS, and RDS + aws_service_integrations = setunion( + # AWS services used by ECS Fargate: ECR to fetch images, S3 for image layers, and CloudWatch for logs + ["ecr.api", "ecr.dkr", "s3", "logs"], + + # Feature flags with AWS Evidently + ["evidently", "evidently-dataplane"], + + # AWS services used by the database's role manager + var.has_database ? ["ssm", "kms", "secretsmanager"] : [], + ) + + # S3 and DynamoDB use Gateway VPC endpoints. All other services use Interface VPC endpoints + interface_vpc_endpoints = toset([for aws_service in local.aws_service_integrations : aws_service if !contains(["s3", "dynamodb"], aws_service)]) + gateway_vpc_endpoints = toset([for aws_service in local.aws_service_integrations : aws_service if contains(["s3", "dynamodb"], aws_service)]) +} + +data "aws_region" "current" {} + +# VPC Endpoints for accessing AWS Services +# ---------------------------------------- +# +# Since the role manager Lambda function is in the VPC (which is needed to be +# able to access the database) we need to allow the Lambda function to access +# AWS Systems Manager Parameter Store (to fetch the database password) and +# KMS (to decrypt SecureString parameters from Parameter Store). We can do +# this by either allowing internet access to the Lambda, or by using a VPC +# endpoint. The latter is more secure. +# See https://repost.aws/knowledge-center/lambda-vpc-parameter-store +# See https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint + +data "aws_subnet" "private" { + count = length(module.aws_vpc.private_subnets) + id = module.aws_vpc.private_subnets[count.index] +} + +# AWS services may only be available in certain regions and availability zones, +# so we use this data source to get that information and only create +# VPC endpoints in the regions / availability zones where the particular service +# is available. +data "aws_vpc_endpoint_service" "aws_service" { + for_each = local.interface_vpc_endpoints + service = each.key +} + +locals { + # Map from the name of an AWS service to a list of the private subnets that are in availability + # zones where the service is available. Only create this map for AWS services where we are going + # to create an Interface VPC endpoint, which require a list of subnet ids in which to create the + # elastic network interface for the endpoint. + aws_service_subnets = { + for service in local.interface_vpc_endpoints : + service => [ + for subnet in data.aws_subnet.private[*] : + subnet.id + if contains(data.aws_vpc_endpoint_service.aws_service[service].availability_zones, subnet.availability_zone) + ] + } +} + +resource "aws_security_group" "aws_services" { + name_prefix = var.aws_services_security_group_name_prefix + description = "VPC endpoints to access AWS services from the VPCs private subnets" + vpc_id = module.aws_vpc.vpc_id +} + +resource "aws_vpc_endpoint" "interface" { + for_each = local.interface_vpc_endpoints + + vpc_id = module.aws_vpc.vpc_id + service_name = "com.amazonaws.${data.aws_region.current.name}.${each.key}" + vpc_endpoint_type = "Interface" + security_group_ids = [aws_security_group.aws_services.id] + subnet_ids = local.aws_service_subnets[each.key] + private_dns_enabled = true +} + +resource "aws_vpc_endpoint" "gateway" { + for_each = local.gateway_vpc_endpoints + + vpc_id = module.aws_vpc.vpc_id + service_name = "com.amazonaws.${data.aws_region.current.name}.${each.key}" + vpc_endpoint_type = "Gateway" + route_table_ids = module.aws_vpc.private_route_table_ids +} diff --git a/infra/networks/main.tf b/infra/networks/main.tf index 9f5ac2057..d85fb65d9 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -1,7 +1,3 @@ -# TODO: This file is is a temporary implementation of the network layer -# that currently just adds resources to the default VPC -# The full network implementation is part of https://github.com/navapbc/template-infra/issues/152 - data "aws_region" "current" {} locals { @@ -64,13 +60,6 @@ data "aws_vpc" "default" { default = true } -data "aws_subnets" "default" { - filter { - name = "default-for-az" - values = [true] - } -} - # VPC Endpoints for accessing AWS Services # ---------------------------------------- # diff --git a/infra/networks/staging.s3.tfbackend b/infra/networks/staging.s3.tfbackend new file mode 100644 index 000000000..77e8e4f49 --- /dev/null +++ b/infra/networks/staging.s3.tfbackend @@ -0,0 +1,4 @@ +bucket = "simpler-grants-gov-315341936575-us-east-1-tf" +key = "infra/networks/staging.tfstate" +dynamodb_table = "simpler-grants-gov-315341936575-us-east-1-tf-state-locks" +region = "us-east-1" diff --git a/infra/networks/subnet-backfill.tf b/infra/networks/subnet-backfill.tf deleted file mode 100644 index 7009f0457..000000000 --- a/infra/networks/subnet-backfill.tf +++ /dev/null @@ -1,92 +0,0 @@ -# The purpose of this file is to backfill the default VPC with 3 private subnets. - -locals { - backfill_subnet_cidrs = { - # The CIDRs were chosen to be within `172.31.0.0/16` but not overlap with the nearest - # CIDRs already being used in the VPC. - # - # You can can confirm the ranges with a tool like: - # https://www.ipaddressguide.com/cidr - # - # The `/20` CIDR block was chosen because most of the existing subnets are `/20`. - "us-east-1a" = "172.31.144.0/20", # /20 = 4096 IPs, last address is 172.31.159.255 - "us-east-1b" = "172.31.160.0/20", # /20 = 4096 IPs, last address is 172.31.175.255 - "us-east-1c" = "172.31.176.0/20", # /20 = 4096 IPs, last address is 172.31.191.255 - } -} - -# ------- # -# SUBNETS # -# ------- # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet -resource "aws_subnet" "backfill_private" { - for_each = local.backfill_subnet_cidrs - vpc_id = data.aws_vpc.default.id - availability_zone = each.key - cidr_block = each.value - map_public_ip_on_launch = false - tags = { - Name = "backfill-private-${each.key}" - subnet_type = "private" - } -} - -# ----------- # -# NAT GATEWAY # -# ----------- # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip -# -# purpose: All external traffic from the private subnets will be routed through this EIP -# via means of a NAT gateway. -resource "aws_eip" "backfill_private" { - # checkov:skip=CKV2_AWS_19: These EIPs are attached to NAT gateways - for_each = local.backfill_subnet_cidrs - domain = "vpc" - tags = { - Name = "backfill-private-${each.key}" - } -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway -resource "aws_nat_gateway" "backfill_private" { - for_each = local.backfill_subnet_cidrs - allocation_id = aws_eip.backfill_private[each.key].allocation_id - subnet_id = aws_subnet.backfill_private[each.key].id - tags = { - Name = "backfill-private-${each.key}" - } -} - -# ------------ # -# ROUTE TABLES # -# ------------ # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table -resource "aws_route_table" "backfill_private" { - for_each = local.backfill_subnet_cidrs - vpc_id = data.aws_vpc.default.id - tags = { - Name = "backfill-private-${each.key}" - } -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association -# -# purpose: Associate the private subnets with the private route table. -resource "aws_route_table_association" "backfill_private" { - for_each = local.backfill_subnet_cidrs - subnet_id = aws_subnet.backfill_private[each.key].id - route_table_id = aws_route_table.backfill_private[each.key].id -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route -# -# purpose: Route external traffic through the NAT gateway. -resource "aws_route" "backfill_private" { - for_each = local.backfill_subnet_cidrs - route_table_id = aws_route_table.backfill_private[each.key].id - destination_cidr_block = "0.0.0.0/0" - nat_gateway_id = aws_nat_gateway.backfill_private[each.key].id -} From 0f926842937d6b74f9a9c10e832accadc58d2883 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:15:46 -0800 Subject: [PATCH 02/22] Moves DMS to networking layer module --- infra/modules/database/networking.tf | 28 ----------------- infra/modules/dms/main.tf | 38 +++++++++++++++++++++++ infra/modules/dms/networking.tf | 46 +++++++++++++++++++++++++--- infra/modules/dms/variables.tf | 4 ++- infra/networks/main.tf | 34 +++----------------- 5 files changed, 87 insertions(+), 63 deletions(-) diff --git a/infra/modules/database/networking.tf b/infra/modules/database/networking.tf index 4ffedde89..afc0e46ef 100644 --- a/infra/modules/database/networking.tf +++ b/infra/modules/database/networking.tf @@ -13,14 +13,6 @@ resource "aws_security_group" "role_manager" { vpc_id = var.vpc_id } -# We need to attach this security group to our DMS instance when created -resource "aws_security_group" "dms" { - # checkov:skip= CKV2_AWS_5:DMS instance not created yet - name_prefix = "${var.name}-dms" - description = "Database DMS security group" - vpc_id = var.vpc_id -} - resource "aws_vpc_security_group_egress_rule" "role_manager_egress_to_db" { security_group_id = aws_security_group.role_manager.id description = "Allow role manager to access database" @@ -41,26 +33,6 @@ resource "aws_vpc_security_group_ingress_rule" "db_ingress_from_role_manager" { referenced_security_group_id = aws_security_group.role_manager.id } -resource "aws_vpc_security_group_egress_rule" "db_egress_from_dms" { - security_group_id = aws_security_group.db.id - description = "Allow outbound requests to database from DMS" - - from_port = 5432 - to_port = 5432 - ip_protocol = "tcp" - referenced_security_group_id = aws_security_group.dms.id -} - -resource "aws_vpc_security_group_ingress_rule" "db_ingress_from_dms" { - security_group_id = aws_security_group.db.id - description = "Allow inbound requests to database from DMS" - - from_port = 5432 - to_port = 5432 - ip_protocol = "tcp" - referenced_security_group_id = aws_security_group.dms.id -} - resource "aws_vpc_security_group_egress_rule" "role_manager_egress_to_vpc_endpoints" { security_group_id = aws_security_group.role_manager.id description = "Allow outbound requests from role manager to VPC endpoints" diff --git a/infra/modules/dms/main.tf b/infra/modules/dms/main.tf index e69de29bb..c2b8c3127 100644 --- a/infra/modules/dms/main.tf +++ b/infra/modules/dms/main.tf @@ -0,0 +1,38 @@ +locals { + our_target_cidr_block = "10.0.0.0/20" # our [Nava] cidr block, where the target database for the DMS is located + their_source_cidr_block = "10.220.0.0/16" # their [MicroHealth] cidr block, where the origin database for the DMS is located +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter +data "aws_ssm_parameter" "dms_peer_owner_id" { + name = "/network/dms/peer-owner-id" +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter +data "aws_ssm_parameter" "dms_peer_vpc_id" { + name = "/network/dms/peer-vpc-id" +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc +data "aws_vpc" "main" { + id = var.vpc_id +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection +resource "aws_vpc_peering_connection" "dms" { + peer_owner_id = data.aws_ssm_parameter.dms_peer_owner_id.value + peer_vpc_id = data.aws_ssm_parameter.dms_peer_vpc_id.value + vpc_id = var.vpc_id + peer_region = "us-east-2" + + tags = { + Name = "DMS VPC Peering" + } +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route +resource "aws_route" "dms" { + route_table_id = data.aws_vpc.main.main_route_table_id + destination_cidr_block = local.their_source_cidr_block + vpc_peering_connection_id = aws_vpc_peering_connection.dms.id +} diff --git a/infra/modules/dms/networking.tf b/infra/modules/dms/networking.tf index 96dd38269..23b4d8951 100644 --- a/infra/modules/dms/networking.tf +++ b/infra/modules/dms/networking.tf @@ -2,9 +2,45 @@ data "aws_caller_identity" "current" {} data "aws_region" "current" {} -# This connection was created in the console, the provided arguments act more as a query than a reference -data "aws_vpc_peering_connection" "dms" { - owner_id = data.aws_caller_identity.current.account_id - cidr_block = "172.31.0.0/16" # our cidr block, where the target database for the DMS is located - peer_cidr_block = "10.220.0.0/16" # their cidr block, where the origin database for the DMS is located +# We need to attach this security group to our DMS instance when created +resource "aws_security_group" "dms" { + name_prefix = "dms" + description = "Database DMS security group" + vpc_id = var.vpc_id +} + +resource "aws_vpc_security_group_egress_rule" "postgres_egress_from_dms" { + description = "Allow outbound requests to database from DMS" + cidr_ipv4 = local.our_target_cidr_block + from_port = 5432 # postgres default port + to_port = 5432 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_ingress_rule" "postgres_ingress_from_dms" { + description = "Allow inbound requests to database from DMS" + cidr_ipv4 = local.our_target_cidr_block + from_port = 5432 # postgres default port + to_port = 5432 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_egress_rule" "oracle_egress_from_dms" { + description = "Allow outbound requests to database from DMS" + cidr_ipv4 = local.their_source_cidr_block + from_port = 1521 # oracle default port + to_port = 1521 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_ingress_rule" "oracle_ingress_from_dms" { + description = "Allow inbound requests to database from DMS" + cidr_ipv4 = local.their_source_cidr_block + from_port = 1521 # oracle default port + to_port = 1521 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id } diff --git a/infra/modules/dms/variables.tf b/infra/modules/dms/variables.tf index 8b1378917..38231226c 100644 --- a/infra/modules/dms/variables.tf +++ b/infra/modules/dms/variables.tf @@ -1 +1,3 @@ - +variable "vpc_id" { + type = string +} diff --git a/infra/networks/main.tf b/infra/networks/main.tf index 9f5ac2057..7f571081b 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -60,6 +60,11 @@ module "app_config" { source = "../api/app-config" } +module "dms" { + source = "../modules/dms" + vpc_id = data.aws_vpc.default.id +} + data "aws_vpc" "default" { default = true } @@ -125,32 +130,3 @@ resource "aws_vpc_endpoint" "gateway" { vpc_endpoint_type = "Gateway" route_table_ids = [for table in aws_route_table.backfill_private : table.id] } - -# VPC Configuration for DMS -# ---------------------------------------- - -data "aws_ssm_parameter" "dms_peer_owner_id" { - name = "/network/dms/peer-owner-id" -} - -data "aws_ssm_parameter" "dms_peer_vpc_id" { - name = "/network/dms/peer-vpc-id" -} - -resource "aws_vpc_peering_connection" "dms" { - peer_owner_id = data.aws_ssm_parameter.dms_peer_owner_id.value - peer_vpc_id = data.aws_ssm_parameter.dms_peer_vpc_id.value - vpc_id = data.aws_vpc.default.id - peer_region = "us-east-2" - - tags = { - Name = "DMS VPC Peering" - } -} - -resource "aws_route" "dms" { - route_table_id = data.aws_vpc.default.main_route_table_id - # MicroHealth VPC CIDR block - destination_cidr_block = "10.220.0.0/16" - vpc_peering_connection_id = aws_vpc_peering_connection.dms.id -} From 5fbf896f3fd2b63ecb3e0c43cd1f247cdaadab95 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:23:00 -0800 Subject: [PATCH 03/22] misc fixes --- infra/api/database/main.tf | 5 +++++ infra/networks/main.tf | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index 3f671c26a..2b6251044 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -88,3 +88,8 @@ module "database" { private_subnet_ids = data.aws_subnets.default.ids aws_services_security_group_id = data.aws_security_groups.aws_services.ids[0] } + +module "dms" { + source = "../../modules/dms" + vpc_id = data.aws_vpc.default.id +} diff --git a/infra/networks/main.tf b/infra/networks/main.tf index 7f571081b..97f1816a0 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -60,11 +60,6 @@ module "app_config" { source = "../api/app-config" } -module "dms" { - source = "../modules/dms" - vpc_id = data.aws_vpc.default.id -} - data "aws_vpc" "default" { default = true } From 5a19e50b51d7a8398a2bab058b94207d676cc05a Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:27:36 -0800 Subject: [PATCH 04/22] diff reduction --- infra/modules/dms/main.tf | 19 ------------ infra/modules/dms/networking.tf | 53 +++++++++------------------------ infra/modules/dms/security.tf | 45 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 58 deletions(-) create mode 100644 infra/modules/dms/security.tf diff --git a/infra/modules/dms/main.tf b/infra/modules/dms/main.tf index c2b8c3127..6dbb25be5 100644 --- a/infra/modules/dms/main.tf +++ b/infra/modules/dms/main.tf @@ -17,22 +17,3 @@ data "aws_ssm_parameter" "dms_peer_vpc_id" { data "aws_vpc" "main" { id = var.vpc_id } - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection -resource "aws_vpc_peering_connection" "dms" { - peer_owner_id = data.aws_ssm_parameter.dms_peer_owner_id.value - peer_vpc_id = data.aws_ssm_parameter.dms_peer_vpc_id.value - vpc_id = var.vpc_id - peer_region = "us-east-2" - - tags = { - Name = "DMS VPC Peering" - } -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route -resource "aws_route" "dms" { - route_table_id = data.aws_vpc.main.main_route_table_id - destination_cidr_block = local.their_source_cidr_block - vpc_peering_connection_id = aws_vpc_peering_connection.dms.id -} diff --git a/infra/modules/dms/networking.tf b/infra/modules/dms/networking.tf index 23b4d8951..79289d52d 100644 --- a/infra/modules/dms/networking.tf +++ b/infra/modules/dms/networking.tf @@ -1,46 +1,21 @@ -# Add Security Groups for VPC -> DMS here data "aws_caller_identity" "current" {} data "aws_region" "current" {} -# We need to attach this security group to our DMS instance when created -resource "aws_security_group" "dms" { - name_prefix = "dms" - description = "Database DMS security group" - vpc_id = var.vpc_id -} - -resource "aws_vpc_security_group_egress_rule" "postgres_egress_from_dms" { - description = "Allow outbound requests to database from DMS" - cidr_ipv4 = local.our_target_cidr_block - from_port = 5432 # postgres default port - to_port = 5432 - ip_protocol = "tcp" - security_group_id = aws_security_group.dms.id -} - -resource "aws_vpc_security_group_ingress_rule" "postgres_ingress_from_dms" { - description = "Allow inbound requests to database from DMS" - cidr_ipv4 = local.our_target_cidr_block - from_port = 5432 # postgres default port - to_port = 5432 - ip_protocol = "tcp" - security_group_id = aws_security_group.dms.id -} +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection +resource "aws_vpc_peering_connection" "dms" { + peer_owner_id = data.aws_ssm_parameter.dms_peer_owner_id.value + peer_vpc_id = data.aws_ssm_parameter.dms_peer_vpc_id.value + vpc_id = var.vpc_id + peer_region = "us-east-2" -resource "aws_vpc_security_group_egress_rule" "oracle_egress_from_dms" { - description = "Allow outbound requests to database from DMS" - cidr_ipv4 = local.their_source_cidr_block - from_port = 1521 # oracle default port - to_port = 1521 - ip_protocol = "tcp" - security_group_id = aws_security_group.dms.id + tags = { + Name = "DMS VPC Peering" + } } -resource "aws_vpc_security_group_ingress_rule" "oracle_ingress_from_dms" { - description = "Allow inbound requests to database from DMS" - cidr_ipv4 = local.their_source_cidr_block - from_port = 1521 # oracle default port - to_port = 1521 - ip_protocol = "tcp" - security_group_id = aws_security_group.dms.id +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route +resource "aws_route" "dms" { + route_table_id = data.aws_vpc.main.main_route_table_id + destination_cidr_block = local.their_source_cidr_block + vpc_peering_connection_id = aws_vpc_peering_connection.dms.id } diff --git a/infra/modules/dms/security.tf b/infra/modules/dms/security.tf new file mode 100644 index 000000000..c8f76394a --- /dev/null +++ b/infra/modules/dms/security.tf @@ -0,0 +1,45 @@ +# Add Security Groups for VPC -> DMS here + +# We need to attach this security group to our DMS instance when created +resource "aws_security_group" "dms" { + # checkov:skip= CKV2_AWS_5:DMS instance not created yet + name_prefix = "dms" + description = "Database DMS security group" + vpc_id = var.vpc_id +} + +resource "aws_vpc_security_group_egress_rule" "postgres_egress_from_dms" { + description = "Allow outbound requests to database from DMS" + cidr_ipv4 = local.our_target_cidr_block + from_port = 5432 # postgres default port + to_port = 5432 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_ingress_rule" "postgres_ingress_from_dms" { + description = "Allow inbound requests to database from DMS" + cidr_ipv4 = local.our_target_cidr_block + from_port = 5432 # postgres default port + to_port = 5432 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_egress_rule" "oracle_egress_from_dms" { + description = "Allow outbound requests to database from DMS" + cidr_ipv4 = local.their_source_cidr_block + from_port = 1521 # oracle default port + to_port = 1521 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} + +resource "aws_vpc_security_group_ingress_rule" "oracle_ingress_from_dms" { + description = "Allow inbound requests to database from DMS" + cidr_ipv4 = local.their_source_cidr_block + from_port = 1521 # oracle default port + to_port = 1521 + ip_protocol = "tcp" + security_group_id = aws_security_group.dms.id +} From 0aa2338301b28e369bf4f56875c99e42ad53a2e1 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:48:19 -0800 Subject: [PATCH 05/22] move to networking --- infra/networks/main.tf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/infra/networks/main.tf b/infra/networks/main.tf index 97f1816a0..66eb9c19e 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -60,6 +60,11 @@ module "app_config" { source = "../api/app-config" } +module "dms_networking" { + source = "../modules/dms-networking" + vpc_id = data.aws_vpc.default.id +} + data "aws_vpc" "default" { default = true } From f26b775caa67ab48e84adf6cadcb1296e10ed864 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:49:37 -0800 Subject: [PATCH 06/22] move to networking folder From 1d76c838b4e628aa4bb2bfc42886aca734b8c7b0 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:49:49 -0800 Subject: [PATCH 07/22] move to networking folder --- infra/api/database/main.tf | 5 ----- infra/modules/{dms => dms-networking}/.terraform.lock.hcl | 0 infra/modules/{dms => dms-networking}/main.tf | 0 infra/modules/{dms => dms-networking}/networking.tf | 0 infra/modules/{dms => dms-networking}/outputs.tf | 0 infra/modules/{dms => dms-networking}/security.tf | 0 infra/modules/{dms => dms-networking}/variables.tf | 0 7 files changed, 5 deletions(-) rename infra/modules/{dms => dms-networking}/.terraform.lock.hcl (100%) rename infra/modules/{dms => dms-networking}/main.tf (100%) rename infra/modules/{dms => dms-networking}/networking.tf (100%) rename infra/modules/{dms => dms-networking}/outputs.tf (100%) rename infra/modules/{dms => dms-networking}/security.tf (100%) rename infra/modules/{dms => dms-networking}/variables.tf (100%) diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index 2b6251044..3f671c26a 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -88,8 +88,3 @@ module "database" { private_subnet_ids = data.aws_subnets.default.ids aws_services_security_group_id = data.aws_security_groups.aws_services.ids[0] } - -module "dms" { - source = "../../modules/dms" - vpc_id = data.aws_vpc.default.id -} diff --git a/infra/modules/dms/.terraform.lock.hcl b/infra/modules/dms-networking/.terraform.lock.hcl similarity index 100% rename from infra/modules/dms/.terraform.lock.hcl rename to infra/modules/dms-networking/.terraform.lock.hcl diff --git a/infra/modules/dms/main.tf b/infra/modules/dms-networking/main.tf similarity index 100% rename from infra/modules/dms/main.tf rename to infra/modules/dms-networking/main.tf diff --git a/infra/modules/dms/networking.tf b/infra/modules/dms-networking/networking.tf similarity index 100% rename from infra/modules/dms/networking.tf rename to infra/modules/dms-networking/networking.tf diff --git a/infra/modules/dms/outputs.tf b/infra/modules/dms-networking/outputs.tf similarity index 100% rename from infra/modules/dms/outputs.tf rename to infra/modules/dms-networking/outputs.tf diff --git a/infra/modules/dms/security.tf b/infra/modules/dms-networking/security.tf similarity index 100% rename from infra/modules/dms/security.tf rename to infra/modules/dms-networking/security.tf diff --git a/infra/modules/dms/variables.tf b/infra/modules/dms-networking/variables.tf similarity index 100% rename from infra/modules/dms/variables.tf rename to infra/modules/dms-networking/variables.tf From a9cd45e9086d015748bfe32102827902dbd080e3 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:55:20 -0800 Subject: [PATCH 08/22] puts cidr back --- infra/modules/dms-networking/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/modules/dms-networking/main.tf b/infra/modules/dms-networking/main.tf index 6dbb25be5..17933fbb6 100644 --- a/infra/modules/dms-networking/main.tf +++ b/infra/modules/dms-networking/main.tf @@ -1,5 +1,5 @@ locals { - our_target_cidr_block = "10.0.0.0/20" # our [Nava] cidr block, where the target database for the DMS is located + our_target_cidr_block = "172.31.0.0/16" # our [Nava] cidr block, where the target database for the DMS is located their_source_cidr_block = "10.220.0.0/16" # their [MicroHealth] cidr block, where the origin database for the DMS is located } From 41e46f8b62ba8121e30b41252d8a0432b453921a Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 12:58:01 -0800 Subject: [PATCH 09/22] update cidr --- infra/modules/dms-networking/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/modules/dms-networking/main.tf b/infra/modules/dms-networking/main.tf index 17933fbb6..6dbb25be5 100644 --- a/infra/modules/dms-networking/main.tf +++ b/infra/modules/dms-networking/main.tf @@ -1,5 +1,5 @@ locals { - our_target_cidr_block = "172.31.0.0/16" # our [Nava] cidr block, where the target database for the DMS is located + our_target_cidr_block = "10.0.0.0/20" # our [Nava] cidr block, where the target database for the DMS is located their_source_cidr_block = "10.220.0.0/16" # their [MicroHealth] cidr block, where the origin database for the DMS is located } From 382a7e946e618c0d882e38139f74ade703d215e3 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 14:35:51 -0800 Subject: [PATCH 10/22] checkpoint --- infra/modules/network/main.tf | 8 +-- infra/modules/network/outputs.tf | 3 ++ infra/modules/network/variables.tf | 5 -- infra/networks/main.tf | 86 +++--------------------------- infra/networks/variables.tf | 5 ++ 5 files changed, 20 insertions(+), 87 deletions(-) create mode 100644 infra/modules/network/outputs.tf diff --git a/infra/modules/network/main.tf b/infra/modules/network/main.tf index 9def582e4..1bfde2558 100644 --- a/infra/modules/network/main.tf +++ b/infra/modules/network/main.tf @@ -1,7 +1,7 @@ data "aws_availability_zones" "available" {} locals { - vpc_cidr = "10.${var.cidr_second_octet}.0.0/20" + vpc_cidr = "10.0.0.0/20" num_availability_zones = 3 availability_zones = slice(data.aws_availability_zones.available.names, 0, local.num_availability_zones) } @@ -14,9 +14,9 @@ module "aws_vpc" { azs = local.availability_zones cidr = local.vpc_cidr - public_subnets = ["10.${var.cidr_second_octet}.10.0/24", "10.${var.cidr_second_octet}.11.0/24", "10.${var.cidr_second_octet}.12.0/24"] - private_subnets = ["10.${var.cidr_second_octet}.0.0/24", "10.${var.cidr_second_octet}.1.0/24", "10.${var.cidr_second_octet}.2.0/24"] - database_subnets = ["10.${var.cidr_second_octet}.5.0/24", "10.${var.cidr_second_octet}.6.0/24", "10.${var.cidr_second_octet}.7.0/24"] + public_subnets = ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"] + private_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"] + database_subnets = ["10.0.5.0/24", "10.0.6.0/24", "10.0.7.0/24"] public_subnet_tags = { subnet_type = "public" } private_subnet_tags = { subnet_type = "private" } database_subnet_tags = { subnet_type = "database" } diff --git a/infra/modules/network/outputs.tf b/infra/modules/network/outputs.tf new file mode 100644 index 000000000..d4976db1c --- /dev/null +++ b/infra/modules/network/outputs.tf @@ -0,0 +1,3 @@ +output "vpc_id" { + value = module.aws_vpc.vpc_id +} diff --git a/infra/modules/network/variables.tf b/infra/modules/network/variables.tf index e0637408f..d57661b8c 100644 --- a/infra/modules/network/variables.tf +++ b/infra/modules/network/variables.tf @@ -3,11 +3,6 @@ variable "name" { description = "Name to give the VPC. Will be added to the VPC under the 'network_name' tag." } -variable "cidr_second_octet" { - type = string - description = "For a given example CIDR of 10.x.0.0/16, this variable would be 'x'." -} - variable "aws_services_security_group_name_prefix" { type = string description = "Prefix for the name of the security group attached to VPC endpoints" diff --git a/infra/networks/main.tf b/infra/networks/main.tf index 8c76ac804..d64d7610a 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -5,25 +5,6 @@ locals { description = "VPC resources" }) region = module.project_config.default_region - - # List of AWS services used by this VPC - # This list is used to create VPC endpoints so that the AWS services can - # be accessed without network traffic ever leaving the VPC's private network - # For a list of AWS services that integrate with AWS PrivateLink - # see https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.html - # - # The database module requires VPC access from private networks to SSM, KMS, and RDS - aws_service_integrations = setunion( - # AWS services used by ECS Fargate: ECR to fetch images, S3 for image layers, and CloudWatch for logs - ["ecr.api", "ecr.dkr", "s3", "logs"], - - # AWS services used by the database's role manager - var.has_database ? ["ssm", "kms", "secretsmanager"] : [], - ) - - # S3 and DynamoDB use Gateway VPC endpoints. All other services use Interface VPC endpoints - interface_vpc_endpoints = toset([for aws_service in local.aws_service_integrations : aws_service if !contains(["s3", "dynamodb"], aws_service)]) - gateway_vpc_endpoints = toset([for aws_service in local.aws_service_integrations : aws_service if contains(["s3", "dynamodb"], aws_service)]) } terraform { @@ -56,66 +37,15 @@ module "app_config" { source = "../api/app-config" } -module "dms_networking" { - source = "../modules/dms-networking" - vpc_id = data.aws_vpc.default.id -} - -data "aws_vpc" "default" { - default = true +module "network" { + source = "../modules/network" + name = var.environment_name + database_subnet_group_name = var.environment_name + aws_services_security_group_name_prefix = var.environment_name } -# VPC Endpoints for accessing AWS Services -# ---------------------------------------- -# -# Since the role manager Lambda function is in the VPC (which is needed to be -# able to access the database) we need to allow the Lambda function to access -# AWS Systems Manager Parameter Store (to fetch the database password) and -# KMS (to decrypt SecureString parameters from Parameter Store). We can do -# this by either allowing internet access to the Lambda, or by using a VPC -# endpoint. The latter is more secure. -# See https://repost.aws/knowledge-center/lambda-vpc-parameter-store -# See https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group -resource "aws_security_group" "aws_services" { - count = length(local.aws_service_integrations) > 0 ? 1 : 0 - - name_prefix = module.project_config.aws_services_security_group_name_prefix - description = "VPC endpoints to access AWS services from the VPCs private subnets" - vpc_id = data.aws_vpc.default.id -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule -resource "aws_vpc_security_group_ingress_rule" "aws_services" { - count = length(local.aws_service_integrations) > 0 ? 1 : 0 - - security_group_id = aws_security_group.aws_services[0].id - description = "Allow all traffic from the VPCs CIDR block to the VPC endpoint security group" - from_port = 443 - to_port = 443 - ip_protocol = "tcp" - cidr_ipv4 = data.aws_vpc.default.cidr_block -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint -resource "aws_vpc_endpoint" "aws_service" { - for_each = local.aws_service_integrations - - vpc_id = data.aws_vpc.default.id - service_name = "com.amazonaws.${data.aws_region.current.name}.${each.key}" - vpc_endpoint_type = "Interface" - security_group_ids = [aws_security_group.aws_services[0].id] - subnet_ids = [for subnet in aws_subnet.backfill_private : subnet.id] - private_dns_enabled = true +module "dms_networking" { + source = "../modules/dms-networking" + vpc_id = module.network.vpc_id } -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint -resource "aws_vpc_endpoint" "gateway" { - for_each = local.gateway_vpc_endpoints - - vpc_id = data.aws_vpc.default.id - service_name = "com.amazonaws.${data.aws_region.current.name}.${each.key}" - vpc_endpoint_type = "Gateway" - route_table_ids = [for table in aws_route_table.backfill_private : table.id] -} diff --git a/infra/networks/variables.tf b/infra/networks/variables.tf index f45967381..537eb1c5d 100644 --- a/infra/networks/variables.tf +++ b/infra/networks/variables.tf @@ -3,3 +3,8 @@ variable "has_database" { description = "whether the application has a database" default = true } + +variable "environment_name" { + type = string + description = "name of the application environment" +} From b10fefcaa713416d69c80025f3d363784629e500 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 17:01:04 -0800 Subject: [PATCH 11/22] filter by correct vpc --- infra/api/database/main.tf | 4 ++++ infra/api/service/main.tf | 8 ++++++++ infra/frontend/service/main.tf | 14 +++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index eabe718bf..640aa05f8 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -8,6 +8,10 @@ data "aws_vpc" "network" { # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet data "aws_subnets" "database" { + filter { + name = "vpc-id" + values = [data.aws_vpc.network.id] + } filter { name = "tag:subnet_type" values = ["database"] diff --git a/infra/api/service/main.tf b/infra/api/service/main.tf index ccc14ba0e..e9fec3a21 100644 --- a/infra/api/service/main.tf +++ b/infra/api/service/main.tf @@ -8,6 +8,10 @@ data "aws_vpc" "network" { # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet data "aws_subnets" "private" { + filter { + name = "vpc-id" + values = [data.aws_vpc.network.id] + } filter { name = "tag:subnet_type" values = ["private"] @@ -16,6 +20,10 @@ data "aws_subnets" "private" { # docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet data "aws_subnets" "public" { + filter { + name = "vpc-id" + values = [data.aws_vpc.network.id] + } filter { name = "tag:subnet_type" values = ["public"] diff --git a/infra/frontend/service/main.tf b/infra/frontend/service/main.tf index ed7669e4d..e897f0621 100644 --- a/infra/frontend/service/main.tf +++ b/infra/frontend/service/main.tf @@ -6,16 +6,24 @@ data "aws_vpc" "network" { } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet +# docs: https://registry.terraform.io/providers/hashicorp/aws/4.67.0/docs/data-sources/subnets data "aws_subnets" "private" { + filter { + name = "vpc-id" + values = [data.aws_vpc.network.id] + } filter { name = "tag:subnet_type" values = ["private"] } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet +# docs: https://registry.terraform.io/providers/hashicorp/aws/4.67.0/docs/data-sources/subnets data "aws_subnets" "public" { + filter { + name = "vpc-id" + values = [data.aws_vpc.network.id] + } filter { name = "tag:subnet_type" values = ["public"] @@ -120,7 +128,7 @@ module "service" { service_name = local.service_name image_repository_name = module.app_config.image_repository_name image_tag = local.image_tag - vpc_id = data.aws_vpc.default.id + vpc_id = data.aws_vpc.network.id public_subnet_ids = data.aws_subnets.public.ids private_subnet_ids = data.aws_subnets.private.ids enable_autoscaling = module.app_config.enable_autoscaling From d2448e9dca6bf2e3490134e25de311d2ecde80b3 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Thu, 18 Jan 2024 17:46:32 -0800 Subject: [PATCH 12/22] add sg perms --- infra/modules/network/vpc-endpoints.tf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/infra/modules/network/vpc-endpoints.tf b/infra/modules/network/vpc-endpoints.tf index 701d57d37..8c91820d3 100644 --- a/infra/modules/network/vpc-endpoints.tf +++ b/infra/modules/network/vpc-endpoints.tf @@ -71,6 +71,15 @@ resource "aws_security_group" "aws_services" { vpc_id = module.aws_vpc.vpc_id } +resource "aws_vpc_security_group_ingress_rule" "vpc_endpoints_ingress_from_vpc_cidr" { + security_group_id = aws_security_group.aws_services.id + description = "Allow inbound requests to VPC endpoints from the VPC cidr block" + from_port = 443 + to_port = 443 + ip_protocol = "tcp" + cidr_ipv4 = local.vpc_cidr +} + resource "aws_vpc_endpoint" "interface" { for_each = local.interface_vpc_endpoints From 3d65fdf5ad98b470f261ec40376cf9484c01768e Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 13:35:30 -0800 Subject: [PATCH 13/22] keep default network From 052d2878734d4167437e913aa3d2faa64b4c1ce0 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 13:39:14 -0800 Subject: [PATCH 14/22] keep default network --- infra/api/database/main.tf | 2 +- infra/api/service/main.tf | 2 +- infra/frontend/service/main.tf | 2 +- infra/project-config/main.tf | 7 +++++++ infra/project-config/outputs.tf | 4 ++++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index 640aa05f8..3be318439 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -2,7 +2,7 @@ data "aws_vpc" "network" { filter { name = "tag:Name" - values = [var.environment_name] + values = module.project_config.network_configs[var.environment_name].vpc_name } } diff --git a/infra/api/service/main.tf b/infra/api/service/main.tf index e9fec3a21..affd251b6 100644 --- a/infra/api/service/main.tf +++ b/infra/api/service/main.tf @@ -2,7 +2,7 @@ data "aws_vpc" "network" { filter { name = "tag:Name" - values = [var.environment_name] + values = module.project_config.network_configs[var.environment_name].vpc_name } } diff --git a/infra/frontend/service/main.tf b/infra/frontend/service/main.tf index e897f0621..64b43424b 100644 --- a/infra/frontend/service/main.tf +++ b/infra/frontend/service/main.tf @@ -2,7 +2,7 @@ data "aws_vpc" "network" { filter { name = "tag:Name" - values = [var.environment_name] + values = module.project_config.network_configs[var.environment_name].vpc_name } } diff --git a/infra/project-config/main.tf b/infra/project-config/main.tf index 08755144e..52f8af1aa 100644 --- a/infra/project-config/main.tf +++ b/infra/project-config/main.tf @@ -16,4 +16,11 @@ locals { github_actions_role_name = "${local.project_name}-github-actions" aws_services_security_group_name_prefix = "aws-service-vpc-endpoints" + + network_configs = { + # TODO(https://github.com/HHS/simpler-grants-gov/issues/1051) deploy to a non-default VPC in every environment + dev = { vpc_name = "default" } + staging = { vpc_name = "staging" } + prod = { vpc_name = "default" } + } } diff --git a/infra/project-config/outputs.tf b/infra/project-config/outputs.tf index 690f1eb22..574dfe0bf 100644 --- a/infra/project-config/outputs.tf +++ b/infra/project-config/outputs.tf @@ -38,3 +38,7 @@ output "github_actions_role_name" { output "aws_services_security_group_name_prefix" { value = local.aws_services_security_group_name_prefix } + +output "network_configs" { + value = local.network_configs +} From db2f19ba8f726ed11d3bebf944e74cc7c707eb85 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 13:44:50 -0800 Subject: [PATCH 15/22] git restore --- infra/frontend/service/main.tf | 4 +- infra/networks/subnet-backfill.tf | 92 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 infra/networks/subnet-backfill.tf diff --git a/infra/frontend/service/main.tf b/infra/frontend/service/main.tf index 64b43424b..84284d5b6 100644 --- a/infra/frontend/service/main.tf +++ b/infra/frontend/service/main.tf @@ -6,7 +6,7 @@ data "aws_vpc" "network" { } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/4.67.0/docs/data-sources/subnets +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets data "aws_subnets" "private" { filter { name = "vpc-id" @@ -18,7 +18,7 @@ data "aws_subnets" "private" { } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/4.67.0/docs/data-sources/subnets +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets data "aws_subnets" "public" { filter { name = "vpc-id" diff --git a/infra/networks/subnet-backfill.tf b/infra/networks/subnet-backfill.tf new file mode 100644 index 000000000..7009f0457 --- /dev/null +++ b/infra/networks/subnet-backfill.tf @@ -0,0 +1,92 @@ +# The purpose of this file is to backfill the default VPC with 3 private subnets. + +locals { + backfill_subnet_cidrs = { + # The CIDRs were chosen to be within `172.31.0.0/16` but not overlap with the nearest + # CIDRs already being used in the VPC. + # + # You can can confirm the ranges with a tool like: + # https://www.ipaddressguide.com/cidr + # + # The `/20` CIDR block was chosen because most of the existing subnets are `/20`. + "us-east-1a" = "172.31.144.0/20", # /20 = 4096 IPs, last address is 172.31.159.255 + "us-east-1b" = "172.31.160.0/20", # /20 = 4096 IPs, last address is 172.31.175.255 + "us-east-1c" = "172.31.176.0/20", # /20 = 4096 IPs, last address is 172.31.191.255 + } +} + +# ------- # +# SUBNETS # +# ------- # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet +resource "aws_subnet" "backfill_private" { + for_each = local.backfill_subnet_cidrs + vpc_id = data.aws_vpc.default.id + availability_zone = each.key + cidr_block = each.value + map_public_ip_on_launch = false + tags = { + Name = "backfill-private-${each.key}" + subnet_type = "private" + } +} + +# ----------- # +# NAT GATEWAY # +# ----------- # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip +# +# purpose: All external traffic from the private subnets will be routed through this EIP +# via means of a NAT gateway. +resource "aws_eip" "backfill_private" { + # checkov:skip=CKV2_AWS_19: These EIPs are attached to NAT gateways + for_each = local.backfill_subnet_cidrs + domain = "vpc" + tags = { + Name = "backfill-private-${each.key}" + } +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway +resource "aws_nat_gateway" "backfill_private" { + for_each = local.backfill_subnet_cidrs + allocation_id = aws_eip.backfill_private[each.key].allocation_id + subnet_id = aws_subnet.backfill_private[each.key].id + tags = { + Name = "backfill-private-${each.key}" + } +} + +# ------------ # +# ROUTE TABLES # +# ------------ # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table +resource "aws_route_table" "backfill_private" { + for_each = local.backfill_subnet_cidrs + vpc_id = data.aws_vpc.default.id + tags = { + Name = "backfill-private-${each.key}" + } +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association +# +# purpose: Associate the private subnets with the private route table. +resource "aws_route_table_association" "backfill_private" { + for_each = local.backfill_subnet_cidrs + subnet_id = aws_subnet.backfill_private[each.key].id + route_table_id = aws_route_table.backfill_private[each.key].id +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route +# +# purpose: Route external traffic through the NAT gateway. +resource "aws_route" "backfill_private" { + for_each = local.backfill_subnet_cidrs + route_table_id = aws_route_table.backfill_private[each.key].id + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.backfill_private[each.key].id +} From b78ea6808b9d37eed3dcd4aef4b5d519a6220cf1 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 14:23:59 -0800 Subject: [PATCH 16/22] rm subnet backfill --- infra/networks/subnet-backfill.tf | 92 ------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 infra/networks/subnet-backfill.tf diff --git a/infra/networks/subnet-backfill.tf b/infra/networks/subnet-backfill.tf deleted file mode 100644 index 7009f0457..000000000 --- a/infra/networks/subnet-backfill.tf +++ /dev/null @@ -1,92 +0,0 @@ -# The purpose of this file is to backfill the default VPC with 3 private subnets. - -locals { - backfill_subnet_cidrs = { - # The CIDRs were chosen to be within `172.31.0.0/16` but not overlap with the nearest - # CIDRs already being used in the VPC. - # - # You can can confirm the ranges with a tool like: - # https://www.ipaddressguide.com/cidr - # - # The `/20` CIDR block was chosen because most of the existing subnets are `/20`. - "us-east-1a" = "172.31.144.0/20", # /20 = 4096 IPs, last address is 172.31.159.255 - "us-east-1b" = "172.31.160.0/20", # /20 = 4096 IPs, last address is 172.31.175.255 - "us-east-1c" = "172.31.176.0/20", # /20 = 4096 IPs, last address is 172.31.191.255 - } -} - -# ------- # -# SUBNETS # -# ------- # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet -resource "aws_subnet" "backfill_private" { - for_each = local.backfill_subnet_cidrs - vpc_id = data.aws_vpc.default.id - availability_zone = each.key - cidr_block = each.value - map_public_ip_on_launch = false - tags = { - Name = "backfill-private-${each.key}" - subnet_type = "private" - } -} - -# ----------- # -# NAT GATEWAY # -# ----------- # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip -# -# purpose: All external traffic from the private subnets will be routed through this EIP -# via means of a NAT gateway. -resource "aws_eip" "backfill_private" { - # checkov:skip=CKV2_AWS_19: These EIPs are attached to NAT gateways - for_each = local.backfill_subnet_cidrs - domain = "vpc" - tags = { - Name = "backfill-private-${each.key}" - } -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway -resource "aws_nat_gateway" "backfill_private" { - for_each = local.backfill_subnet_cidrs - allocation_id = aws_eip.backfill_private[each.key].allocation_id - subnet_id = aws_subnet.backfill_private[each.key].id - tags = { - Name = "backfill-private-${each.key}" - } -} - -# ------------ # -# ROUTE TABLES # -# ------------ # - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table -resource "aws_route_table" "backfill_private" { - for_each = local.backfill_subnet_cidrs - vpc_id = data.aws_vpc.default.id - tags = { - Name = "backfill-private-${each.key}" - } -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association -# -# purpose: Associate the private subnets with the private route table. -resource "aws_route_table_association" "backfill_private" { - for_each = local.backfill_subnet_cidrs - subnet_id = aws_subnet.backfill_private[each.key].id - route_table_id = aws_route_table.backfill_private[each.key].id -} - -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route -# -# purpose: Route external traffic through the NAT gateway. -resource "aws_route" "backfill_private" { - for_each = local.backfill_subnet_cidrs - route_table_id = aws_route_table.backfill_private[each.key].id - destination_cidr_block = "0.0.0.0/0" - nat_gateway_id = aws_nat_gateway.backfill_private[each.key].id -} From 221ec006028d02f77b30ab1e77dcbbc3a11b5c63 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 14:25:48 -0800 Subject: [PATCH 17/22] git restore --- infra/modules/dms-networking/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/modules/dms-networking/main.tf b/infra/modules/dms-networking/main.tf index 6dbb25be5..17933fbb6 100644 --- a/infra/modules/dms-networking/main.tf +++ b/infra/modules/dms-networking/main.tf @@ -1,5 +1,5 @@ locals { - our_target_cidr_block = "10.0.0.0/20" # our [Nava] cidr block, where the target database for the DMS is located + our_target_cidr_block = "172.31.0.0/16" # our [Nava] cidr block, where the target database for the DMS is located their_source_cidr_block = "10.220.0.0/16" # their [MicroHealth] cidr block, where the origin database for the DMS is located } From bcd40843366519e070e0072b77e24d516a746f68 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Fri, 19 Jan 2024 14:27:14 -0800 Subject: [PATCH 18/22] swap defaults around --- infra/modules/network/variables.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/modules/network/variables.tf b/infra/modules/network/variables.tf index d57661b8c..d3ba7511f 100644 --- a/infra/modules/network/variables.tf +++ b/infra/modules/network/variables.tf @@ -16,11 +16,11 @@ variable "database_subnet_group_name" { variable "has_database" { type = bool description = "Whether the application(s) in this network have a database. Determines whether to create VPC endpoints needed by the database layer." - default = false + default = true } variable "has_external_non_aws_service" { type = bool description = "Whether the application(s) in this network need to call external non-AWS services. Determines whether or not to create NAT gateways." - default = false + default = true } From f7cb4ac61452c79419c7133a88c095581eb38746 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Tue, 23 Jan 2024 14:10:56 -0800 Subject: [PATCH 19/22] diff reduction --- infra/networks/main.tf | 11 ++- infra/networks/subnet-backfill.tf | 125 ++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 infra/networks/subnet-backfill.tf diff --git a/infra/networks/main.tf b/infra/networks/main.tf index d64d7610a..de85b2650 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -37,15 +37,14 @@ module "app_config" { source = "../api/app-config" } +module "dms_networking" { + source = "../modules/dms-networking" + vpc_id = module.network.vpc_id +} + module "network" { source = "../modules/network" name = var.environment_name database_subnet_group_name = var.environment_name aws_services_security_group_name_prefix = var.environment_name } - -module "dms_networking" { - source = "../modules/dms-networking" - vpc_id = module.network.vpc_id -} - diff --git a/infra/networks/subnet-backfill.tf b/infra/networks/subnet-backfill.tf new file mode 100644 index 000000000..a44aefb1f --- /dev/null +++ b/infra/networks/subnet-backfill.tf @@ -0,0 +1,125 @@ +# The purpose of this file is to backfill the default VPC with 3 private subnets. + +locals { + backfill_subnet_cidrs = { + # The CIDRs were chosen to be within `172.31.0.0/16` but not overlap with the nearest + # CIDRs already being used in the VPC. + # + # You can can confirm the ranges with a tool like: + # https://www.ipaddressguide.com/cidr + # + # The `/20` CIDR block was chosen because most of the existing subnets are `/20`. + "us-east-1a" = "172.31.144.0/20", # /20 = 4096 IPs, last address is 172.31.159.255 + "us-east-1b" = "172.31.160.0/20", # /20 = 4096 IPs, last address is 172.31.175.255 + "us-east-1c" = "172.31.176.0/20", # /20 = 4096 IPs, last address is 172.31.191.255 + } +} + +# ------- # +# SUBNETS # +# ------- # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet +resource "aws_subnet" "backfill_private" { + for_each = local.backfill_subnet_cidrs + vpc_id = data.aws_vpc.default.id + availability_zone = each.key + cidr_block = each.value + map_public_ip_on_launch = false + tags = { + Name = "default-private-${each.key}" + subnet_type = "private" + } +} +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet +data "aws_subnets" "public" { + filter { + name = "vpc-id" + values = [data.aws_vpc.default.id] + } + filter { + name = "tag:subnet_type" + values = ["public"] + } +} + +# ----------- # +# NAT GATEWAY # +# ----------- # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip +# +# purpose: All external traffic from the private subnets will be routed through this EIP +# via means of a NAT gateway. +resource "aws_eip" "backfill_private" { + # checkov:skip=CKV2_AWS_19: These EIPs are attached to NAT gateways + for_each = local.backfill_subnet_cidrs + domain = "vpc" + tags = { + Name = "default-private-${each.key}" + } +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway +resource "aws_nat_gateway" "backfill_private_0" { + allocation_id = aws_eip.backfill_private["us-east-1a"].allocation_id + subnet_id = data.aws_subnets.public.ids[0] + tags = { + Name = "default-private-us-east-1a" + } +} +resource "aws_nat_gateway" "backfill_private_1" { + allocation_id = aws_eip.backfill_private["us-east-1b"].allocation_id + subnet_id = data.aws_subnets.public.ids[1] + tags = { + Name = "default-private-us-east-1b" + } +} +resource "aws_nat_gateway" "backfill_private_2" { + allocation_id = aws_eip.backfill_private["us-east-1c"].allocation_id + subnet_id = data.aws_subnets.public.ids[2] + tags = { + Name = "default-private-us-east-1c" + } +} + +# ------------ # +# ROUTE TABLES # +# ------------ # + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table +resource "aws_route_table" "backfill_private" { + for_each = local.backfill_subnet_cidrs + vpc_id = data.aws_vpc.default.id + tags = { + Name = "default-private-${each.key}" + } +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association +# +# purpose: Associate the private subnets with the private route table. +resource "aws_route_table_association" "backfill_private" { + for_each = local.backfill_subnet_cidrs + subnet_id = aws_subnet.backfill_private[each.key].id + route_table_id = aws_route_table.backfill_private[each.key].id +} + +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route +# +# purpose: Route external traffic through the NAT gateway. +resource "aws_route" "backfill_private_0" { + route_table_id = aws_route_table.backfill_private["us-east-1a"].id + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.backfill_private_0.id +} +resource "aws_route" "backfill_private_1" { + route_table_id = aws_route_table.backfill_private["us-east-1b"].id + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.backfill_private_1.id +} +resource "aws_route" "backfill_private_2" { + route_table_id = aws_route_table.backfill_private["us-east-1c"].id + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.backfill_private_2.id +} From 2f63b94628d9e4e5ac262fb5b682500f9746e0c3 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Tue, 23 Jan 2024 14:39:17 -0800 Subject: [PATCH 20/22] revert --- infra/networks/main.tf | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/infra/networks/main.tf b/infra/networks/main.tf index de85b2650..fe02ad59d 100644 --- a/infra/networks/main.tf +++ b/infra/networks/main.tf @@ -42,6 +42,17 @@ module "dms_networking" { vpc_id = module.network.vpc_id } +data "aws_vpc" "default" { + default = true +} + +data "aws_subnets" "default" { + filter { + name = "default-for-az" + values = [true] + } +} + module "network" { source = "../modules/network" name = var.environment_name From 803617782667d0a9a46231d241dd2cecd4f1f611 Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Tue, 23 Jan 2024 15:52:22 -0800 Subject: [PATCH 21/22] diff reduction From e5eb6073ce86776c4662f7fcf425b2dc72fd382a Mon Sep 17 00:00:00 2001 From: Kai Siren Date: Tue, 23 Jan 2024 15:52:31 -0800 Subject: [PATCH 22/22] diff reduction --- infra/api/database/main.tf | 1 + infra/frontend/service/main.tf | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/infra/api/database/main.tf b/infra/api/database/main.tf index addf5d9a6..bdc7ed116 100644 --- a/infra/api/database/main.tf +++ b/infra/api/database/main.tf @@ -18,6 +18,7 @@ data "aws_subnets" "database" { } } + locals { # The prefix key/value pair is used for Terraform Workspaces, which is useful for projects with multiple infrastructure developers. # By default, Terraform creates a workspace named “default.” If a non-default workspace is not created this prefix will equal “default”, diff --git a/infra/frontend/service/main.tf b/infra/frontend/service/main.tf index 4ae59c007..22d5fb7c2 100644 --- a/infra/frontend/service/main.tf +++ b/infra/frontend/service/main.tf @@ -6,7 +6,7 @@ data "aws_vpc" "network" { } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet data "aws_subnets" "private" { filter { name = "vpc-id" @@ -18,7 +18,7 @@ data "aws_subnets" "private" { } } -# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets +# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet data "aws_subnets" "public" { filter { name = "vpc-id"