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 <sruffilli@google.com>
Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>
Co-authored-by: Julio Castillo <jccb@google.com>
This commit is contained in:
lopezvit
2026-05-06 16:21:58 +03:00
committed by GitHub
parent 04e64c4ae2
commit 8eca61bb46
11 changed files with 241 additions and 5 deletions

View File

@@ -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. | <code>net-cloudnat</code> | |
| [factory-cloudnat.tf](./factory-cloudnat.tf) | Cloud NAT factory. | <code>net-address</code> · <code>net-cloudnat</code> | |
| [factory-dns.tf](./factory-dns.tf) | DNS zones and RPZ factory. | <code>dns</code> · <code>dns-response-policy</code> | |
| [factory-firewall-policies.tf](./factory-firewall-policies.tf) | Firewall policies factory. | <code>net-firewall-policy</code> | |
| [factory-ncc.tf](./factory-ncc.tf) | NCC Hubs and Groups factory | | <code>google_network_connectivity_group</code> · <code>google_network_connectivity_hub</code> · <code>google_network_connectivity_spoke</code> |

View File

@@ -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
})
}

View File

@@ -197,6 +197,9 @@
"properties": {
"region": {
"type": "string"
},
"num_nat_ips": {
"type": "number"
}
}
}

View File

@@ -67,6 +67,7 @@
- **nat_config**<a name="refs-nat_config"></a>: *object*
- **`^[a-z0-9-]+$`**: *object*
- ⁺**region**: *string*
- **num_nat_ips**: *number*
- **ncc_config**<a name="refs-ncc_config"></a>: *object*
- ⁺**hub**: *string*
- **group**: *string*

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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: