Make Cloud NAT creation optional in FAST net stages. (#2038)
* Make Cloud NAT creation optional in FAST net stages. Fixes #2021 * Update READMEs
This commit is contained in:
parent
5ae2f6987d
commit
13636ba07b
|
@ -101,7 +101,7 @@ In this setup:
|
|||
|
||||
### Internet egress
|
||||
|
||||
The path of least resistance for Internet egress is using Cloud NAT, and that is what's implemented in this setup, with a NAT gateway configured for each VPC.
|
||||
Cloud NAT provides the simplest path for internet egress. This setup uses Cloud NAT, with optional per-VPC NAT gateways. Cloud NAT is disabled by default; enable it by setting the `enable_cloud_nat` variable.
|
||||
|
||||
Several other scenarios are possible of course, with varying degrees of complexity:
|
||||
|
||||
|
@ -389,20 +389,21 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L103) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L123) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L139) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L110) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L130) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L146) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | DNS configuration. | <code title="object({ enable_logging = optional(bool, true) resolvers = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L82) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L113) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L133) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | <code>bool</code> | | <code>false</code> | |
|
||||
| [factories_config](variables.tf#L89) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L120) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L140) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [peering_configs](variables-peerings.tf#L19) | Peering configurations. | <code title="object({ dev = optional(object({ export = optional(bool, true) import = optional(bool, true) public_export = optional(bool) public_import = optional(bool) }), {}) prod = optional(object({ export = optional(bool, true) import = optional(bool, true) public_export = optional(bool) public_import = optional(bool) }), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [psa_ranges](variables.tf#L150) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L169) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L181) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L195) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L157) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L176) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L188) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L202) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -95,8 +95,8 @@ module "dev-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "dev-spoke-cloudnat" {
|
||||
for_each = toset(values(module.dev-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.dev-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.dev-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "dev-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -80,6 +80,7 @@ moved {
|
|||
|
||||
module "landing-nat-primary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.primary
|
||||
name = local.region_shortnames[var.regions.primary]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -93,8 +93,8 @@ module "prod-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "prod-spoke-cloudnat" {
|
||||
for_each = toset(values(module.prod-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.prod-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.prod-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "prod-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -79,6 +79,13 @@ variable "dns" {
|
|||
nullable = false
|
||||
}
|
||||
|
||||
variable "enable_cloud_nat" {
|
||||
description = "Deploy Cloud NAT."
|
||||
type = bool
|
||||
default = false
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Configuration for network resource factories."
|
||||
type = object({
|
||||
|
|
|
@ -107,7 +107,7 @@ As is evident from the table above, the hub/landing VPC acts as the route concen
|
|||
|
||||
### Internet egress
|
||||
|
||||
The path of least resistance for Internet egress is using Cloud NAT, and that is what's implemented in this setup, with a NAT gateway configured for each VPC.
|
||||
Cloud NAT provides the simplest path for internet egress. This setup uses Cloud NAT, with optional per-VPC NAT gateways. Cloud NAT is disabled by default; enable it by setting the `enable_cloud_nat` variable.
|
||||
|
||||
Several other scenarios are possible of course, with varying degrees of complexity:
|
||||
|
||||
|
@ -413,20 +413,21 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L103) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L123) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L139) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L110) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L130) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L146) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | DNS configuration. | <code title="object({ enable_logging = optional(bool, true) resolvers = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L82) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L113) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L133) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L150) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L169) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L181) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | <code>bool</code> | | <code>false</code> | |
|
||||
| [factories_config](variables.tf#L89) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L120) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L140) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L157) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L176) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L188) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_configs](variables-vpn.tf#L17) | Hub to spokes VPN configurations. | <code title="object({ dev = optional(object({ asn = optional(number, 65501) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }), {}) landing = optional(object({ asn = optional(number, 65500) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }), {}) prod = optional(object({ asn = optional(number, 65502) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [vpn_onprem_primary_config](variables.tf#L195) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_primary_config](variables.tf#L202) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -95,8 +95,8 @@ module "dev-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "dev-spoke-cloudnat" {
|
||||
for_each = toset(values(module.dev-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.dev-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.dev-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "dev-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -80,6 +80,7 @@ moved {
|
|||
|
||||
module "landing-nat-primary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.primary
|
||||
name = local.region_shortnames[var.regions.primary]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -93,8 +93,8 @@ module "prod-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "prod-spoke-cloudnat" {
|
||||
for_each = toset(values(module.prod-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.prod-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.prod-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "prod-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -79,6 +79,13 @@ variable "dns" {
|
|||
nullable = false
|
||||
}
|
||||
|
||||
variable "enable_cloud_nat" {
|
||||
description = "Deploy Cloud NAT."
|
||||
type = bool
|
||||
default = false
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Configuration for network resource factories."
|
||||
type = object({
|
||||
|
|
|
@ -79,7 +79,7 @@ The traffic destined to the VMs in each MIG is mediated through regional interna
|
|||
By default, the design assumes the following:
|
||||
|
||||
- on-premise networks (and related resources) are considered trusted. As such, the VPNs connecting with on-premises are terminated in GCP, in the trusted VPC
|
||||
- the public Internet is considered untrusted. As such [Cloud NAT](https://cloud.google.com/nat/docs/overview) has been deployed in the untrusted landing VPC only
|
||||
- the public Internet is considered untrusted. As such [Cloud NAT](https://cloud.google.com/nat/docs/overview) is deployed in the untrusted landing VPC only
|
||||
- cross-environment traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs. For demo purposes, the current NVA performs simple routing/natting only
|
||||
- any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions
|
||||
|
||||
|
@ -169,7 +169,7 @@ The Cloud Routers (connected to the VPN gateways in the trusted VPC) are configu
|
|||
|
||||
### Internet egress
|
||||
|
||||
In this setup, Internet egress is realized through [Cloud NAT](https://cloud.google.com/nat/docs/overview), deployed in the untrusted landing VPC. This allows instances in all other VPCs to reach the Internet, passing through the NVAs (being the public Internet considered untrusted).
|
||||
In this setup, Internet egress is realized through [Cloud NAT](https://cloud.google.com/nat/docs/overview), deployed in the untrusted landing VPC. This allows instances in all other VPCs to reach the Internet, passing through the NVAs (being the public Internet considered untrusted). Cloud NAT is disabled by default; enable it by setting the `enable_cloud_nat` variable
|
||||
|
||||
Several other scenarios are possible, with various degrees of complexity:
|
||||
|
||||
|
@ -458,22 +458,23 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L103) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L146) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L162) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L110) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L153) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L169) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | DNS configuration. | <code title="object({ enable_logging = optional(bool, true) resolvers = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L82) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L113) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.68.0.0/16" gcp_dev_secondary = "10.84.0.0/16" gcp_landing_trusted_primary = "10.64.0.0/17" gcp_landing_trusted_secondary = "10.80.0.0/17" gcp_landing_untrusted_primary = "10.64.127.0/17" gcp_landing_untrusted_secondary = "10.80.127.0/17" gcp_prod_primary = "10.72.0.0/16" gcp_prod_secondary = "10.88.0.0/16" }">{…}</code> | |
|
||||
| [groups](variables.tf#L128) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [onprem_cidr](variables.tf#L138) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L156) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L173) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L192) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L204) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L218) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L261) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | <code>bool</code> | | <code>false</code> | |
|
||||
| [factories_config](variables.tf#L89) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L120) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.68.0.0/16" gcp_dev_secondary = "10.84.0.0/16" gcp_landing_trusted_primary = "10.64.0.0/17" gcp_landing_trusted_secondary = "10.80.0.0/17" gcp_landing_untrusted_primary = "10.64.127.0/17" gcp_landing_untrusted_secondary = "10.80.127.0/17" gcp_prod_primary = "10.72.0.0/16" gcp_prod_secondary = "10.88.0.0/16" }">{…}</code> | |
|
||||
| [groups](variables.tf#L135) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [onprem_cidr](variables.tf#L145) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L163) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L180) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L199) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L211) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L225) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L268) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -81,6 +81,7 @@ moved {
|
|||
|
||||
module "landing-nat-primary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.primary
|
||||
name = local.region_shortnames[var.regions.primary]
|
||||
|
@ -96,6 +97,7 @@ moved {
|
|||
|
||||
module "landing-nat-secondary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.secondary
|
||||
name = local.region_shortnames[var.regions.secondary]
|
||||
|
|
|
@ -79,6 +79,13 @@ variable "dns" {
|
|||
nullable = false
|
||||
}
|
||||
|
||||
variable "enable_cloud_nat" {
|
||||
description = "Deploy Cloud NAT."
|
||||
type = bool
|
||||
default = false
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Configuration for network resource factories."
|
||||
type = object({
|
||||
|
|
|
@ -71,7 +71,7 @@ In this setup:
|
|||
|
||||
### Internet egress
|
||||
|
||||
The path of least resistance for Internet egress is using Cloud NAT, and that is what's implemented in this setup, with a NAT gateway configured for each VPC.
|
||||
Cloud NAT provides the simplest path for internet egress. This setup uses Cloud NAT, with optional per-VPC NAT gateways. Cloud NAT is disabled by default; enable it by setting the `enable_cloud_nat` variable.
|
||||
|
||||
Several other scenarios are possible of course, with varying degrees of complexity:
|
||||
|
||||
|
@ -332,20 +332,21 @@ Regions are defined via the `regions` variable which sets up a mapping between t
|
|||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L104) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L124) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L140) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L111) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L131) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L147) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | DNS configuration. | <code title="object({ dev_resolvers = optional(list(string), []) enable_logging = optional(bool, true) prod_resolvers = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L83) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L114) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L134) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L151) | IP ranges used for Private Service Access (e.g. CloudSQL). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L170) | Region definitions. | <code title="object({ primary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L180) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_dev_primary_config](variables.tf#L194) | VPN gateway configuration for onprem interconnection from dev in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_prod_primary_config](variables.tf#L237) | VPN gateway configuration for onprem interconnection from prod in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [enable_cloud_nat](variables.tf#L83) | Deploy Cloud NAT. | <code>bool</code> | | <code>false</code> | |
|
||||
| [factories_config](variables.tf#L90) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [groups](variables.tf#L121) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L141) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L158) | IP ranges used for Private Service Access (e.g. CloudSQL). | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L177) | Region definitions. | <code title="object({ primary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L187) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_dev_primary_config](variables.tf#L201) | VPN gateway configuration for onprem interconnection from dev in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_prod_primary_config](variables.tf#L244) | VPN gateway configuration for onprem interconnection from prod in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -95,8 +95,8 @@ module "dev-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "dev-spoke-cloudnat" {
|
||||
for_each = toset(values(module.dev-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.dev-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.dev-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "dev-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -93,8 +93,8 @@ module "prod-spoke-firewall" {
|
|||
}
|
||||
|
||||
module "prod-spoke-cloudnat" {
|
||||
for_each = toset(values(module.prod-spoke-vpc.subnet_regions))
|
||||
source = "../../../modules/net-cloudnat"
|
||||
for_each = toset(var.enable_cloud_nat ? values(module.prod-spoke-vpc.subnet_regions) : [])
|
||||
project_id = module.prod-spoke-project.project_id
|
||||
region = each.value
|
||||
name = "prod-nat-${local.region_shortnames[each.value]}"
|
||||
|
|
|
@ -80,6 +80,13 @@ variable "dns" {
|
|||
nullable = false
|
||||
}
|
||||
|
||||
variable "enable_cloud_nat" {
|
||||
description = "Deploy Cloud NAT."
|
||||
type = bool
|
||||
default = false
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Configuration for network resource factories."
|
||||
type = object({
|
||||
|
|
|
@ -102,7 +102,7 @@ Following the majority of real-life deployments, **we assume appliances to be st
|
|||
By default, the design assumes that:
|
||||
|
||||
- on-premise networks (and related resources) are considered trusted. As such, the VPNs connecting with on-premises are terminated in GCP, in the trusted VPC
|
||||
- the public Internet is considered untrusted. As such [Cloud NAT](https://cloud.google.com/nat/docs/overview) has been deployed in the untrusted landing VPC only. Also, the default route is set to carry traffic from the trusted VPCs, through the NVAs, to the untrusted VPC.
|
||||
- the public Internet is considered untrusted. As such [Cloud NAT](https://cloud.google.com/nat/docs/overview) is deployed in the untrusted landing VPC only. Also, the default route is set to carry traffic from the trusted VPCs, through the NVAs, to the untrusted VPC.
|
||||
- cross-spoke (environment) traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs.
|
||||
- any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions.
|
||||
|
||||
|
@ -190,7 +190,7 @@ The Cloud Routers (connected to the VPN gateways in the trusted VPC) are configu
|
|||
|
||||
### Internet egress
|
||||
|
||||
In this setup, Internet egress is realized through [Cloud NAT](https://cloud.google.com/nat/docs/overview), deployed in the untrusted landing VPC. This allows instances in all other VPCs to reach the Internet, passing through the NVAs (being the public Internet considered untrusted).
|
||||
In this setup, Internet egress is realized through [Cloud NAT](https://cloud.google.com/nat/docs/overview), deployed in the untrusted landing VPC. This allows instances in all other VPCs to reach the Internet, passing through the NVAs (being the public Internet considered untrusted). Cloud NAT is disabled by default; enable it by setting the `enable_cloud_nat` variable
|
||||
|
||||
Several other scenarios are possible, with various degrees of complexity:
|
||||
|
||||
|
@ -484,24 +484,25 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
|
|||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [automation](variables.tf#L42) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L50) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L103) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L157) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L173) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L110) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | <code title="object({ networking = string networking-dev = string networking-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L164) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L180) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [alert_config](variables.tf#L17) | Configuration for monitoring alerts. | <code title="object({ vpn_tunnel_established = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) user_labels = optional(map(string), {}) })) vpn_tunnel_bandwidth = optional(object({ auto_close = optional(string, null) duration = optional(string, "120s") enabled = optional(bool, true) notification_channels = optional(list(string), []) threshold_mbys = optional(string, "187.5") user_labels = optional(map(string), {}) })) })">object({…})</code> | | <code title="{ vpn_tunnel_established = {} vpn_tunnel_bandwidth = {} }">{…}</code> | |
|
||||
| [custom_roles](variables.tf#L63) | Custom roles defined at the org level, in key => id format. | <code title="object({ service_project_network_admin = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [dns](variables.tf#L72) | DNS configuration. | <code title="object({ enable_logging = optional(bool, true) resolvers = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L82) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L113) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.68.0.0/16" gcp_dev_secondary = "10.84.0.0/16" gcp_landing_trusted_primary = "10.64.0.0/17" gcp_landing_trusted_secondary = "10.80.0.0/17" gcp_landing_untrusted_primary = "10.64.127.0/17" gcp_landing_untrusted_secondary = "10.80.127.0/17" gcp_prod_primary = "10.72.0.0/16" gcp_prod_secondary = "10.88.0.0/16" }">{…}</code> | |
|
||||
| [groups](variables.tf#L128) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [ncc_asn](variables.tf#L138) | The NCC Cloud Routers ASN configuration. | <code>map(number)</code> | | <code title="{ nva_primary = 64513 nva_secondary = 64514 trusted = 64515 untrusted = 64512 }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L149) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L167) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L184) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L203) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L215) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L229) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L272) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [zones](variables.tf#L315) | Zones in which NVAs are deployed. | <code>list(string)</code> | | <code>["b", "c"]</code> | |
|
||||
| [enable_cloud_nat](variables.tf#L82) | Deploy Cloud NAT. | <code>bool</code> | | <code>false</code> | |
|
||||
| [factories_config](variables.tf#L89) | Configuration for network resource factories. | <code title="object({ data_dir = optional(string, "data") dns_policy_rules_file = optional(string, "data/dns-policy-rules.yaml") firewall_policy_name = optional(string, "net-default") })">object({…})</code> | | <code title="{ data_dir = "data" }">{…}</code> | |
|
||||
| [gcp_ranges](variables.tf#L120) | GCP address ranges in name => range format. | <code>map(string)</code> | | <code title="{ gcp_dev_primary = "10.68.0.0/16" gcp_dev_secondary = "10.84.0.0/16" gcp_landing_trusted_primary = "10.64.0.0/17" gcp_landing_trusted_secondary = "10.80.0.0/17" gcp_landing_untrusted_primary = "10.64.127.0/17" gcp_landing_untrusted_secondary = "10.80.127.0/17" gcp_prod_primary = "10.72.0.0/16" gcp_prod_secondary = "10.88.0.0/16" }">{…}</code> | |
|
||||
| [groups](variables.tf#L135) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code title="object({ gcp-network-admins = optional(string) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [ncc_asn](variables.tf#L145) | The NCC Cloud Routers ASN configuration. | <code>map(number)</code> | | <code title="{ nva_primary = 64513 nva_secondary = 64514 trusted = 64515 untrusted = 64512 }">{…}</code> | |
|
||||
| [onprem_cidr](variables.tf#L156) | Onprem addresses in name => range format. | <code>map(string)</code> | | <code title="{ main = "10.0.0.0/24" }">{…}</code> | |
|
||||
| [outputs_location](variables.tf#L174) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [psa_ranges](variables.tf#L191) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | <code title="object({ dev = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) prod = object({ ranges = map(string) export_routes = optional(bool, false) import_routes = optional(bool, false) peered_domains = optional(list(string), []) }) })">object({…})</code> | | <code>null</code> | |
|
||||
| [regions](variables.tf#L210) | Region definitions. | <code title="object({ primary = string secondary = string })">object({…})</code> | | <code title="{ primary = "europe-west1" secondary = "europe-west4" }">{…}</code> | |
|
||||
| [service_accounts](variables.tf#L222) | Automation service accounts in name => email format. | <code title="object({ data-platform-dev = string data-platform-prod = string gke-dev = string gke-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | | <code>null</code> | <code>1-resman</code> |
|
||||
| [vpn_onprem_primary_config](variables.tf#L236) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [vpn_onprem_secondary_config](variables.tf#L279) | VPN gateway configuration for onprem interconnection in the secondary region. | <code title="object({ peer_external_gateways = map(object({ redundancy_type = string interfaces = list(string) })) router_config = object({ create = optional(bool, true) asn = number name = optional(string) keepalive = optional(number) custom_advertise = optional(object({ all_subnets = bool ip_ranges = map(string) })) }) tunnels = map(object({ bgp_peer = object({ address = string asn = number route_priority = optional(number, 1000) custom_advertise = optional(object({ all_subnets = bool all_vpc_subnets = bool all_peer_vpc_subnets = bool ip_ranges = map(string) })) }) 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 })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [zones](variables.tf#L322) | Zones in which NVAs are deployed. | <code>list(string)</code> | | <code>["b", "c"]</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -82,6 +82,7 @@ moved {
|
|||
|
||||
module "landing-nat-primary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.primary
|
||||
name = local.region_shortnames[var.regions.primary]
|
||||
|
@ -97,6 +98,7 @@ moved {
|
|||
|
||||
module "landing-nat-secondary" {
|
||||
source = "../../../modules/net-cloudnat"
|
||||
count = var.enable_cloud_nat ? 1 : 0
|
||||
project_id = module.landing-project.project_id
|
||||
region = var.regions.secondary
|
||||
name = local.region_shortnames[var.regions.secondary]
|
||||
|
|
|
@ -79,6 +79,13 @@ variable "dns" {
|
|||
nullable = false
|
||||
}
|
||||
|
||||
variable "enable_cloud_nat" {
|
||||
description = "Deploy Cloud NAT."
|
||||
type = bool
|
||||
default = false
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "factories_config" {
|
||||
description = "Configuration for network resource factories."
|
||||
type = object({
|
||||
|
|
|
@ -11,6 +11,7 @@ dns = {
|
|||
resolvers = ["10.10.10.10"]
|
||||
enable_logging = true
|
||||
}
|
||||
enable_cloud_nat = true
|
||||
folder_ids = {
|
||||
networking = null
|
||||
networking-dev = null
|
||||
|
|
|
@ -11,6 +11,7 @@ dns = {
|
|||
resolvers = ["10.10.10.10"]
|
||||
enable_logging = true
|
||||
}
|
||||
enable_cloud_nat = true
|
||||
folder_ids = {
|
||||
networking = null
|
||||
networking-dev = null
|
||||
|
|
|
@ -11,6 +11,7 @@ dns = {
|
|||
resolvers = ["10.10.10.10"]
|
||||
enable_logging = true
|
||||
}
|
||||
enable_cloud_nat = true
|
||||
folder_ids = {
|
||||
networking = null
|
||||
networking-dev = null
|
||||
|
|
|
@ -12,6 +12,7 @@ dns = {
|
|||
prod_resolvers = ["10.20.10.10"]
|
||||
enable_logging = true
|
||||
}
|
||||
enable_cloud_nat = true
|
||||
folder_ids = {
|
||||
networking = null
|
||||
networking-dev = null
|
||||
|
|
|
@ -11,6 +11,7 @@ dns = {
|
|||
resolvers = ["10.10.10.10"]
|
||||
enable_logging = true
|
||||
}
|
||||
enable_cloud_nat = true
|
||||
folder_ids = {
|
||||
networking = null
|
||||
networking-dev = null
|
||||
|
|
Loading…
Reference in New Issue