feat(2-networking): add NS And DS record dynamically from sub-zones records (#3818)

* feat(2-networking): add NS And DS record dynamically from sub-zones records

* tfdoc

* feat(test): 2-networking adding dns_delegations test with and without DSSEC

---------

Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>
Co-authored-by: Simone Ruffilli <sruffilli@google.com>
This commit is contained in:
lopezvit
2026-03-31 11:54:54 +03:00
committed by GitHub
parent fcb3b7908d
commit 956ada4ddd
14 changed files with 321 additions and 0 deletions

View File

@@ -12,6 +12,7 @@
- [Networking projects](#networking-projects)
- [VPCs](#vpcs)
- [DNS](#dns)
- [Delegated Public Zones](#delegated-public-zones)
- [Firewall Policies](#firewall-policies)
- [Cloud NAT and Routers](#cloud-nat-and-routers)
- [VPC Connectivity](#vpc-connectivity)
@@ -200,6 +201,68 @@ In the default dataset, DNS is centralized in the `net-core-0` (hub) project. It
The spoke VPCs have their own private zones for subdomains (e.g., `dev.test.`) and use the hub for all other DNS lookups.
#### Delegated Public Zones
The factory also supports delegating public zones, which is useful for scenarios where a parent public zone is managed in one project, and you want to delegate a subdomain to a different project.
To configure this, you first define the parent public zone. Then, for the delegated zone, you specify `delegation_config` pointing to the parent zone. This automatically creates the necessary `NS` (and `DS` records if you are using DNSSEC) records in the parent zone.
Here's an example of how to set this up:
```yaml
# Parent public zone (e.g., in dns/zones/net-core-0/pub-gcp-example-com.yaml)
#
# yaml-language-server: $schema=../../../../../schemas/dns.schema.json
project_id: $project_ids:net-core-0
domain: gcp.example.com.
public:
enable_logging: false
dnssec_config:
state: "on"
non_existence: "nsec3"
key_signing_key:
algorithm: "ecdsap256sha256"
key_length: 256
zone_signing_key:
algorithm: "ecdsap256sha256"
key_length: 256
recordsets:
"A localhost":
records: ["127.0.0.1"]
delegations:
- net-dev-0/pub-dev-gcp-example-com
```
```yaml
# Delegated child zone (e.g., in dns/zones/net-dev-0/pub-dev-gcp-example-com.yaml)
#
# yaml-language-server: $schema=../../../../../schemas/dns.schema.json
project_id: $project_ids:net-dev-0
domain: dev.gcp.example.com.
public:
enable_logging: false
dnssec_config:
state: "on"
non_existence: "nsec3"
key_signing_key:
algorithm: "ecdsap256sha256"
key_length: 256
zone_signing_key:
algorithm: "ecdsap256sha256"
key_length: 256
recordsets:
"A localhost":
records: ["127.0.0.1"]
```
In this example:
- A public zone for `gcp.example.com.` is created in the `net-core-0` project.
- A separate public zone for `dev.gcp.example.com.` is created in the `net-dev-0` project.
- The `delegation_config` in the parent zone tells the factory to find the child zone named `pub-dev-gcp-example-com` in the `net-dev-0` project and create the necessary `NS` and `DS` records to make the delegation effective.
### Firewall Policies
This stage supports both VPC-level firewall rules and hierarchical firewall policies.

View File

@@ -75,6 +75,30 @@ locals {
}
)
}
# DNS delegations: auto-create NS and DS records in parent zones
# from child zone outputs (name_servers, dns_keys).
# Grouped by parent zone key so a single module call per parent
# handles all its delegation recordsets.
dns_delegation_recordsets = {
for zone_key, zone_config in local.dns_zones :
zone_key => merge(
{
for child_key in zone_config.delegations :
"NS ${module.dns-zones[child_key].domain}" => {
records = module.dns-zones[child_key].name_servers
}
},
{
for child_key in zone_config.delegations :
"DS ${module.dns-zones[child_key].domain}" => {
records = [module.dns-zones[child_key].dns_keys.key_signing_keys[0].ds_record]
}
if try(local.dns_zones[child_key].zone_config.public.dnssec_config.state, "off") == "on"
}
)
if length(try(zone_config.delegations, [])) > 0
}
# DNS response policies
_dns_response_policies_files = try(
fileset(local.paths.dns_response_policies, "**/*.yaml"), []
@@ -115,6 +139,19 @@ module "dns-zones" {
depends_on = [module.vpc-factory]
}
module "dns-delegations" {
source = "../../../modules/dns"
for_each = local.dns_delegation_recordsets
project_id = local.dns_zones[each.key].project_id
name = replace(each.key, "/", "-")
recordsets = each.value
context = {
project_ids = local.ctx_projects.project_ids
networks = local.ctx_vpcs.self_links
}
depends_on = [module.dns-zones]
}
module "dns-response-policies" {
source = "../../../modules/dns-response-policy"
for_each = local.dns_response_policies

View File

@@ -38,6 +38,13 @@
},
"public": {
"$ref": "#/$defs/public_zone"
},
"delegations": {
"type": "array",
"description": "List of child zone keys (e.g. 'net-dev-0/pvt-dev-zone') whose NS and DS records are auto-created in this parent zone.",
"items": {
"type": "string"
}
}
},
"required": [

View File

@@ -16,6 +16,8 @@
- **peering**: *reference([peering_zone](#refs-peering_zone))*
- **forwarding**: *reference([forwarding_zone](#refs-forwarding_zone))*
- **public**: *reference([public_zone](#refs-public_zone))*
- **delegations**: *array*
- items: *string*
## Definitions