diff --git a/modules/net-firewall-policy/README.md b/modules/net-firewall-policy/README.md
index 10d395fe0f..4c1722c469 100644
--- a/modules/net-firewall-policy/README.md
+++ b/modules/net-firewall-policy/README.md
@@ -253,19 +253,76 @@ issue-1995:
- 1-65535
- protocol: icmp
```
+
+You might need to reference external security profile groups in your firewall rules, using their Terraform ids. For example, `//networksecurity.googleapis.com/${google_network_security_security_profile_group.security_profile_group.id}`. To do so, list your security profile groups in the `security_profile_group_ids` map variable. Then reference them by key from your factories.
+
+```hcl
+module "vpc" {
+ source = "./fabric/modules/net-vpc"
+ project_id = "my-project"
+ name = "my-network"
+}
+
+resource "google_network_security_security_profile" "security_profile" {
+ name = "security-profile"
+ type = "THREAT_PREVENTION"
+ parent = "organizations/0123456789"
+ location = "global"
+}
+
+resource "google_network_security_security_profile_group" "security_profile_group" {
+ name = "security-profile-group"
+ parent = "organizations/0123456789"
+ location = "global"
+ description = "Sample security profile group."
+ threat_prevention_profile = google_network_security_security_profile.security_profile.id
+}
+
+module "firewall-policy" {
+ source = "./fabric/modules/net-firewall-policy"
+ name = "fw-policy"
+ parent_id = "my-project"
+ security_profile_group_ids = {
+ http-sg = "//networksecurity.googleapis.com/${google_network_security_security_profile_group.security_profile_group.id}"
+ }
+ attachments = {
+ my-vpc = module.vpc.self_link
+ }
+ factories_config = {
+ ingress_rules_file_path = "configs/ingress-spg.yaml"
+ }
+}
+# tftest modules=2 resources=8 files=ingress-spg inventory=factory-spg.yaml
+```
+
+```yaml
+# tftest-file id=ingress-spg path=configs/ingress-spg.yaml
+http:
+ priority: 1000
+ action: apply_security_profile_group
+ security_profile_group: http-sg
+ match:
+ source_ranges:
+ - 10.0.0.0/8
+ layer4_configs:
+ - protocol: tcp
+ ports:
+ - 80
+```
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L115) | Policy name. | string
| ✓ | |
-| [parent_id](variables.tf#L121) | Parent node where the policy will be created, `folders/nnn` or `organizations/nnn` for hierarchical policy, project id for a network policy. | string
| ✓ | |
+| [name](variables.tf#L117) | Policy name. | string
| ✓ | |
+| [parent_id](variables.tf#L123) | Parent node where the policy will be created, `folders/nnn` or `organizations/nnn` for hierarchical policy, project id for a network policy. | string
| ✓ | |
| [attachments](variables.tf#L17) | Ids of the resources to which this policy will be attached, in descriptive name => self link format. Specify folders or organization for hierarchical policy, VPCs for network policy. | map(string)
| | {}
|
| [description](variables.tf#L24) | Policy description. | string
| | null
|
-| [egress_rules](variables.tf#L30) | List of egress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. The match.layer4configs map is in protocol => optional [ports] format. | map(object({…}))
| | {}
|
-| [factories_config](variables.tf#L67) | Paths to folders for the optional factories. | object({…})
| | {}
|
-| [ingress_rules](variables.tf#L78) | List of ingress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. | map(object({…}))
| | {}
|
-| [region](variables.tf#L127) | Policy region. Leave null for hierarchical policy, set to 'global' for a global network policy. | string
| | null
|
+| [egress_rules](variables.tf#L30) | List of egress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. The match.layer4configs map is in protocol => optional [ports] format. | map(object({…}))
| | {}
|
+| [factories_config](variables.tf#L68) | Paths to folders for the optional factories. | object({…})
| | {}
|
+| [ingress_rules](variables.tf#L79) | List of ingress rule definitions, action can be 'allow', 'deny', 'goto_next' or 'apply_security_profile_group'. | map(object({…}))
| | {}
|
+| [region](variables.tf#L129) | Policy region. Leave null for hierarchical policy, set to 'global' for a global network policy. | string
| | null
|
+| [security_profile_group_ids](variables.tf#L135) | The optional security groups ids to be referenced in factories. | map(string)
| | {}
|
## Outputs
diff --git a/modules/net-firewall-policy/factory.tf b/modules/net-firewall-policy/factory.tf
index 74ef28d798..b36a068b39 100644
--- a/modules/net-firewall-policy/factory.tf
+++ b/modules/net-firewall-policy/factory.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ locals {
target_resources = lookup(v, "target_resources", null)
target_service_accounts = lookup(v, "target_service_accounts", null)
target_tags = lookup(v, "target_tags", null)
+ tls_inspect = lookup(v, "tls_inspect", null)
match = {
address_groups = lookup(v.match, "address_groups", null)
fqdns = lookup(v.match, "fqdns", null)
@@ -85,6 +86,7 @@ locals {
target_resources = lookup(v, "target_resources", null)
target_service_accounts = lookup(v, "target_service_accounts", null)
target_tags = lookup(v, "target_tags", null)
+ tls_inspect = lookup(v, "tls_inspect", null)
match = {
address_groups = lookup(v.match, "address_groups", null)
fqdns = lookup(v.match, "fqdns", null)
diff --git a/modules/net-firewall-policy/hierarchical.tf b/modules/net-firewall-policy/hierarchical.tf
index 48bc9c9e18..7969a559d1 100644
--- a/modules/net-firewall-policy/hierarchical.tf
+++ b/modules/net-firewall-policy/hierarchical.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,12 +37,16 @@ resource "google_compute_firewall_policy_rule" "hierarchical" {
action = local.rules[each.key].action
description = local.rules[each.key].description
direction = local.rules[each.key].direction
- security_profile_group = local.rules[each.key].security_profile_group
disabled = local.rules[each.key].disabled
enable_logging = local.rules[each.key].enable_logging
priority = local.rules[each.key].priority
target_resources = local.rules[each.key].target_resources
target_service_accounts = local.rules[each.key].target_service_accounts
+ tls_inspect = local.rules[each.key].tls_inspect
+ security_profile_group = try(
+ var.security_profile_group_ids[local.rules[each.key].security_profile_group],
+ local.rules[each.key].security_profile_group
+ )
match {
dest_ip_ranges = local.rules[each.key].match.destination_ranges
src_ip_ranges = local.rules[each.key].match.source_ranges
diff --git a/modules/net-firewall-policy/net-global.tf b/modules/net-firewall-policy/net-global.tf
index db15930da9..cf837c8617 100644
--- a/modules/net-firewall-policy/net-global.tf
+++ b/modules/net-firewall-policy/net-global.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,11 +44,15 @@ resource "google_compute_network_firewall_policy_rule" "net-global" {
action = local.rules[each.key].action
description = local.rules[each.key].description
direction = local.rules[each.key].direction
- security_profile_group = local.rules[each.key].security_profile_group
disabled = local.rules[each.key].disabled
enable_logging = local.rules[each.key].enable_logging
priority = local.rules[each.key].priority
target_service_accounts = local.rules[each.key].target_service_accounts
+ tls_inspect = local.rules[each.key].tls_inspect
+ security_profile_group = try(
+ var.security_profile_group_ids[local.rules[each.key].security_profile_group],
+ local.rules[each.key].security_profile_group
+ )
match {
dest_ip_ranges = local.rules[each.key].match.destination_ranges
src_ip_ranges = local.rules[each.key].match.source_ranges
diff --git a/modules/net-firewall-policy/net-regional.tf b/modules/net-firewall-policy/net-regional.tf
index a3d9f53da6..281cbc4f91 100644
--- a/modules/net-firewall-policy/net-regional.tf
+++ b/modules/net-firewall-policy/net-regional.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,6 @@ resource "google_compute_region_network_firewall_policy_rule" "net-regional" {
action = local.rules[each.key].action
description = local.rules[each.key].description
direction = local.rules[each.key].direction
- security_profile_group = local.rules[each.key].security_profile_group
disabled = local.rules[each.key].disabled
enable_logging = local.rules[each.key].enable_logging
priority = local.rules[each.key].priority
diff --git a/modules/net-firewall-policy/variables.tf b/modules/net-firewall-policy/variables.tf
index fad6ab9043..bab3ee8531 100644
--- a/modules/net-firewall-policy/variables.tf
+++ b/modules/net-firewall-policy/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ variable "egress_rules" {
target_resources = optional(list(string))
target_service_accounts = optional(list(string))
target_tags = optional(list(string))
+ tls_inspect = optional(bool, null)
match = object({
address_groups = optional(list(string))
fqdns = optional(list(string))
@@ -87,6 +88,7 @@ variable "ingress_rules" {
target_resources = optional(list(string))
target_service_accounts = optional(list(string))
target_tags = optional(list(string))
+ tls_inspect = optional(bool, null)
match = object({
address_groups = optional(list(string))
fqdns = optional(list(string))
@@ -129,3 +131,10 @@ variable "region" {
type = string
default = null
}
+
+variable "security_profile_group_ids" {
+ description = "The optional security groups ids to be referenced in factories."
+ type = map(string)
+ nullable = false
+ default = {}
+}
diff --git a/tests/modules/net_firewall_policy/examples/factory-spg.yaml b/tests/modules/net_firewall_policy/examples/factory-spg.yaml
new file mode 100644
index 0000000000..82353b4cf5
--- /dev/null
+++ b/tests/modules/net_firewall_policy/examples/factory-spg.yaml
@@ -0,0 +1,105 @@
+# Copyright 2024 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.
+
+values:
+ google_network_security_security_profile.security_profile:
+ description: null
+ labels: null
+ location: global
+ name: security-profile
+ parent: organizations/0123456789
+ threat_prevention_profile: []
+ type: THREAT_PREVENTION
+ google_network_security_security_profile_group.security_profile_group:
+ description: Sample security profile group.
+ labels: null
+ location: global
+ name: security-profile-group
+ parent: organizations/0123456789
+ module.firewall-policy.google_compute_firewall_policy.hierarchical[0]:
+ description: null
+ parent: my-project
+ short_name: fw-policy
+ module.firewall-policy.google_compute_firewall_policy_association.hierarchical["my-vpc"]:
+ name: fw-policy-my-vpc
+ module.firewall-policy.google_compute_firewall_policy_rule.hierarchical["ingress/http"]:
+ action: apply_security_profile_group
+ description: null
+ direction: INGRESS
+ disabled: false
+ enable_logging: null
+ match:
+ - dest_address_groups: null
+ dest_fqdns: null
+ dest_ip_ranges: null
+ dest_region_codes: null
+ dest_threat_intelligences: null
+ layer4_configs:
+ - ip_protocol: tcp
+ ports:
+ - '80'
+ src_address_groups: null
+ src_fqdns: null
+ src_ip_ranges:
+ - 10.0.0.0/8
+ src_region_codes: null
+ src_threat_intelligences: null
+ priority: 1000
+ target_resources: null
+ target_service_accounts: null
+ tls_inspect: null
+ module.vpc.google_compute_network.network[0]:
+ auto_create_subnetworks: false
+ delete_default_routes_on_create: false
+ description: Terraform-managed.
+ enable_ula_internal_ipv6: null
+ name: my-network
+ network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL
+ project: my-project
+ routing_mode: GLOBAL
+ module.vpc.google_compute_route.gateway["private-googleapis"]:
+ description: Terraform-managed.
+ dest_range: 199.36.153.8/30
+ name: my-network-private-googleapis
+ network: my-network
+ next_hop_gateway: default-internet-gateway
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_vpn_tunnel: null
+ priority: 1000
+ project: my-project
+ tags: null
+ module.vpc.google_compute_route.gateway["restricted-googleapis"]:
+ description: Terraform-managed.
+ dest_range: 199.36.153.4/30
+ name: my-network-restricted-googleapis
+ network: my-network
+ next_hop_gateway: default-internet-gateway
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_vpn_tunnel: null
+ priority: 1000
+ project: my-project
+ tags: null
+
+counts:
+ google_compute_firewall_policy: 1
+ google_compute_firewall_policy_association: 1
+ google_compute_firewall_policy_rule: 1
+ google_compute_network: 1
+ google_compute_route: 2
+ google_network_security_security_profile: 1
+ google_network_security_security_profile_group: 1
+ modules: 2
+ resources: 8