From 8eca61bb468ea4e538e37adefa61fac6e3da2671 Mon Sep 17 00:00:00 2001 From: lopezvit Date: Wed, 6 May 2026 16:21:58 +0300 Subject: [PATCH] Add support for static IPs NAT to 2-networking (#3889) * feat(2-networking): add support for static IPs NAT * fix(linting): fix linting * fix(linting): fix linting * fix(2-networking): factory-cloudnat don't assume that the context values are present. * fix(2-networking): factory-cloudnat pass region in a try to forward the problem to the module --------- Co-authored-by: Simone Ruffilli Co-authored-by: Ludovico Magnocavallo Co-authored-by: Julio Castillo --- fast/stages/2-networking/README.md | 15 +++- fast/stages/2-networking/factory-cloudnat.tf | 24 +++++- .../2-networking/schemas/vpc.schema.json | 3 + .../stages/2-networking/schemas/vpc.schema.md | 1 + .../data-teststatic-ips-nat/defaults.yaml | 41 ++++++++++ .../projects/net-core-0.yaml | 20 +++++ .../vpcs/core/.config.yaml | 17 ++++ .../vpcs/core/subnets/core-default.yaml | 8 ++ .../s2_networking/static_ips_nat.tfvars | 34 ++++++++ .../stages/s2_networking/static_ips_nat.yaml | 78 +++++++++++++++++++ tests/fast/stages/s2_networking/tftest.yaml | 5 ++ 11 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 tests/fast/stages/s2_networking/data-teststatic-ips-nat/defaults.yaml create mode 100644 tests/fast/stages/s2_networking/data-teststatic-ips-nat/projects/net-core-0.yaml create mode 100644 tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/.config.yaml create mode 100644 tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/subnets/core-default.yaml create mode 100644 tests/fast/stages/s2_networking/static_ips_nat.tfvars create mode 100644 tests/fast/stages/s2_networking/static_ips_nat.yaml diff --git a/fast/stages/2-networking/README.md b/fast/stages/2-networking/README.md index 4b2cd4e91..f16324d60 100644 --- a/fast/stages/2-networking/README.md +++ b/fast/stages/2-networking/README.md @@ -284,6 +284,19 @@ nat_config: # [...] ``` +- **External IPs for NAT:** You can specify how many static IPs do you want, so they would be reserved and kept static. This is helpful when you need to connect to an external service that needs to whitelist the IPs. This is done by defining the number of static IP addresses in the `nat` section of a VPC's `.config.yaml` file. + +For example: + +```yaml +# [...] +nat_config: + nat-ew8: + num_nat_ips: 3 + region: $locations:primary +# [...] +``` + - **Cloud Routers:** The `factory-routers.tf` file manages Cloud Routers, which are used with Cloud VPN and Cloud Interconnect to exchange routes with on-premises networks. Routers are configured within each VPC's `.config.yaml` file. ```yaml @@ -359,7 +372,7 @@ Internally created resources are mapped to context namespaces, and use specific | name | description | modules | resources | |---|---|---|---| -| [factory-cloudnat.tf](./factory-cloudnat.tf) | Cloud NAT factory. | net-cloudnat | | +| [factory-cloudnat.tf](./factory-cloudnat.tf) | Cloud NAT factory. | net-address · net-cloudnat | | | [factory-dns.tf](./factory-dns.tf) | DNS zones and RPZ factory. | dns · dns-response-policy | | | [factory-firewall-policies.tf](./factory-firewall-policies.tf) | Firewall policies factory. | net-firewall-policy | | | [factory-ncc.tf](./factory-ncc.tf) | NCC Hubs and Groups factory | | google_network_connectivity_group · google_network_connectivity_hub · google_network_connectivity_spoke | diff --git a/fast/stages/2-networking/factory-cloudnat.tf b/fast/stages/2-networking/factory-cloudnat.tf index f76508db0..c7c3b5873 100644 --- a/fast/stages/2-networking/factory-cloudnat.tf +++ b/fast/stages/2-networking/factory-cloudnat.tf @@ -29,6 +29,8 @@ locals { config_timeouts = try(nat_config.config_timeouts, {}) endpoint_types = try(nat_config.endpoint_types, null) logging_filter = try(nat_config.logging_filter, null) + num_nat_ips = try(nat_config.num_nat_ips, 0) + region = try(nat_config.region, null) router_asn = try(nat_config.router_asn, null) router_create = try(nat_config.router_create, true) router_network = module.vpc-factory.vpcs[vpc_key].id @@ -40,12 +42,25 @@ locals { ])...) } +module "addresses" { + source = "../../../modules/net-address" + for_each = { for k, v in local.nat_configs : k => v if tonumber(v.num_nat_ips) > 0 } + project_id = each.value.project_id + external_addresses = { + for i in range(tonumber(each.value.num_nat_ips)) : "${each.value.name}-ip-${i}" => { region = each.value.region } + } + context = merge(local.ctx, { + project_ids = local.ctx_projects.project_ids + locations = local.ctx.locations + }) +} + module "nat" { source = "../../../modules/net-cloudnat" for_each = local.nat_configs project_id = each.value.project_id name = each.value.name - addresses = each.value.addresses + addresses = concat(each.value.addresses, [for a in try(module.addresses[each.key].external_addresses, {}) : a.self_link]) config_port_allocation = each.value.config_port_allocation config_source_subnetworks = each.value.config_source_subnetworks config_timeouts = each.value.config_timeouts @@ -58,8 +73,9 @@ module "nat" { rules = each.value.rules type = each.value.type context = merge(local.ctx, { - project_ids = local.ctx_projects.project_ids - vpc_self_links = local.ctx_vpcs.self_links - locations = local.ctx.locations + project_ids = local.ctx_projects.project_ids + networks = local.ctx_vpcs.self_links + locations = local.ctx.locations + subnets = local.ctx_vpcs.subnets_by_vpc }) } diff --git a/fast/stages/2-networking/schemas/vpc.schema.json b/fast/stages/2-networking/schemas/vpc.schema.json index 59289339a..f881d53eb 100644 --- a/fast/stages/2-networking/schemas/vpc.schema.json +++ b/fast/stages/2-networking/schemas/vpc.schema.json @@ -197,6 +197,9 @@ "properties": { "region": { "type": "string" + }, + "num_nat_ips": { + "type": "number" } } } diff --git a/fast/stages/2-networking/schemas/vpc.schema.md b/fast/stages/2-networking/schemas/vpc.schema.md index 990e7fa8f..420b32718 100644 --- a/fast/stages/2-networking/schemas/vpc.schema.md +++ b/fast/stages/2-networking/schemas/vpc.schema.md @@ -67,6 +67,7 @@ - **nat_config**: *object* - **`^[a-z0-9-]+$`**: *object* - ⁺**region**: *string* + - **num_nat_ips**: *number* - **ncc_config**: *object* - ⁺**hub**: *string* - **group**: *string* diff --git a/tests/fast/stages/s2_networking/data-teststatic-ips-nat/defaults.yaml b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/defaults.yaml new file mode 100644 index 000000000..fdb490446 --- /dev/null +++ b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/defaults.yaml @@ -0,0 +1,41 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# yaml-language-server: $schema=../../schemas/defaults.schema.json + +context: + cidr_ranges_sets: + healthchecks: + - 35.191.0.0/16 + - 130.211.0.0/22 + - 209.85.152.0/22 + - 209.85.204.0/22 + rfc1918: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + locations: + primary: europe-west1 + secondary: europe-west3 + iam_principals: {} +projects: + defaults: + locations: + storage: eu +vpcs: + auto_create_subnetworks: false + delete_default_route_on_create: true + mtu: 1500 +output_files: + storage_bucket: $storage_buckets:iac-0/iac-outputs diff --git a/tests/fast/stages/s2_networking/data-teststatic-ips-nat/projects/net-core-0.yaml b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/projects/net-core-0.yaml new file mode 100644 index 000000000..3e8e97916 --- /dev/null +++ b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/projects/net-core-0.yaml @@ -0,0 +1,20 @@ +# skip boilerplate check +--- +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../schemas/project.schema.json +name: prod-net-core-0 +parent: $folder_ids:networking +services: + - compute.googleapis.com + - container.googleapis.com + - dns.googleapis.com + - iap.googleapis.com + - logging.googleapis.com + - monitoring.googleapis.com + - networkmanagement.googleapis.com + - networksecurity.googleapis.com + - servicenetworking.googleapis.com + - vpcaccess.googleapis.com +shared_vpc_host_config: + enabled: true diff --git a/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/.config.yaml b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/.config.yaml new file mode 100644 index 000000000..3fbea8268 --- /dev/null +++ b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/.config.yaml @@ -0,0 +1,17 @@ +# skip boilerplate check +--- +# start of document (---) avoids errors if the file only contains comments + +# yaml-language-server: $schema=../../../../schemas/vpc.schema.json + +project_id: $project_ids:net-core-0 +name: core-0 +delete_default_routes_on_create: true +nat_config: + nat-static: + region: $locations:primary + num_nat_ips: 3 + config_source_subnetworks: + all: false + subnetworks: + - self_link: $subnets:core/europe-west1/core-default diff --git a/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/subnets/core-default.yaml b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/subnets/core-default.yaml new file mode 100644 index 000000000..ebe56e9ff --- /dev/null +++ b/tests/fast/stages/s2_networking/data-teststatic-ips-nat/vpcs/core/subnets/core-default.yaml @@ -0,0 +1,8 @@ +# skip boilerplate check + +# yaml-language-server: $schema=../../../../../schemas/subnet.schema.json + +name: core-default +region: $locations:primary +ip_cidr_range: 10.71.0.0/24 +description: Default primary-region subnet for core diff --git a/tests/fast/stages/s2_networking/static_ips_nat.tfvars b/tests/fast/stages/s2_networking/static_ips_nat.tfvars new file mode 100644 index 000000000..08e3b00a4 --- /dev/null +++ b/tests/fast/stages/s2_networking/static_ips_nat.tfvars @@ -0,0 +1,34 @@ +automation = { + outputs_bucket = "test" +} +billing_account = { + id = "000000-111111-222222" +} +factories_config = { + dataset = "./data-teststatic-ips-nat" + paths = { + defaults = "defaults.yaml" + } +} +folder_ids = { + "networking" = "folders/12345678" + "networking/prod" = "folders/23456789" + "networking/dev" = "folders/34567890" +} +organization = { + domain = "fast.example.com" + id = 123456789012 + customer_id = "C00000000" +} +prefix = "fast" +service_accounts = { + "iac-0/iac-pf-rw" = "iac-pf-rw@test.iam.gserviceaccount.com" + "iac-0/iac-pf-ro" = "iac-pf-ro@test.iam.gserviceaccount.com" +} +storage_buckets = { + "iac-0/iac-outputs" = "test" +} +tag_values = { + "environment/development" = "tagValues/12345" + "environment/production" = "tagValues/12346" +} diff --git a/tests/fast/stages/s2_networking/static_ips_nat.yaml b/tests/fast/stages/s2_networking/static_ips_nat.yaml new file mode 100644 index 000000000..a5a597924 --- /dev/null +++ b/tests/fast/stages/s2_networking/static_ips_nat.yaml @@ -0,0 +1,78 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +counts: + google_compute_address: 3 + google_compute_network: 1 + google_compute_route: 3 + google_compute_router: 1 + google_compute_router_nat: 1 + google_compute_shared_vpc_host_project: 1 + google_compute_subnetwork: 1 + google_logging_project_settings: 1 + google_project: 1 + google_project_iam_member: 8 + google_project_service: 10 + google_project_service_identity: 8 + google_storage_bucket_object: 2 + modules: 7 + resources: 43 + terraform_data: 2 +values: + module.addresses["core/nat-static"].google_compute_address.external["core-nat-static-ip-0"]: + address_type: EXTERNAL + description: 'Terraform managed.' + name: core-nat-static-ip-0 + project: fast-prod-net-core-0 + region: europe-west1 + module.addresses["core/nat-static"].google_compute_address.external["core-nat-static-ip-1"]: + address_type: EXTERNAL + description: 'Terraform managed.' + name: core-nat-static-ip-1 + project: fast-prod-net-core-0 + region: europe-west1 + module.addresses["core/nat-static"].google_compute_address.external["core-nat-static-ip-2"]: + address_type: EXTERNAL + description: 'Terraform managed.' + name: core-nat-static-ip-2 + project: fast-prod-net-core-0 + region: europe-west1 + module.nat["core/nat-static"].google_compute_router.router[0]: + name: core-nat-static-nat + project: fast-prod-net-core-0 + region: europe-west1 + module.nat["core/nat-static"].google_compute_router_nat.nat: + enable_dynamic_port_allocation: False + enable_endpoint_independent_mapping: True + icmp_idle_timeout_sec: 30 + log_config: + - enable: False + filter: ALL + max_ports_per_vm: 65536 + name: core-nat-static + nat64_subnetwork: [] + project: fast-prod-net-core-0 + region: europe-west1 + router: core-nat-static-nat + rules: [] + source_subnetwork_ip_ranges_to_nat: LIST_OF_SUBNETWORKS + subnetwork: + - secondary_ip_range_names: [] + source_ip_ranges_to_nat: + - 'ALL_IP_RANGES' + tcp_established_idle_timeout_sec: 1200 + tcp_time_wait_timeout_sec: 120 + tcp_transitory_idle_timeout_sec: 30 + type: PUBLIC + udp_idle_timeout_sec: 30 diff --git a/tests/fast/stages/s2_networking/tftest.yaml b/tests/fast/stages/s2_networking/tftest.yaml index 9b1a487cf..c4aea7a8a 100644 --- a/tests/fast/stages/s2_networking/tftest.yaml +++ b/tests/fast/stages/s2_networking/tftest.yaml @@ -22,6 +22,11 @@ tests: - dns_delegations.yaml extra_dirs: - ../../../tests/fast/stages/s2_networking/data-testdns-delegation + static_ips_nat: + inventory: + - static_ips_nat.yaml + extra_dirs: + - ../../../tests/fast/stages/s2_networking/data-teststatic-ips-nat ncc: nva: vlan_attachments: