diff --git a/infrastructure/gcp/cloud-dns/.terraform.lock.hcl b/infrastructure/gcp/cloud-dns/.terraform.lock.hcl new file mode 100644 index 00000000..a947a847 --- /dev/null +++ b/infrastructure/gcp/cloud-dns/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/google" { + version = "6.50.0" + constraints = ">= 5.0.0, < 7.0.0" + hashes = [ + "h1:MAAe4zFFdqS9M5rpmJK/vKgdb6ZMD/s/0Xd97yTDipA=", + "zh:1d4695f807d998f11fcdcfa174766287b82a8093513af857bcdad2d81c642480", + "zh:3173ac5df0294624d113812e49e2a55714aff7db617488168cecdf4168df9e29", + "zh:34d2b3d44c23bd6354fc4ab5917b302872ea1ab8de107034567f955b1717fa5b", + "zh:3a77f3cc2f3664cd5aaeeef4d044e6ec1695a079588fffec3ca03953664e5f04", + "zh:6b444e4b629ea8dc8cb112a39dde098dc5584d26d6de4177558f556a9a226696", + "zh:96545c8cd4d3a57069c5d1799eab5aedd887e16d98b5559a195f6d2c2d9bc674", + "zh:ba464caafde95ee16671d6b5ec90f053ed77a9d06c567456db6efd9160fa3165", + "zh:d876938e5b0d3f57a984d9be72467995f87fef6569968623415dc51d9f54d30b", + "zh:dfd908d873e314ab807d0abc9cfd42d2611cd06dc1b9ec719ebdbb738e8e68d6", + "zh:f9f16819a7738d564afd45fd169ba61004ec4e4e7089d2a4950cb8895be1fe1f", + ] +} diff --git a/infrastructure/gcp/cloud-dns/README.md b/infrastructure/gcp/cloud-dns/README.md index 5dc4c9d1..8320ae47 100644 --- a/infrastructure/gcp/cloud-dns/README.md +++ b/infrastructure/gcp/cloud-dns/README.md @@ -49,7 +49,7 @@ resource "example_resource" "this" { | Name | Version | |------|---------| -| [google](#provider\_google) | >= 5.0, < 7.0 | +| [google](#provider\_google) | 6.50.0 | ## Resources @@ -61,6 +61,7 @@ resource "example_resource" "this" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [dnssec\_enabled](#input\_dnssec\_enabled) | Enable DNSSEC for the zone. Only applies to public zones; signing is inert until the DS record is published at the domain registrar. | `bool` | `true` | no | | [domain\_name](#input\_domain\_name) | The domain name for the DNS zone (without trailing dot, e.g. example.com) | `string` | n/a | yes | | [private\_zone\_networks](#input\_private\_zone\_networks) | VPC network self-links for private zones | `list(string)` | `[]` | no | | [project\_id](#input\_project\_id) | The GCP project ID | `string` | n/a | yes | diff --git a/infrastructure/gcp/cloud-dns/main.tf b/infrastructure/gcp/cloud-dns/main.tf index 630b6a70..c6ec6880 100644 --- a/infrastructure/gcp/cloud-dns/main.tf +++ b/infrastructure/gcp/cloud-dns/main.tf @@ -8,6 +8,13 @@ resource "google_dns_managed_zone" "zone" { dns_name = "${var.domain_name}." visibility = var.visibility + dynamic "dnssec_config" { + for_each = var.visibility == "public" && var.dnssec_enabled ? [1] : [] + content { + state = "on" + } + } + dynamic "private_visibility_config" { for_each = var.visibility == "private" ? [1] : [] content { diff --git a/infrastructure/gcp/cloud-dns/tests/cloud_dns.tftest.hcl b/infrastructure/gcp/cloud-dns/tests/cloud_dns.tftest.hcl index d8dabbfd..d4a3ba85 100644 --- a/infrastructure/gcp/cloud-dns/tests/cloud_dns.tftest.hcl +++ b/infrastructure/gcp/cloud-dns/tests/cloud_dns.tftest.hcl @@ -74,3 +74,39 @@ run "labels_applied_from_tags" { error_message = "Labels should be applied from tags variable" } } + +run "dnssec_enabled_by_default_on_public_zone" { + command = plan + + assert { + condition = google_dns_managed_zone.zone.dnssec_config[0].state == "on" + error_message = "DNSSEC should be on by default for public zones" + } +} + +run "dnssec_can_be_disabled" { + command = plan + + variables { + dnssec_enabled = false + } + + assert { + condition = length(google_dns_managed_zone.zone.dnssec_config) == 0 + error_message = "DNSSEC should not be configured when dnssec_enabled is false" + } +} + +run "dnssec_ignored_on_private_zone" { + command = plan + + variables { + visibility = "private" + dnssec_enabled = true + } + + assert { + condition = length(google_dns_managed_zone.zone.dnssec_config) == 0 + error_message = "DNSSEC should not be configured on private zones even when dnssec_enabled is true" + } +} diff --git a/infrastructure/gcp/cloud-dns/variables.tf b/infrastructure/gcp/cloud-dns/variables.tf index 5a0b9b9d..57857d60 100644 --- a/infrastructure/gcp/cloud-dns/variables.tf +++ b/infrastructure/gcp/cloud-dns/variables.tf @@ -26,6 +26,12 @@ variable "private_zone_networks" { default = [] } +variable "dnssec_enabled" { + type = bool + description = "Enable DNSSEC for the zone. Only applies to public zones; signing is inert until the DS record is published at the domain registrar." + default = true +} + variable "tags" { type = map(string) description = "A mapping of labels to assign to the DNS managed zone"