diff --git a/routing/availabilty_zones.tf b/routing/availabilty_zones.tf new file mode 120000 index 0000000..8767215 --- /dev/null +++ b/routing/availabilty_zones.tf @@ -0,0 +1 @@ +../common//availabilty_zones.tf \ No newline at end of file diff --git a/routing/data.tf b/routing/data.tf new file mode 120000 index 0000000..995624d --- /dev/null +++ b/routing/data.tf @@ -0,0 +1 @@ +../common/data.tf \ No newline at end of file diff --git a/routing/defaults.tf b/routing/defaults.tf new file mode 120000 index 0000000..a5556ac --- /dev/null +++ b/routing/defaults.tf @@ -0,0 +1 @@ +../common/defaults.tf \ No newline at end of file diff --git a/routing/main.tf b/routing/main.tf new file mode 100644 index 0000000..93e74ee --- /dev/null +++ b/routing/main.tf @@ -0,0 +1,151 @@ +/* +* # About aws-vpc-setup :: routing +* +* This submodule creates route tables, one for private subnets and one for public subnets +* +* # Usage +* +* ```hcl +* module "routing" { +* source = "git@github.e.it.census.gov:terraform-modules/aws-vpc-setup.git//routing" +* vpc_id = var.vpc_id +* vpc_full_name = var.vpc_full_name +* availability_zones = var.availability_zones +* +* vpc_name = var.vpc_name +* vpc_short_name = var.vpc_short_name +* +* vpc_cidr_block = var.vpc_cidr_block +* vpc_index = var.vpc_index +* vpc_environment = var.vpc_environment +* +* tags = {} +* } +*/ + +locals { + account_id = var.account_id != "" ? var.account_id : data.aws_caller_identity.current.account_id + account_environment = data.aws_arn.current.partition == "aws-us-gov" ? "gov" : "ew" + + base_tags = { + "boc:tf_module_version" = local._module_version + "boc:created_by" = "terraform" + } + + availability_zones = length(var.availability_zones) != 0 ? var.availability_zones : data.aws_availability_zones.zones.names + az_count = length(local.availability_zones) + az_count_list = range(local.az_count) + az_list = toset(local.availability_zones) + empty = toset([]) +} + + +#--- +# route table: public +#--- +resource "aws_route_table" "public" { + for_each = local.availability_zones + vpc_id = var.vpc_id + + tags = merge( + local.base_tags, + var.tags, + map("Name", format("%v%v-%v-%v", local._prefixes["route-table"], var.vpc_full_name, "public", each.key)) + ) +} + +resource "aws_route_table_association" "public" { + count = length(local.public_subnets) + subnet_id = aws_subnet.public[count.index].id + route_table_id = element(aws_route_table.public[*].id, count.index) +} + +#--- +# route table: private +#--- +resource "aws_route_table" "private" { + for_each = local.availability_zones + vpc_id = var.vpc_id + + tags = merge( + local.base_tags, + var.tags, + map("Name", format("%v%v-%v-%v", local._prefixes["route-table"], var.vpc_full_name, "private", each.key)) + ) +} + +# resource "aws_route_table" "private" { +# count = local.az_count +# vpc_id = aws_vpc.vpc.id +# # propagating_vgws = var.vpc_vpn_dynamic_routing ? [ aws_vpn_gateway.vpn.id ] : [] +# +# tags = merge( +# local.common_tags, +# map("Name", format("route-%s-%s-%s", var.vpc_full_name, "private", element(local.az_list, count.index))) +# ) +# } + +resource "aws_route_table_association" "private" { + count = length(local.private_subnets) + subnet_id = aws_subnet.private[count.index].id + route_table_id = element(aws_route_table.private[*].id, count.index) +} + + +#--- +# NAT Gateway setup +# EIP +# IGW +# NATGW +#--- +resource "aws_eip" "nat" { + for_each = var.enable_igw && var.enable_nat ? local.availability_zones : local.empty + vpc_id = var.vpc_id + vpc = true + + tags = merge( + local.base_tags, + var.tags, + map("Name", format("%v%v-%v", local._prefixes["elastic-ip"], var.vpc_full_name, each.key)), + ) +} + +resource "aws_internet_gateway" "gateway" { + count = var.enable_igw ? 1 : 0 + vpc_id = var.vpc_id + + tags = merge( + local.base_tags, + var.tags, + map("Name", format("%v%v", local._prefixes["internet-gateway"], var.vpc_full_name)), + ) +} + +# need public subnet ids by az +resource "aws_nat_gateway" "nat" { + for_each = var.enable_igw && var.enable_nat ? local.availability_zones : local.empty + allocation_id = aws_eip.nat[each.key].id + # subnet_id = element(aws_subnet.public[*].id, count.index) + subnet_id = "string" + # depends_on = [aws_internet_gateway.gateway] + + tags = merge( + local.base_tags, + var.tags, + map("Name", format("%v%v-%v", local._prefixes["nat-gateway"], var.vpc_full_name, each.key)), + ) +} + +resource "aws_route" "nat_public" { + for_each = var.enable_igw && var.enable_nat ? local.availability_zones : local.empty + route_table_id = aws_route_table.public[each.key].id + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.gateway[0].id +} + +resource "aws_route" "nat_private" { + for_each = var.enable_igw && var.enable_nat ? local.availability_zones : local.empty + route_table_id = aws_route_table.private[each.key].id + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = aws_nat_gateway.nat[each.key].id +} diff --git a/routing/outputs.tf b/routing/outputs.tf new file mode 100644 index 0000000..3c1e5c2 --- /dev/null +++ b/routing/outputs.tf @@ -0,0 +1,49 @@ +# output "vpc_id" { +# value = aws_vpc.vpc.id +# } +# +# output "vpc_arn" { +# value = aws_vpc.vpc.arn +# } +# +# output "main_route_table_id" { +# value = aws_vpc.vpc.main_route_table_id +# } +# +# output "private_route_table_ids" { +# value = aws_route_table.private[*].id +# } +# output "public_route_table_ids" { +# value = aws_route_table.public[*].id +# } +# +# output "vpc_domain_name" { +# description = "VPC domain name" +# value = var.vpc_domain_name +# } +# +# output "vpc_dns_servers" { +# description = "VPC domain name servers" +# value = var.vpc_dns_servers +# } +# +# output "vpc_info" { +# description = "VPC info" +# value = { +# "vpc_id" = aws_vpc.vpc.id +# "vpc_arn" = aws_vpc.vpc.arn +# "vpc_full_name" = var.vpc_full_name +# "s3_endpoint_id" = aws_vpc_endpoint.s3.id +# "dynamodb_endpoint_id" = aws_vpc_endpoint.dynamodb.id +# } +# } + +output "public_route_table_ids" { + description = "Public route table IDs map by availability zone" + value = { for k in local.availability_zones : k => aws_route_table.public[k].id } +} + +output "private_route_table_ids" { + description = "Private route table IDs map by availability zone" + value = { for k in local.availability_zones : k => aws_route_table.private[k].id } +} diff --git a/routing/prefixes.tf b/routing/prefixes.tf new file mode 120000 index 0000000..7e265d5 --- /dev/null +++ b/routing/prefixes.tf @@ -0,0 +1 @@ +../common/prefixes.tf \ No newline at end of file diff --git a/routing/variables.common.tf b/routing/variables.common.tf new file mode 120000 index 0000000..7439ed8 --- /dev/null +++ b/routing/variables.common.tf @@ -0,0 +1 @@ +../common/variables.common.tf \ No newline at end of file diff --git a/routing/variables.common.vpc.tf b/routing/variables.common.vpc.tf new file mode 120000 index 0000000..5e77d37 --- /dev/null +++ b/routing/variables.common.vpc.tf @@ -0,0 +1 @@ +../common/variables.common.vpc.tf \ No newline at end of file diff --git a/routing/variables.tf b/routing/variables.tf new file mode 100644 index 0000000..f967c45 --- /dev/null +++ b/routing/variables.tf @@ -0,0 +1,109 @@ +variable "vpc_cidr_block" { + description = "VPC CIDR Block" + type = string +} + +variable "enable_vpc_endpoint_s3" { + description = "Flag to enable|disable S3 VPC Endpoint (default: true)" + type = bool + default = true +} + +variable "enable_vpc_endpoint_dynamodb" { + description = "Flag to enable|disable DynamoDB VPC Endpoint (default: true)" + type = bool + default = true +} + +variable "enable_igw" { + description = "Flag to enable AWS Internet Gateway (IGW) in the VPC (default: false)" + type = bool + default = false +} + +variable "enable_nat" { + description = "Flag to enable AWS NAT Gateway in the VPC (default: false)" + type = bool + default = false +} + +### +## +## variable "vpc_domain_name" { +## description = "Domain Name" +## default = "csp1.census.gov" +## } +## +## variable "dhcp_vpc_domain_name" { +## description = "Domain Name for DHCP Options" +## default = "compute.csp1.census.gov" +## } +## +## variable "vpc_dns_servers" { +## description = "Enterprise DNS Servers" +## # default = ["10.193.0.22", "10.193.2.22" ] +## default = ["148.129.127.22", "148.129.191.22"] +## # add 10.193.0.22, 10.193.2.22 +## } +## +## variable "vpc_ntp_servers" { +## description = "Enterprise NTP Servers" +## default = ["148.129.127.23", "148.129.191.23"] +## } +## +## variable "network_census" { +## description = "Census Subnets" +## type = list +## default = ["148.129.0.0/16", "172.16.0.0/12", "192.168.0.0/16"] +## } +## +## variable "network_peers" { +## description = "Census AWS Peer Subnets" +## type = list +## default = ["10.193.0.0/19"] +## # default = [ ] +## } +## +## variable "vpn_connections" { +## description = "VPN Connection Details" +## type = map +## } +## +## variable "vpc_vpn_dynamic_routing" { +## description = "Dyanmic routing with BGP (true | false)" +## type = bool +## } +## +## variable "vpc_enable_igw" { +## description = "Enable AWS Internet Gateway (IGW) on the VPC (true | false[x])" +## type = bool +## default = false +## } +## +## variable "vpc_enable_nat" { +## description = "Enable AWS NAT Gateway on the VPC (true | false[x])" +## type = bool +## default = false +## } +## +## variable "vpc_enable_vpn" { +## description = "Enable AWS VPN Configuration on the VPC (true[x] | false)" +## type = bool +## default = true +## } +## +## # bits is the extra size of the bits from the subnet, which is split from the size of the vpc cidr +## # vpc_cidr = /19 +## # cidr_subnets defines values (19 + N) +## # this bits gets you (19 + N + bits) +## # example: /19 vpc cidr, 3 for cidr means a /22 (19+3) and then 2 for bits means /24 +## variable "subnet_maps" { +## description = "Subnet objects" +## type = list(object( +## { +## label = string +## bits = number +## private = bool +## })) +## } + diff --git a/routing/version.tf b/routing/version.tf new file mode 120000 index 0000000..b83c5b7 --- /dev/null +++ b/routing/version.tf @@ -0,0 +1 @@ +../common/version.tf \ No newline at end of file diff --git a/routing/vpc-endpoints.tf b/routing/vpc-endpoints.tf new file mode 100644 index 0000000..227d27a --- /dev/null +++ b/routing/vpc-endpoints.tf @@ -0,0 +1,53 @@ +#--- +# vpc endpoint: s3 +#--- +data "aws_vpc_endpoint_service" "s3" { + service = "s3" + # service_name = "com.amazonaws.${local.region}.s3" + filter { + name = "service-type" + values = ["Gateway"] + } +} + +resource "aws_vpc_endpoint" "s3" { + vpc_id = aws_vpc.vpc.id + service_name = data.aws_vpc_endpoint_service.s3.service_name + depends_on = [aws_vpc.vpc] + + tags = merge( + local.common_tags, + map("Name", "vpce-s3-${var.vpc_full_name}-"), + ) +} + +resource "aws_vpc_endpoint_route_table_association" "private_s3" { + count = length(aws_route_table.private[*].id) + vpc_endpoint_id = aws_vpc_endpoint.s3.id + route_table_id = element(aws_route_table.private[*].id, count.index) +} + +#--- +# vpc endpoint: dynamodb +#--- +data "aws_vpc_endpoint_service" "dynamodb" { + service = "dynamodb" + # service_name = "com.amazonaws.${local.region}.dynamodb" +} + +resource "aws_vpc_endpoint" "dynamodb" { + vpc_id = aws_vpc.vpc.id + service_name = data.aws_vpc_endpoint_service.dynamodb.service_name + depends_on = [aws_vpc.vpc] + + tags = merge( + local.common_tags, + map("Name", "vpce-dynamodb-${var.vpc_full_name}-"), + ) +} + +resource "aws_vpc_endpoint_route_table_association" "private_dynamodb" { + count = length(aws_route_table.private[*].id) + vpc_endpoint_id = aws_vpc_endpoint.s3.id + route_table_id = element(aws_route_table.private[*].id, count.index) +} diff --git a/routing/vpc-nat.tf.x b/routing/vpc-nat.tf.x new file mode 100644 index 0000000..82572a3 --- /dev/null +++ b/routing/vpc-nat.tf.x @@ -0,0 +1,51 @@ +resource "aws_eip" "nat" { + count = var.vpc_enable_igw && var.vpc_enable_nat ? local.az_count : 0 + vpc = true + + tags = merge( + local.common_tags, + map("Name", format("eip-%s-%s", var.vpc_full_name, element(local.az_list, count.index))) + ) +} + +resource "aws_internet_gateway" "gateway" { + count = var.vpc_enable_igw ? 1 : 0 + vpc_id = aws_vpc.vpc.id + + tags = merge( + local.common_tags, + map("Name", "igw-${var.vpc_full_name}"), + ) +} + +resource "aws_nat_gateway" "nat" { + count = var.vpc_enable_igw && var.vpc_enable_nat ? local.az_count : 0 + # count = local.az_count + allocation_id = aws_eip.nat[count.index].id + subnet_id = element(aws_subnet.public[*].id, count.index) + depends_on = [aws_internet_gateway.gateway] + + tags = merge( + local.common_tags, + map("Name", format("nat-%s-%s", var.vpc_full_name, element(local.az_list, count.index))) + ) +} + +resource "aws_route" "nat_public" { + count = var.vpc_enable_igw && var.vpc_enable_nat ? length(aws_route_table.public[*].id) : 0 + # count = length(aws_route_table.public[*].id) + # count = 0 + route_table_id = element(aws_route_table.public[*].id, count.index) + destination_cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.gateway[0].id + depends_on = [aws_route_table.public, aws_internet_gateway.gateway] +} + +resource "aws_route" "nat_private" { + count = var.vpc_enable_igw && var.vpc_enable_nat ? length(aws_route_table.private[*].id) : 0 + # count = length(aws_route_table.private[*].id) + route_table_id = element(aws_route_table.private[*].id, count.index) + destination_cidr_block = "0.0.0.0/0" + nat_gateway_id = element(aws_nat_gateway.nat[*].id, count.index) + depends_on = [aws_route_table.private, aws_nat_gateway.nat] +} diff --git a/routing/vpc-peers.tf.disabled b/routing/vpc-peers.tf.disabled new file mode 100644 index 0000000..36493c6 --- /dev/null +++ b/routing/vpc-peers.tf.disabled @@ -0,0 +1,137 @@ +# no peer1 on vpc1-shared +#--- +# local account shared peer vpc peer1 +#--- + +locals { + vpc_id_me = aws_vpc.vpc.id + cidr_block_me = var.vpc_cidr_block + short_me = split(",", var.vpc_full_name) + route_tables_me = tolist(data.aws_route_tables.me.ids) + + vpc_id_peer2 = var.vpc_peer2 + cidr_block_peer2 = data.aws_vpc.peer2.cidr_block + # short_peer2 = [ "${var.account_id_peer2}_${var.vpc_peer2}" ] + short_peer2 = ["${var.account_id_peer2}_${var.vpc_tag_peer2}"] + route_tables_peer2 = tolist(data.aws_route_tables.peer2.ids) + label_peer2 = format("vpcp-%s:%s", local.short_me[0], local.short_peer2[0]) +} + +#--- +# peer2 +#--- +data "aws_vpc" "peer2" { + provider = aws.peer2 + id = local.vpc_id_peer2 +} + +#--- +# private route tables, local and peer +#--- +data "aws_route_tables" "me" { + provider = aws + vpc_id = local.vpc_id_me + filter { + name = "tag:Name" + values = ["*-private-*"] + } +} + +data "aws_route_tables" "peer2" { + provider = aws.peer2 + vpc_id = local.vpc_id_peer2 + filter { + name = "tag:Name" + values = ["*${var.vpc_tag_peer2}*private*", "*${var.vpc_tag_peer2}"] + } +} + +resource "aws_vpc_peering_connection" "me_peer2" { + provider = aws + vpc_id = local.vpc_id_me + peer_vpc_id = local.vpc_id_peer2 + peer_owner_id = var.account_id_peer2 + peer_region = var.region_peer2 + auto_accept = false + + # accepter { + # allow_remote_vpc_dns_resolution = false + # allow_classic_link_to_remote_vpc = false + # allow_vpc_to_remote_classic_link = false + # } + # requester { + # allow_remote_vpc_dns_resolution = false + # allow_classic_link_to_remote_vpc = false + # allow_vpc_to_remote_classic_link = false + # } + + tags = merge( + local.common_tags, + map("Name", local.label_peer2), + ) +} + + +resource "aws_vpc_peering_connection_accepter" "me_peer2" { + provider = aws.peer2 + vpc_peering_connection_id = aws_vpc_peering_connection.me_peer2.id + auto_accept = true + # depends_on = ["aws_vpc_peering_connection.me_peer2"] + + # accepter { + # allow_remote_vpc_dns_resolution = false + # allow_classic_link_to_remote_vpc = false + # allow_vpc_to_remote_classic_link = false + # } + # requester { + # allow_remote_vpc_dns_resolution = false + # allow_classic_link_to_remote_vpc = false + # allow_vpc_to_remote_classic_link = false + # } + + # accepter { + # allow_remote_vpc_dns_resolution = true + # } + # tags { + # Name = "vpcp-do2cat-vpc3_do3ma1ew-vpc1" + # Environment = "infrastructure" + # CostAllocation = "csvd:inf" + # Creator = "${var.tag_creator}" + # } + tags = merge( + local.common_tags, + map("Name", local.label_peer2), + ) +} + +# local routes +resource "aws_route" "me_peer2" { + provider = aws + count = length(data.aws_route_tables.me.ids) + # route_table_id = data.aws_route_tables.me.ids[count.index] + route_table_id = local.route_tables_me[count.index] + destination_cidr_block = local.cidr_block_peer2 + vpc_peering_connection_id = aws_vpc_peering_connection.me_peer2.id +} + +# peer routes +resource "aws_route" "peer2_me" { + provider = aws.peer2 + count = length(data.aws_route_tables.peer2.ids) + # route_table_id = data.aws_route_tables.peer2.ids[count.index] + route_table_id = local.route_tables_peer2[count.index] + destination_cidr_block = local.cidr_block_me + vpc_peering_connection_id = aws_vpc_peering_connection.me_peer2.id +} + +# output "rt_me" { +# value = data.aws_route_tables.me.ids +# } +# output "rt_peer1" { +# value = data.aws_route_tables.peer1.ids +# } +# +# output "rt_peer2" { +# value = data.aws_route_tables.peer2.ids +# } + diff --git a/routing/vpc.tf.x b/routing/vpc.tf.x new file mode 100644 index 0000000..9d1fa16 --- /dev/null +++ b/routing/vpc.tf.x @@ -0,0 +1,83 @@ +#--- +# dhcp options +#--- +resource "aws_vpc_dhcp_options" "vpc" { + domain_name = var.dhcp_vpc_domain_name == "" ? var.vpc_domain_name : var.dhcp_vpc_domain_name + domain_name_servers = var.vpc_dns_servers + ntp_servers = var.vpc_ntp_servers + + tags = merge( + local.common_tags, + map("Name", "${var.vpc_full_name}-dhcp-options"), + ) +} + +resource "aws_vpc_dhcp_options_association" "vpc" { + vpc_id = aws_vpc.vpc.id + dhcp_options_id = aws_vpc_dhcp_options.vpc.id +} + +#--- +# vpc +#--- +resource "aws_vpc" "vpc" { + cidr_block = var.vpc_cidr_block + enable_dns_support = false + enable_dns_hostnames = true + + tags = merge( + local.common_tags, + map("Name", "${var.vpc_full_name}"), + ) +} + +#--- +# route table: main +#--- +resource "aws_default_route_table" "vpc" { + default_route_table_id = aws_vpc.vpc.main_route_table_id + + tags = merge( + local.common_tags, + map("Name", format("default-rt-%s", var.vpc_full_name)) + ) +} + +#--- +# route table: public +#--- +resource "aws_route_table" "public" { + count = local.az_count + vpc_id = aws_vpc.vpc.id + + tags = merge( + local.common_tags, + map("Name", format("route-%s-%s-%s", var.vpc_full_name, "public", element(local.az_list, count.index))) + ) +} + +resource "aws_route_table_association" "public" { + count = length(local.public_subnets) + subnet_id = aws_subnet.public[count.index].id + route_table_id = element(aws_route_table.public[*].id, count.index) +} + +#--- +# route table: private +#--- +resource "aws_route_table" "private" { + count = local.az_count + vpc_id = aws_vpc.vpc.id + # propagating_vgws = var.vpc_vpn_dynamic_routing ? [ aws_vpn_gateway.vpn.id ] : [] + + tags = merge( + local.common_tags, + map("Name", format("route-%s-%s-%s", var.vpc_full_name, "private", element(local.az_list, count.index))) + ) +} + +resource "aws_route_table_association" "private" { + count = length(local.private_subnets) + subnet_id = aws_subnet.private[count.index].id + route_table_id = element(aws_route_table.private[*].id, count.index) +}