diff --git a/blueprints/apigee/network-patterns/nb-glb-psc-neg-sb-psc-ilbl7-hybrid-neg/vpn.tf b/blueprints/apigee/network-patterns/nb-glb-psc-neg-sb-psc-ilbl7-hybrid-neg/vpn.tf index c39878d1..1086f19c 100644 --- a/blueprints/apigee/network-patterns/nb-glb-psc-neg-sb-psc-ilbl7-hybrid-neg/vpn.tf +++ b/blueprints/apigee/network-patterns/nb-glb-psc-neg-sb-psc-ilbl7-hybrid-neg/vpn.tf @@ -32,8 +32,8 @@ module "apigee_vpn" { mode = "CUSTOM" } } - peer_gateway = { - gcp = module.onprem_vpn.self_link + peer_gateways = { + default = { gcp = module.onprem_vpn.self_link } } tunnels = { 0 = { @@ -82,8 +82,8 @@ module "onprem_vpn" { mode = "CUSTOM" } } - peer_gateway = { - gcp = module.apigee_vpn.self_link + peer_gateways = { + default = { gcp = module.apigee_vpn.self_link } } tunnels = { 0 = { diff --git a/blueprints/networking/hub-and-spoke-vpn/vpn-dev-r1.tf b/blueprints/networking/hub-and-spoke-vpn/vpn-dev-r1.tf index 4d1236bb..49ced394 100644 --- a/blueprints/networking/hub-and-spoke-vpn/vpn-dev-r1.tf +++ b/blueprints/networking/hub-and-spoke-vpn/vpn-dev-r1.tf @@ -27,7 +27,9 @@ module "landing-to-dev-vpn-r1" { name = "${var.prefix}-lnd-vpn-r1" asn = 64514 } - peer_gateway = { gcp = module.dev-to-landing-vpn-r1.self_link } + peer_gateways = { + default = { gcp = module.dev-to-landing-vpn-r1.self_link } + } tunnels = { 0 = { bgp_peer = { @@ -63,7 +65,9 @@ module "dev-to-landing-vpn-r1" { mode = "CUSTOM" } } - peer_gateway = { gcp = module.landing-to-dev-vpn-r1.self_link } + peer_gateways = { + default = { gcp = module.landing-to-dev-vpn-r1.self_link } + } tunnels = { 0 = { bgp_peer = { diff --git a/blueprints/networking/hub-and-spoke-vpn/vpn-prod-r1.tf b/blueprints/networking/hub-and-spoke-vpn/vpn-prod-r1.tf index 8e633686..8c025d9e 100644 --- a/blueprints/networking/hub-and-spoke-vpn/vpn-prod-r1.tf +++ b/blueprints/networking/hub-and-spoke-vpn/vpn-prod-r1.tf @@ -28,7 +28,9 @@ module "landing-to-prod-vpn-r1" { ip_ranges = coalesce(var.vpn_configs.land-r1.custom_ranges, {}) } } - peer_gateway = { gcp = module.prod-to-landing-vpn-r1.self_link } + peer_gateways = { + default = { gcp = module.prod-to-landing-vpn-r1.self_link } + } tunnels = { 0 = { bgp_peer = { @@ -64,7 +66,9 @@ module "prod-to-landing-vpn-r1" { ip_ranges = coalesce(var.vpn_configs.prod-r1.custom_ranges, {}) } } - peer_gateway = { gcp = module.landing-to-prod-vpn-r1.self_link } + peer_gateways = { + default = { gcp = module.landing-to-prod-vpn-r1.self_link } + } tunnels = { 0 = { bgp_peer = { diff --git a/blueprints/networking/private-cloud-function-from-onprem/main.tf b/blueprints/networking/private-cloud-function-from-onprem/main.tf index 1848e953..49bab252 100644 --- a/blueprints/networking/private-cloud-function-from-onprem/main.tf +++ b/blueprints/networking/private-cloud-function-from-onprem/main.tf @@ -86,7 +86,9 @@ module "vpn-onprem" { ip_ranges = {} } } - peer_gateway = { gcp = module.vpn-hub.self_link } + peer_gateways = { + default = { gcp = module.vpn-hub.self_link } + } tunnels = { tunnel-0 = { bgp_peer = { @@ -122,7 +124,9 @@ module "vpn-hub" { } } } - peer_gateway = { gcp = module.vpn-onprem.self_link } + peer_gateways = { + default = { gcp = module.vpn-onprem.self_link } + } tunnels = { tunnel-0 = { diff --git a/blueprints/serverless/cloud-run-corporate/main.tf b/blueprints/serverless/cloud-run-corporate/main.tf index 88f853d7..5eb98029 100644 --- a/blueprints/serverless/cloud-run-corporate/main.tf +++ b/blueprints/serverless/cloud-run-corporate/main.tf @@ -540,13 +540,15 @@ module "vpc_sc" { # VPN between main project and "onprem" environment module "vpn_main" { - source = "../../../modules/net-vpn-ha" - count = length(module.project_onprem) - project_id = module.project_main.project_id - region = var.region - network = module.vpc_main.self_link - name = "vpn-main-to-onprem" - peer_gateway = { gcp = module.vpn_onprem[0].self_link } + source = "../../../modules/net-vpn-ha" + count = length(module.project_onprem) + project_id = module.project_main.project_id + region = var.region + network = module.vpc_main.self_link + name = "vpn-main-to-onprem" + peer_gateways = { + default = { gcp = module.vpn_onprem[0].self_link } + } router_config = { asn = 65001 custom_advertise = { @@ -577,13 +579,15 @@ module "vpn_main" { } module "vpn_onprem" { - source = "../../../modules/net-vpn-ha" - count = length(module.project_onprem) - project_id = module.project_onprem[0].project_id - region = var.region - network = module.vpc_onprem[0].self_link - name = "vpn-onprem-to-main" - peer_gateway = { gcp = module.vpn_main[0].self_link } + source = "../../../modules/net-vpn-ha" + count = length(module.project_onprem) + project_id = module.project_onprem[0].project_id + region = var.region + network = module.vpc_onprem[0].self_link + name = "vpn-onprem-to-main" + peer_gateways = { + default = { gcp = module.vpn_main[0].self_link } + } router_config = { asn = 65002 } tunnels = { tunnel-0 = { diff --git a/fast/stages/2-networking-a-peering/vpn-onprem.tf b/fast/stages/2-networking-a-peering/vpn-onprem.tf index a04a0097..2e9f3c24 100644 --- a/fast/stages/2-networking-a-peering/vpn-onprem.tf +++ b/fast/stages/2-networking-a-peering/vpn-onprem.tf @@ -48,8 +48,10 @@ module "landing-to-onprem-primary-vpn" { name = "landing-onprem-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_onprem_configs.landing-primary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.landing-primary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.landing-primary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.landing-primary.tunnels : diff --git a/fast/stages/2-networking-b-vpn/vpn-onprem.tf b/fast/stages/2-networking-b-vpn/vpn-onprem.tf index a04a0097..2e9f3c24 100644 --- a/fast/stages/2-networking-b-vpn/vpn-onprem.tf +++ b/fast/stages/2-networking-b-vpn/vpn-onprem.tf @@ -48,8 +48,10 @@ module "landing-to-onprem-primary-vpn" { name = "landing-onprem-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_onprem_configs.landing-primary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.landing-primary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.landing-primary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.landing-primary.tunnels : diff --git a/fast/stages/2-networking-b-vpn/vpn-spoke-dev.tf b/fast/stages/2-networking-b-vpn/vpn-spoke-dev.tf index 09cc31e0..97adc642 100644 --- a/fast/stages/2-networking-b-vpn/vpn-spoke-dev.tf +++ b/fast/stages/2-networking-b-vpn/vpn-spoke-dev.tf @@ -50,7 +50,9 @@ module "landing-to-dev-primary-vpn" { name = "landing-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_spoke_configs.landing-primary.asn } - peer_gateway = { gcp = module.dev-to-landing-primary-vpn.self_link } + peer_gateways = { + default = { gcp = module.dev-to-landing-primary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { @@ -95,7 +97,9 @@ module "dev-to-landing-primary-vpn" { name = "dev-spoke-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_spoke_configs.spoke-dev-primary.asn } - peer_gateway = { gcp = module.landing-to-dev-primary-vpn.self_link } + peer_gateways = { + default = { gcp = module.landing-to-dev-primary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { diff --git a/fast/stages/2-networking-b-vpn/vpn-spoke-prod-primary.tf b/fast/stages/2-networking-b-vpn/vpn-spoke-prod-primary.tf index 071b1d05..9d36c16e 100644 --- a/fast/stages/2-networking-b-vpn/vpn-spoke-prod-primary.tf +++ b/fast/stages/2-networking-b-vpn/vpn-spoke-prod-primary.tf @@ -33,7 +33,9 @@ module "landing-to-prod-primary-vpn" { name = "landing-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_spoke_configs.landing-primary.asn } - peer_gateway = { gcp = module.prod-to-landing-primary-vpn.self_link } + peer_gateways = { + default = { gcp = module.prod-to-landing-primary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { @@ -75,7 +77,9 @@ module "prod-to-landing-primary-vpn" { name = "prod-spoke-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_spoke_configs.spoke-prod-primary.asn } - peer_gateway = { gcp = module.landing-to-prod-primary-vpn.self_link } + peer_gateways = { + default = { gcp = module.landing-to-prod-primary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { diff --git a/fast/stages/2-networking-b-vpn/vpn-spoke-prod-secondary.tf b/fast/stages/2-networking-b-vpn/vpn-spoke-prod-secondary.tf index a7c0e0fe..a3ee9e9f 100644 --- a/fast/stages/2-networking-b-vpn/vpn-spoke-prod-secondary.tf +++ b/fast/stages/2-networking-b-vpn/vpn-spoke-prod-secondary.tf @@ -33,7 +33,9 @@ module "landing-to-prod-secondary-vpn" { name = "landing-vpn-${local.region_shortnames[var.regions.secondary]}" asn = var.router_spoke_configs.landing-secondary.asn } - peer_gateway = { gcp = module.prod-to-landing-secondary-vpn.self_link } + peer_gateways = { + default = { gcp = module.prod-to-landing-secondary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { @@ -75,7 +77,9 @@ module "prod-to-landing-secondary-vpn" { name = "prod-spoke-vpn-${local.region_shortnames[var.regions.secondary]}" asn = var.router_spoke_configs.spoke-prod-secondary.asn } - peer_gateway = { gcp = module.landing-to-prod-secondary-vpn.self_link } + peer_gateways = { + default = { gcp = module.landing-to-prod-secondary-vpn.self_link } + } tunnels = { 0 = { bgp_peer = { diff --git a/fast/stages/2-networking-c-nva/vpn-onprem.tf b/fast/stages/2-networking-c-nva/vpn-onprem.tf index 57f2024a..31adbe71 100644 --- a/fast/stages/2-networking-c-nva/vpn-onprem.tf +++ b/fast/stages/2-networking-c-nva/vpn-onprem.tf @@ -51,8 +51,10 @@ module "landing-to-onprem-primary-vpn" { name = "landing-onprem-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_configs.landing-trusted-primary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.landing-trusted-primary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.landing-trusted-primary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.landing-trusted-primary.tunnels : @@ -85,8 +87,10 @@ module "landing-to-onprem-secondary-vpn" { name = "landing-onprem-vpn-${local.region_shortnames[var.regions.secondary]}" asn = var.router_configs.landing-trusted-secondary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.landing-trusted-secondary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.landing-trusted-secondary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.landing-trusted-secondary.tunnels : diff --git a/fast/stages/2-networking-d-separate-envs/vpn-onprem-dev.tf b/fast/stages/2-networking-d-separate-envs/vpn-onprem-dev.tf index e95cd14f..c5269c4d 100644 --- a/fast/stages/2-networking-d-separate-envs/vpn-onprem-dev.tf +++ b/fast/stages/2-networking-d-separate-envs/vpn-onprem-dev.tf @@ -48,8 +48,10 @@ module "dev-to-onprem-primary-vpn" { name = "dev-onprem-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_onprem_configs.dev-primary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.dev-primary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.dev-primary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.dev-primary.tunnels : diff --git a/fast/stages/2-networking-d-separate-envs/vpn-onprem-prod.tf b/fast/stages/2-networking-d-separate-envs/vpn-onprem-prod.tf index 0793e274..760ba4e5 100644 --- a/fast/stages/2-networking-d-separate-envs/vpn-onprem-prod.tf +++ b/fast/stages/2-networking-d-separate-envs/vpn-onprem-prod.tf @@ -32,8 +32,10 @@ module "prod-to-onprem-primary-vpn" { name = "prod-onprem-vpn-${local.region_shortnames[var.regions.primary]}" asn = var.router_onprem_configs.prod-primary.asn } - peer_gateway = { - external = var.vpn_onprem_configs.prod-primary.peer_external_gateway + peer_gateways = { + default = { + external = var.vpn_onprem_configs.prod-primary.peer_external_gateway + } } tunnels = { for t in var.vpn_onprem_configs.prod-primary.tunnels : diff --git a/modules/net-vpn-ha/README.md b/modules/net-vpn-ha/README.md index 0b7b5290..8bbac84d 100644 --- a/modules/net-vpn-ha/README.md +++ b/modules/net-vpn-ha/README.md @@ -1,17 +1,21 @@ # Cloud HA VPN Module + This module makes it easy to deploy either GCP-to-GCP or GCP-to-On-prem [Cloud HA VPN](https://cloud.google.com/vpn/docs/concepts/overview#ha-vpn). ## Examples ### GCP to GCP + ```hcl module "vpn-1" { - source = "./fabric/modules/net-vpn-ha" - project_id = var.project_id - region = "europe-west4" - network = var.vpc1.self_link - name = "net1-to-net-2" - peer_gateway = { gcp = module.vpn-2.self_link } + source = "./fabric/modules/net-vpn-ha" + project_id = var.project_id + region = "europe-west4" + network = var.vpc1.self_link + name = "net1-to-net-2" + peer_gateways = { + default = { gcp = module.vpn-2.self_link } + } router_config = { asn = 64514 custom_advertise = { @@ -48,7 +52,9 @@ module "vpn-2" { network = var.vpc2.self_link name = "net2-to-net1" router_config = { asn = 64513 } - peer_gateway = { gcp = module.vpn-1.self_link } + peer_gateways = { + default = { gcp = module.vpn-1.self_link } + } tunnels = { remote-0 = { bgp_peer = { @@ -84,10 +90,12 @@ module "vpn_ha" { region = var.region network = var.vpc.self_link name = "mynet-to-onprem" - peer_gateway = { - external = { - redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" - interfaces = ["8.8.8.8"] # on-prem router ip address + peer_gateways = { + default = { + external = { + redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" + interfaces = ["8.8.8.8"] # on-prem router ip address + } } } router_config = { asn = 64514 } @@ -124,13 +132,13 @@ module "vpn_ha" { |---|---|:---:|:---:|:---:| | [name](variables.tf#L17) | VPN Gateway name (if an existing VPN Gateway is not used), and prefix used for dependent resources. | string | ✓ | | | [network](variables.tf#L22) | VPC used for the gateway and routes. | string | ✓ | | -| [peer_gateway](variables.tf#L27) | Configuration of the (external or GCP) peer gateway. | object({…}) | ✓ | | -| [project_id](variables.tf#L43) | Project where resources will be created. | string | ✓ | | -| [region](variables.tf#L48) | Region used for resources. | string | ✓ | | -| [router_config](variables.tf#L53) | Cloud Router configuration for the VPN. If you want to reuse an existing router, set create to false and use name to specify the desired router. | object({…}) | ✓ | | -| [tunnels](variables.tf#L68) | VPN tunnel configurations. | map(object({…})) | | {} | -| [vpn_gateway](variables.tf#L95) | HA VPN Gateway Self Link for using an existing HA VPN Gateway. Ignored if `vpn_gateway_create` is set to `true`. | string | | null | -| [vpn_gateway_create](variables.tf#L101) | Create HA VPN Gateway. | bool | | true | +| [project_id](variables.tf#L46) | Project where resources will be created. | string | ✓ | | +| [region](variables.tf#L51) | Region used for resources. | string | ✓ | | +| [router_config](variables.tf#L56) | Cloud Router configuration for the VPN. If you want to reuse an existing router, set create to false and use name to specify the desired router. | object({…}) | ✓ | | +| [peer_gateways](variables.tf#L27) | Configuration of the (external or GCP) peer gateway. | map(object({…})) | | {} | +| [tunnels](variables.tf#L71) | VPN tunnel configurations. | map(object({…})) | | {} | +| [vpn_gateway](variables.tf#L99) | HA VPN Gateway Self Link for using an existing HA VPN Gateway. Ignored if `vpn_gateway_create` is set to `true`. | string | | null | +| [vpn_gateway_create](variables.tf#L105) | Create HA VPN Gateway. | bool | | true | ## Outputs diff --git a/modules/net-vpn-ha/main.tf b/modules/net-vpn-ha/main.tf index 9d53ee08..1925cdfc 100644 --- a/modules/net-vpn-ha/main.tf +++ b/modules/net-vpn-ha/main.tf @@ -16,6 +16,12 @@ */ locals { + peer_gateways_external = { + for k, v in var.peer_gateways : k => v.external if v.external != null + } + peer_gateways_gcp = { + for k, v in var.peer_gateways : k => v.gcp if v.gcp != null + } router = ( var.router_config.create ? try(google_compute_router.router[0].name, null) @@ -38,13 +44,13 @@ resource "google_compute_ha_vpn_gateway" "ha_gateway" { } resource "google_compute_external_vpn_gateway" "external_gateway" { - count = var.peer_gateway.external != null ? 1 : 0 - name = "external-${var.name}" + for_each = local.peer_gateways_external + name = "${var.name}-${each.key}" project = var.project_id - redundancy_type = var.peer_gateway.external.redundancy_type + redundancy_type = each.value.redundancy_type description = "Terraform managed external VPN gateway" dynamic "interface" { - for_each = var.peer_gateway.external.interfaces + for_each = each.value.interfaces content { id = interface.key ip_address = interface.value @@ -124,18 +130,23 @@ resource "google_compute_router_interface" "router_interface" { } resource "google_compute_vpn_tunnel" "tunnels" { - for_each = var.tunnels - project = var.project_id - region = var.region - name = "${var.name}-${each.key}" - router = local.router - peer_external_gateway = one(google_compute_external_vpn_gateway.external_gateway[*].self_link) + for_each = var.tunnels + project = var.project_id + region = var.region + name = "${var.name}-${each.key}" + router = local.router + peer_external_gateway = try( + google_compute_external_vpn_gateway.external_gateway[each.value.peer_gateway], + null + ) peer_external_gateway_interface = each.value.peer_external_gateway_interface - peer_gcp_gateway = var.peer_gateway.gcp - vpn_gateway_interface = each.value.vpn_gateway_interface - ike_version = each.value.ike_version - shared_secret = coalesce(each.value.shared_secret, local.secret) - vpn_gateway = local.vpn_gateway + peer_gcp_gateway = lookup( + local.peer_gateways_gcp, each.value.peer_gateway, null + ) + vpn_gateway_interface = each.value.vpn_gateway_interface + ike_version = each.value.ike_version + shared_secret = coalesce(each.value.shared_secret, local.secret) + vpn_gateway = local.vpn_gateway } resource "random_id" "secret" { diff --git a/modules/net-vpn-ha/variables.tf b/modules/net-vpn-ha/variables.tf index a423eab1..b12c4cdc 100644 --- a/modules/net-vpn-ha/variables.tf +++ b/modules/net-vpn-ha/variables.tf @@ -24,18 +24,21 @@ variable "network" { type = string } -variable "peer_gateway" { +variable "peer_gateways" { description = "Configuration of the (external or GCP) peer gateway." - type = object({ + type = map(object({ external = optional(object({ redundancy_type = string interfaces = list(string) })) gcp = optional(string) - }) + })) nullable = false + default = {} validation { - condition = (var.peer_gateway.external != null) != (var.peer_gateway.gcp != null) + condition = alltrue([ + for k, v in var.peer_gateways : (v.external != null) != (v.gcp != null) + ]) error_message = "Peer gateway configuration must define exactly one between `external` and `gcp`." } } @@ -84,6 +87,7 @@ variable "tunnels" { bgp_session_range = string ike_version = optional(number, 2) peer_external_gateway_interface = optional(number) + peer_gateway = optional(string, "default") router = optional(string) shared_secret = optional(string) vpn_gateway_interface = number