Add DNS Armor support (#3874)

* add dns armor module

* add dns armor to pf

* added missing/optional attributes

* Update project schemas

* Set version file copyright year to 2025

* replace module with single resource

* moved into it's own file

* Added tests and defaulting enabled to false

* Add optional name parameter and updated schemas

* make dns_threat_detector.enabled optional in project schemas

---------

Co-authored-by: Luca Prete <preteluca@gmail.com>
This commit is contained in:
Liam Nesteroff
2026-04-24 16:58:48 +10:00
committed by GitHub
parent 427d9a3298
commit f5ee82ab3a
15 changed files with 258 additions and 5 deletions

View File

@@ -622,6 +622,8 @@ labels:
app: app-0
team: team-a
parent: $folder_ids:team-a/app-0
dns_threat_detector:
enabled: true
iam_by_principals:
$iam_principals:service_accounts/dev-ta-app0-be/app-0-be:
- roles/storage.objectViewer
@@ -864,6 +866,7 @@ compute.disableSerialPortAccess:
| [projects-bigquery.tf](./projects-bigquery.tf) | None | <code>bigquery-dataset</code> | |
| [projects-buckets.tf](./projects-buckets.tf) | None | <code>gcs</code> | |
| [projects-defaults.tf](./projects-defaults.tf) | None | | |
| [projects-dns-armor.tf](./projects-dns-armor.tf) | None | | <code>google_network_security_dns_threat_detector</code> |
| [projects-kms.tf](./projects-kms.tf) | None | <code>kms</code> | |
| [projects-log-buckets.tf](./projects-log-buckets.tf) | None | <code>logging-bucket</code> | |
| [projects-pubsub.tf](./projects-pubsub.tf) | None | <code>pubsub</code> | |
@@ -878,11 +881,11 @@ compute.disableSerialPortAccess:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [factories_config](variables.tf#L165) | Path to folder with YAML resource description data files. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [factories_config](variables.tf#L166) | Path to folder with YAML resource description data files. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [context](variables.tf#L17) | Context-specific interpolations. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_defaults](variables.tf#L42) | Optional default values used when corresponding project or folder data from files are missing. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_merges](variables.tf#L107) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_overrides](variables.tf#L126) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_defaults](variables.tf#L43) | Optional default values used when corresponding project or folder data from files are missing. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_merges](variables.tf#L108) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [data_overrides](variables.tf#L127) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | <code>object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [folders](variables-folders.tf#L17) | Folders data merged with factory data. | <code>map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [notification_channels](variables-billing.tf#L17) | Notification channels used by budget alerts. | <code>map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [projects](variables-projects.tf#L17) | Projects data merged with factory data. | <code>map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |

View File

@@ -0,0 +1,40 @@
/**
* 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.
*/
resource "google_network_security_dns_threat_detector" "dns_threat_detector" {
provider = google-beta
for_each = {
for k, v in local.projects_input : k => v
if try(v.dns_threat_detector.enabled, false)
}
project = module.projects[each.key].project_id
name = (
try(each.value.dns_threat_detector.name, null) != null
? each.value.dns_threat_detector.name
: (
each.value.prefix == null
? each.value.name
: "${each.value.prefix}-${each.value.name}"
)
)
excluded_networks = [
for s in try(each.value.dns_threat_detector.excluded_networks, []) :
lookup(local.ctx.networks, s, s)
]
threat_detector_provider = try(each.value.dns_threat_detector.threat_detector_provider, null)
labels = try(each.value.dns_threat_detector.labels, {})
location = try(each.value.dns_threat_detector.location, null)
}

View File

@@ -481,6 +481,36 @@
"descriptive_name": {
"type": "string"
},
"dns_threat_detector": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"excluded_networks": {
"type": "array",
"items": {
"type": "string"
}
},
"labels": {
"type": "object"
},
"location": {
"type": "string"
},
"name": {
"type": "string"
},
"threat_detector_provider": {
"type": "string",
"enum": [
"INFOBLOX"
]
}
}
},
"org_policies": {
"type": "object",
"additionalProperties": false,

View File

@@ -149,6 +149,16 @@
- items: *string*
- **name**: *string*
- **descriptive_name**: *string*
- **dns_threat_detector**: *object*
<br>*additional properties: false*
- **enabled**: *boolean*
- **excluded_networks**: *array*
- items: *string*
- **labels**: *object*
- **location**: *string*
- **name**: *string*
- **threat_detector_provider**: *string*
<br>*enum: ['INFOBLOX']*
- **org_policies**: *object*
<br>*additional properties: false*
- **`^[a-z]+\.`**: *object*

View File

@@ -231,6 +231,14 @@ variable "projects" {
friendly_name = optional(string)
location = optional(string)
})), {})
dns_threat_detector = optional(object({
enabled = optional(bool, false)
excluded_networks = optional(list(string), [])
labels = optional(map(string), {})
location = optional(string)
name = optional(string)
threat_detector_provider = optional(string)
}), {})
factories_config = optional(object({
custom_roles = optional(string)
observability = optional(string)

View File

@@ -25,6 +25,7 @@ variable "context" {
kms_keys = optional(map(string), {})
locations = optional(map(string), {})
log_buckets = optional(map(string), {})
networks = optional(map(string), {})
notification_channels = optional(map(string), {})
project_ids = optional(map(string), {})
project_numbers = optional(map(string), {})