diff --git a/modules/net-lb-int/README.md b/modules/net-lb-int/README.md
index 5ed7b40a9..99ae056fe 100644
--- a/modules/net-lb-int/README.md
+++ b/modules/net-lb-int/README.md
@@ -374,20 +374,21 @@ One other issue is a `Provider produced inconsistent final plan` error which is
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L188) | Name used for all resources. | string | ✓ | |
-| [project_id](variables.tf#L193) | Project id where resources will be created. | string | ✓ | |
-| [region](variables.tf#L198) | GCP region. | string | ✓ | |
-| [vpc_config](variables.tf#L224) | VPC-level configuration. | object({…}) | ✓ | |
+| [name](variables.tf#L201) | Name used for all resources. | string | ✓ | |
+| [project_id](variables.tf#L206) | Project id where resources will be created. | string | ✓ | |
+| [region](variables.tf#L211) | GCP region. | string | ✓ | |
+| [vpc_config](variables.tf#L237) | VPC-level configuration. | object({…}) | ✓ | |
| [backend_service_config](variables.tf#L17) | Backend service level configuration. | object({…}) | | {} |
| [backends](variables.tf#L53) | Load balancer backends. | list(object({…})) | | [] |
-| [description](variables.tf#L64) | Optional description used for resources. | string | | "Terraform managed." |
-| [forwarding_rules_config](variables.tf#L70) | The optional forwarding rules configuration. | map(object({…})) | | {…} |
-| [group_configs](variables.tf#L86) | Optional unmanaged groups to create. Can be referenced in backends via outputs. | map(object({…})) | | {} |
-| [health_check](variables.tf#L98) | Name of existing health check to use, disables auto-created health check. Also set `health_check_config = null` when cross-referencing an health check from another load balancer module to avoid a Terraform error. | string | | null |
-| [health_check_config](variables.tf#L104) | Optional auto-created health check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | object({…}) | | {…} |
-| [labels](variables.tf#L182) | Labels set on resources. | map(string) | | {} |
-| [service_attachments](variables.tf#L203) | PSC service attachments, keyed by forwarding rule. | map(object({…})) | | null |
-| [service_label](variables.tf#L218) | Optional prefix of the fully qualified forwarding rule name. | string | | null |
+| [context](variables.tf#L64) | Context-specific interpolations. | object({…}) | | {} |
+| [description](variables.tf#L77) | Optional description used for resources. | string | | "Terraform managed." |
+| [forwarding_rules_config](variables.tf#L83) | The optional forwarding rules configuration. | map(object({…})) | | {…} |
+| [group_configs](variables.tf#L99) | Optional unmanaged groups to create. Can be referenced in backends via outputs. | map(object({…})) | | {} |
+| [health_check](variables.tf#L111) | Name of existing health check to use, disables auto-created health check. Also set `health_check_config = null` when cross-referencing an health check from another load balancer module to avoid a Terraform error. | string | | null |
+| [health_check_config](variables.tf#L117) | Optional auto-created health check configuration, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | object({…}) | | {…} |
+| [labels](variables.tf#L195) | Labels set on resources. | map(string) | | {} |
+| [service_attachments](variables.tf#L216) | PSC service attachments, keyed by forwarding rule. | map(object({…})) | | null |
+| [service_label](variables.tf#L231) | Optional prefix of the fully qualified forwarding rule name. | string | | null |
## Outputs
diff --git a/modules/net-lb-int/groups.tf b/modules/net-lb-int/groups.tf
index 736dfc6f5..3492f5b3d 100644
--- a/modules/net-lb-int/groups.tf
+++ b/modules/net-lb-int/groups.tf
@@ -18,8 +18,8 @@
resource "google_compute_instance_group" "default" {
for_each = var.group_configs
- project = var.project_id
- zone = each.value.zone
+ project = local.project_id
+ zone = lookup(local.ctx.locations, each.value.zone, each.value.zone)
name = "${var.name}-${each.key}"
description = each.value.description
instances = each.value.instances
diff --git a/modules/net-lb-int/health-check.tf b/modules/net-lb-int/health-check.tf
index 1e0bd193b..18bc4ccac 100644
--- a/modules/net-lb-int/health-check.tf
+++ b/modules/net-lb-int/health-check.tf
@@ -31,7 +31,7 @@ locals {
resource "google_compute_health_check" "default" {
provider = google-beta
count = local.hc != null ? 1 : 0
- project = var.project_id
+ project = local.project_id
name = coalesce(local.hc.name, var.name)
description = local.hc.description
check_interval_sec = local.hc.check_interval_sec
diff --git a/modules/net-lb-int/main.tf b/modules/net-lb-int/main.tf
index 201d1e3eb..c517c662b 100644
--- a/modules/net-lb-int/main.tf
+++ b/modules/net-lb-int/main.tf
@@ -16,19 +16,34 @@
locals {
+ _service_attachments = (
+ var.service_attachments == null ? {} : var.service_attachments
+ )
bs_conntrack = var.backend_service_config.connection_tracking
bs_failover = var.backend_service_config.failover_config
forwarding_rule_names = {
for k, v in var.forwarding_rules_config :
k => k == "" ? var.name : "${var.name}-${k}"
}
+ ctx = {
+ for k, v in var.context : k => {
+ for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
+ }
+ }
+ ctx_p = "$"
health_check = (
var.health_check != null
? var.health_check
: google_compute_health_check.default[0].self_link
)
- _service_attachments = (
- var.service_attachments == null ? {} : var.service_attachments
+ network = lookup(
+ local.ctx.networks, var.vpc_config.network, var.vpc_config.network
+ )
+ project_id = lookup(
+ local.ctx.project_ids, var.project_id, var.project_id
+ )
+ region = lookup(
+ local.ctx.locations, var.region, var.region
)
service_attachments = {
for k, v in local._service_attachments :
@@ -44,36 +59,38 @@ moved {
resource "google_compute_forwarding_rule" "default" {
for_each = var.forwarding_rules_config
provider = google-beta
- project = var.project_id
+ project = local.project_id
name = coalesce(each.value.name, local.forwarding_rule_names[each.key])
- region = var.region
+ region = local.region
description = each.value.description
- ip_address = each.value.address
+ ip_address = try(local.ctx.addresses[each.value.address], each.value.address)
ip_protocol = each.value.protocol
ip_version = each.value.address != null ? null : each.value.ipv6 == true ? "IPV6" : "IPV4" # do not set if address is provided
backend_service = (
google_compute_region_backend_service.default.self_link
)
load_balancing_scheme = "INTERNAL"
- network = var.vpc_config.network
+ network = local.network
ports = each.value.ports # "nnnnn" or "nnnnn,nnnnn,nnnnn" max 5
- subnetwork = var.vpc_config.subnetwork
- allow_global_access = each.value.global_access
- labels = var.labels
- all_ports = each.value.ports == null ? true : null
- service_label = var.service_label
+ subnetwork = lookup(
+ local.ctx.subnets, var.vpc_config.subnetwork, var.vpc_config.subnetwork
+ )
+ allow_global_access = each.value.global_access
+ labels = var.labels
+ all_ports = each.value.ports == null ? true : null
+ service_label = var.service_label
# is_mirroring_collector = false
}
resource "google_compute_region_backend_service" "default" {
provider = google-beta
- project = var.project_id
- region = var.region
+ project = local.project_id
+ region = local.region
name = coalesce(var.backend_service_config.name, var.name)
description = var.backend_service_config.description
load_balancing_scheme = "INTERNAL"
protocol = var.backend_service_config.protocol
- network = var.vpc_config.network
+ network = local.network
health_checks = [local.health_check]
connection_draining_timeout_sec = var.backend_service_config.connection_draining_timeout_sec
session_affinity = var.backend_service_config.session_affinity
@@ -135,12 +152,14 @@ resource "google_compute_region_backend_service" "default" {
resource "google_compute_service_attachment" "default" {
for_each = local.service_attachments
- project = var.project_id
- region = var.region
+ project = local.project_id
+ region = local.region
name = local.forwarding_rule_names[each.key]
description = var.description
target_service = google_compute_forwarding_rule.default[each.key].id
- nat_subnets = each.value.nat_subnets
+ nat_subnets = each.value.nat_subnets == null ? null : [
+ for s in each.value.nat_subnets : lookup(local.ctx.subnets, s, s)
+ ]
connection_preference = (
each.value.automatic_connection ? "ACCEPT_AUTOMATIC" : "ACCEPT_MANUAL"
)
diff --git a/modules/net-lb-int/variables.tf b/modules/net-lb-int/variables.tf
index 5df659c0a..5b023581f 100644
--- a/modules/net-lb-int/variables.tf
+++ b/modules/net-lb-int/variables.tf
@@ -61,6 +61,19 @@ variable "backends" {
nullable = false
}
+variable "context" {
+ description = "Context-specific interpolations."
+ type = object({
+ addresses = optional(map(string), {})
+ locations = optional(map(string), {})
+ networks = optional(map(string), {})
+ project_ids = optional(map(string), {})
+ subnets = optional(map(string), {})
+ })
+ default = {}
+ nullable = false
+}
+
variable "description" {
description = "Optional description used for resources."
type = string
diff --git a/modules/net-vpc-firewall/README.md b/modules/net-vpc-firewall/README.md
index 8750d073f..f074556e8 100644
--- a/modules/net-vpc-firewall/README.md
+++ b/modules/net-vpc-firewall/README.md
@@ -269,13 +269,14 @@ module "firewall" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [network](variables.tf#L111) | Name of the network this set of firewall rules applies to. | string | ✓ | |
-| [project_id](variables.tf#L116) | Project id of the project that holds the network. | string | ✓ | |
-| [default_rules_config](variables.tf#L17) | Optionally created convenience rules. Set the 'disabled' attribute to true, or individual rule attributes to empty lists to disable. | object({…}) | | {} |
-| [egress_rules](variables.tf#L37) | List of egress rule definitions, default to deny action. Null destination ranges will be replaced with 0/0. | map(object({…})) | | {} |
-| [factories_config](variables.tf#L60) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
-| [ingress_rules](variables.tf#L70) | List of ingress rule definitions, default to allow action. Null source ranges will be replaced with 0/0. | map(object({…})) | | {} |
-| [named_ranges](variables.tf#L94) | Define mapping of names to ranges that can be used in custom rules. | map(list(string)) | | {…} |
+| [network](variables.tf#L123) | Name of the network this set of firewall rules applies to. | string | ✓ | |
+| [project_id](variables.tf#L128) | Project id of the project that holds the network. | string | ✓ | |
+| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} |
+| [default_rules_config](variables.tf#L29) | Optionally created convenience rules. Set the 'disabled' attribute to true, or individual rule attributes to empty lists to disable. | object({…}) | | {} |
+| [egress_rules](variables.tf#L49) | List of egress rule definitions, default to deny action. Null destination ranges will be replaced with 0/0. | map(object({…})) | | {} |
+| [factories_config](variables.tf#L72) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [ingress_rules](variables.tf#L82) | List of ingress rule definitions, default to allow action. Null source ranges will be replaced with 0/0. | map(object({…})) | | {} |
+| [named_ranges](variables.tf#L106) | Define mapping of names to ranges that can be used in custom rules. | map(list(string)) | | {…} |
## Outputs
diff --git a/modules/net-vpc-firewall/default-rules.tf b/modules/net-vpc-firewall/default-rules.tf
index bbca6dd57..a0f38ab70 100644
--- a/modules/net-vpc-firewall/default-rules.tf
+++ b/modules/net-vpc-firewall/default-rules.tf
@@ -25,23 +25,27 @@ locals {
}
resource "google_compute_firewall" "allow-admins" {
- count = length(local.default_rules.admin_ranges) > 0 ? 1 : 0
- name = "${var.network}-ingress-admins"
- description = "Access from the admin subnet to all subnets."
- network = var.network
- project = var.project_id
- source_ranges = local.default_rules.admin_ranges
+ count = length(local.default_rules.admin_ranges) > 0 ? 1 : 0
+ project = local.project_id
+ network = local.network
+ name = "${local.network_name}-ingress-admins"
+ description = "Access from the admin subnet to all subnets."
+ source_ranges = [
+ for r in local.default_rules.admin_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
allow { protocol = "all" }
}
resource "google_compute_firewall" "allow-tag-http" {
- count = length(local.default_rules.http_ranges) > 0 ? 1 : 0
- name = "${var.network}-ingress-tag-http"
- description = "Allow http to machines with matching tags."
- network = var.network
- project = var.project_id
- source_ranges = local.default_rules.http_ranges
- target_tags = local.default_rules.http_tags
+ count = length(local.default_rules.http_ranges) > 0 ? 1 : 0
+ project = local.project_id
+ network = local.network
+ name = "${local.network_name}-ingress-tag-http"
+ description = "Allow http to machines with matching tags."
+ source_ranges = [
+ for r in local.default_rules.http_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
+ target_tags = local.default_rules.http_tags
allow {
protocol = "tcp"
ports = ["80"]
@@ -49,13 +53,15 @@ resource "google_compute_firewall" "allow-tag-http" {
}
resource "google_compute_firewall" "allow-tag-https" {
- count = length(local.default_rules.https_ranges) > 0 ? 1 : 0
- name = "${var.network}-ingress-tag-https"
- description = "Allow http to machines with matching tags."
- network = var.network
- project = var.project_id
- source_ranges = local.default_rules.https_ranges
- target_tags = local.default_rules.https_tags
+ count = length(local.default_rules.https_ranges) > 0 ? 1 : 0
+ project = local.project_id
+ network = local.network
+ name = "${local.network_name}-ingress-tag-https"
+ description = "Allow http to machines with matching tags."
+ source_ranges = [
+ for r in local.default_rules.https_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
+ target_tags = local.default_rules.https_tags
allow {
protocol = "tcp"
ports = ["443"]
@@ -63,13 +69,15 @@ resource "google_compute_firewall" "allow-tag-https" {
}
resource "google_compute_firewall" "allow-tag-ssh" {
- count = length(local.default_rules.ssh_ranges) > 0 ? 1 : 0
- name = "${var.network}-ingress-tag-ssh"
- description = "Allow SSH to machines with matching tags."
- network = var.network
- project = var.project_id
- source_ranges = local.default_rules.ssh_ranges
- target_tags = local.default_rules.ssh_tags
+ count = length(local.default_rules.ssh_ranges) > 0 ? 1 : 0
+ project = local.project_id
+ network = local.network
+ name = "${local.network_name}-ingress-tag-ssh"
+ description = "Allow SSH to machines with matching tags."
+ source_ranges = [
+ for r in local.default_rules.ssh_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
+ target_tags = local.default_rules.ssh_tags
allow {
protocol = "tcp"
ports = ["22"]
diff --git a/modules/net-vpc-firewall/main.tf b/modules/net-vpc-firewall/main.tf
index 5fed5817e..4a55de8ed 100644
--- a/modules/net-vpc-firewall/main.tf
+++ b/modules/net-vpc-firewall/main.tf
@@ -66,6 +66,15 @@ locals {
for name, rule in merge(var.ingress_rules) :
name => merge(rule, { direction = "INGRESS" })
}
+ ctx = {
+ for k, v in var.context : k => {
+ for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
+ }
+ }
+ ctx_p = "$"
+ network = lookup(local.ctx.networks, var.network, var.network)
+ network_name = reverse(split("/", local.network))[0]
+ project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
# convert rules data to resource format and replace range template variables
rules = {
for name, rule in local._rules :
@@ -94,30 +103,32 @@ locals {
resource "google_compute_firewall" "custom-rules" {
for_each = local.rules
- project = var.project_id
- network = var.network
+ project = local.project_id
+ network = local.network
name = each.key
description = each.value.description
direction = each.value.direction
source_ranges = (
- each.value.direction == "INGRESS"
+ each.value.source_ranges == null
? (
- each.value.source_ranges == null && each.value.sources == null
+ each.value.direction == "INGRESS" && each.value.sources == null
? ["0.0.0.0/0"]
- : each.value.source_ranges
+ : null
)
- #for egress, we will include the source_ranges when provided. Previously, null was forced
- : each.value.source_ranges
+ : [
+ for r in each.value.source_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
)
destination_ranges = (
- each.value.direction == "EGRESS"
+ each.value.destination_ranges == null
? (
- each.value.destination_ranges == null
+ each.value.direction == "EGRESS"
? ["0.0.0.0/0"]
- : each.value.destination_ranges
+ : null
)
- #for ingress, we will include the destination_ranges when provided. Previously, null was forced
- : each.value.destination_ranges
+ : [
+ for r in each.value.destination_ranges : lookup(local.ctx.cidr_ranges, r, r)
+ ]
)
source_tags = (
each.value.use_service_accounts || each.value.direction == "EGRESS"
@@ -126,14 +137,19 @@ resource "google_compute_firewall" "custom-rules" {
)
source_service_accounts = (
each.value.use_service_accounts && each.value.direction == "INGRESS"
- ? each.value.sources
+ ? (each.value.sources == null ? null : [
+ for s in each.value.sources : lookup(local.ctx.iam_principals, s, s)
+ ])
: null
)
target_tags = (
- each.value.use_service_accounts ? null : each.value.targets
+ !each.value.use_service_accounts ? each.value.targets : null
)
target_service_accounts = (
- each.value.use_service_accounts ? each.value.targets : null
+ !each.value.use_service_accounts ? null : (
+ each.value.targets == null ? null : [
+ for s in each.value.targets : lookup(local.ctx.iam_principals, s, s)
+ ])
)
disabled = each.value.disabled == true
priority = each.value.priority
diff --git a/modules/net-vpc-firewall/variables.tf b/modules/net-vpc-firewall/variables.tf
index 104f87d5b..594492694 100644
--- a/modules/net-vpc-firewall/variables.tf
+++ b/modules/net-vpc-firewall/variables.tf
@@ -14,6 +14,18 @@
* limitations under the License.
*/
+variable "context" {
+ description = "Context-specific interpolations."
+ type = object({
+ cidr_ranges = optional(map(string), {})
+ iam_principals = optional(map(string), {})
+ networks = optional(map(string), {})
+ project_ids = optional(map(string), {})
+ })
+ default = {}
+ nullable = false
+}
+
variable "default_rules_config" {
description = "Optionally created convenience rules. Set the 'disabled' attribute to true, or individual rule attributes to empty lists to disable."
type = object({
diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md
index 8309ec6c4..af95ac727 100644
--- a/modules/net-vpc/README.md
+++ b/modules/net-vpc/README.md
@@ -486,7 +486,7 @@ module "vpc" {
project_id = var.project_id
name = "my-network"
context = {
- regions = {
+ locations = {
primary = "europe-west4"
secondary = "europe-west8"
}
@@ -500,7 +500,7 @@ module "vpc" {
```yaml
name: simple
-region: $regions:primary
+region: $locations:primary
ip_cidr_range: 10.0.1.0/24
# tftest-file id=subnet-simple path=config/subnets/subnet-simple.yaml schema=subnet.schema.json
@@ -899,32 +899,32 @@ secondary_ip_ranges:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L171) | The name of the network being created. | string | ✓ | |
-| [project_id](variables.tf#L248) | The ID of the project where this VPC will be created. | string | ✓ | |
+| [name](variables.tf#L184) | The name of the network being created. | string | ✓ | |
+| [project_id](variables.tf#L261) | The ID of the project where this VPC will be created. | string | ✓ | |
| [auto_create_subnetworks](variables.tf#L17) | Set to true to create an auto mode subnet, defaults to custom mode. | bool | | false |
-| [context](variables.tf#L23) | Context-specific interpolations. | object({…}) | | {} |
-| [create_googleapis_routes](variables.tf#L32) | Toggle creation of googleapis private/restricted routes. Disabled when vpc creation is turned off, or when set to null. | object({…}) | | {} |
-| [delete_default_routes_on_create](variables.tf#L45) | Set to true to delete the default routes at creation time. | bool | | false |
-| [description](variables.tf#L51) | An optional description of this resource (triggers recreation on change). | string | | "Terraform-managed." |
-| [dns_policy](variables.tf#L57) | DNS policy setup for the VPC. | object({…}) | | null |
-| [factories_config](variables.tf#L70) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
-| [firewall_policy_enforcement_order](variables.tf#L79) | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string | | "AFTER_CLASSIC_FIREWALL" |
-| [internal_ranges](variables.tf#L91) | Internal range configuration for IPAM operations within the VPC network. | list(object({…})) | | [] |
-| [ipv6_config](variables.tf#L155) | Optional IPv6 configuration for this network. | object({…}) | | {} |
-| [mtu](variables.tf#L165) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null |
-| [network_attachments](variables.tf#L176) | PSC network attachments, names as keys. | map(object({…})) | | {} |
-| [peering_config](variables.tf#L189) | VPC peering configuration. | object({…}) | | null |
-| [policy_based_routes](variables.tf#L200) | Policy based routes, keyed by name. | map(object({…})) | | {} |
-| [psa_configs](variables.tf#L253) | The Private Service Access configuration. | list(object({…})) | | [] |
-| [routes](variables.tf#L284) | Network routes, keyed by name. | map(object({…})) | | {} |
-| [routing_mode](variables.tf#L305) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" |
-| [shared_vpc_host](variables.tf#L315) | Enable shared VPC for this project. | bool | | false |
-| [shared_vpc_service_projects](variables.tf#L321) | Shared VPC service projects to register with this host. | list(string) | | [] |
-| [subnets](variables.tf#L327) | Subnet configuration. | list(object({…})) | | [] |
-| [subnets_private_nat](variables.tf#L407) | List of private NAT subnets. | list(object({…})) | | [] |
-| [subnets_proxy_only](variables.tf#L419) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] |
-| [subnets_psc](variables.tf#L453) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] |
-| [vpc_reuse](variables.tf#L485) | Reuse existing VPC if not null. If the network_id number is not passed in, a data source is used. | object({…}) | | null |
+| [context](variables.tf#L23) | Context-specific interpolations. | object({…}) | | {} |
+| [create_googleapis_routes](variables.tf#L45) | Toggle creation of googleapis private/restricted routes. Disabled when vpc creation is turned off, or when set to null. | object({…}) | | {} |
+| [delete_default_routes_on_create](variables.tf#L58) | Set to true to delete the default routes at creation time. | bool | | false |
+| [description](variables.tf#L64) | An optional description of this resource (triggers recreation on change). | string | | "Terraform-managed." |
+| [dns_policy](variables.tf#L70) | DNS policy setup for the VPC. | object({…}) | | null |
+| [factories_config](variables.tf#L83) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [firewall_policy_enforcement_order](variables.tf#L92) | Order that Firewall Rules and Firewall Policies are evaluated. Can be either 'BEFORE_CLASSIC_FIREWALL' or 'AFTER_CLASSIC_FIREWALL'. | string | | "AFTER_CLASSIC_FIREWALL" |
+| [internal_ranges](variables.tf#L104) | Internal range configuration for IPAM operations within the VPC network. | list(object({…})) | | [] |
+| [ipv6_config](variables.tf#L168) | Optional IPv6 configuration for this network. | object({…}) | | {} |
+| [mtu](variables.tf#L178) | Maximum Transmission Unit in bytes. The minimum value for this field is 1460 (the default) and the maximum value is 1500 bytes. | number | | null |
+| [network_attachments](variables.tf#L189) | PSC network attachments, names as keys. | map(object({…})) | | {} |
+| [peering_config](variables.tf#L202) | VPC peering configuration. | object({…}) | | null |
+| [policy_based_routes](variables.tf#L213) | Policy based routes, keyed by name. | map(object({…})) | | {} |
+| [psa_configs](variables.tf#L266) | The Private Service Access configuration. | list(object({…})) | | [] |
+| [routes](variables.tf#L297) | Network routes, keyed by name. | map(object({…})) | | {} |
+| [routing_mode](variables.tf#L318) | The network routing mode (default 'GLOBAL'). | string | | "GLOBAL" |
+| [shared_vpc_host](variables.tf#L328) | Enable shared VPC for this project. | bool | | false |
+| [shared_vpc_service_projects](variables.tf#L334) | Shared VPC service projects to register with this host. | list(string) | | [] |
+| [subnets](variables.tf#L340) | Subnet configuration. | list(object({…})) | | [] |
+| [subnets_private_nat](variables.tf#L420) | List of private NAT subnets. | list(object({…})) | | [] |
+| [subnets_proxy_only](variables.tf#L432) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | list(object({…})) | | [] |
+| [subnets_psc](variables.tf#L466) | List of subnets for Private Service Connect service producers. | list(object({…})) | | [] |
+| [vpc_reuse](variables.tf#L498) | Reuse existing VPC if not null. If the network_id number is not passed in, a data source is used. | object({…}) | | null |
## Outputs
diff --git a/modules/net-vpc/internal-ranges.tf b/modules/net-vpc/internal-ranges.tf
index 2304919d4..0a78b6717 100644
--- a/modules/net-vpc/internal-ranges.tf
+++ b/modules/net-vpc/internal-ranges.tf
@@ -52,12 +52,10 @@ locals {
}
}
}
-
internal_ranges = merge(
{ for r in var.internal_ranges : r.name => r },
local._factory_internal_ranges
)
-
internal_ranges_ids = {
for k, v in google_network_connectivity_internal_range.internal_range :
k => v.id
@@ -65,14 +63,15 @@ locals {
}
resource "google_network_connectivity_internal_range" "internal_range" {
- provider = google-beta
- for_each = local.internal_ranges
- project = var.project_id
- name = each.value.name
- network = local.network.id
-
- description = each.value.description
- ip_cidr_range = each.value.ip_cidr_range
+ provider = google-beta
+ for_each = local.internal_ranges
+ project = local.project_id
+ name = each.value.name
+ network = local.network.id
+ description = each.value.description
+ ip_cidr_range = try(
+ local.ctx.cidr_ranges[each.value.ip_cidr_range], each.value.ip_cidr_range
+ )
labels = each.value.labels
usage = each.value.usage
peering = each.value.peering
diff --git a/modules/net-vpc/main.tf b/modules/net-vpc/main.tf
index 6fa23edd9..446505cb5 100644
--- a/modules/net-vpc/main.tf
+++ b/modules/net-vpc/main.tf
@@ -15,11 +15,14 @@
*/
locals {
- ctx = {
+ _ctx = {
for k, v in var.context : k => {
for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
}
}
+ ctx = merge(local._ctx, {
+ locations = merge(local._ctx.regions, local._ctx.locations)
+ })
ctx_p = "$"
network = (
var.vpc_reuse == null
@@ -56,19 +59,28 @@ locals {
peer_network = (
var.peering_config == null
? null
- : element(reverse(split("/", var.peering_config.peer_vpc_self_link)), 0)
+ : (
+ startswith(var.peering_config.peer_vpc_self_link, "$networks:")
+ ? lookup(
+ local.ctx.networks,
+ var.peering_config.peer_vpc_self_link,
+ var.peering_config.peer_vpc_self_link
+ )
+ : element(reverse(split("/", var.peering_config.peer_vpc_self_link)), 0)
+ )
)
+ project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
}
data "google_compute_network" "network" {
count = try(var.vpc_reuse.use_data_source, null) == true ? 1 : 0
name = var.name
- project = var.project_id
+ project = local.project_id
}
resource "google_compute_network" "network" {
count = var.vpc_reuse == null ? 1 : 0
- project = var.project_id
+ project = local.project_id
name = var.name
description = var.description
auto_create_subnetworks = var.auto_create_subnetworks
@@ -81,11 +93,15 @@ resource "google_compute_network" "network" {
}
resource "google_compute_network_peering" "local" {
- provider = google-beta
- count = var.peering_config == null ? 0 : 1
- name = "${var.name}-${local.peer_network}"
- network = local.network.self_link
- peer_network = var.peering_config.peer_vpc_self_link
+ provider = google-beta
+ count = var.peering_config == null ? 0 : 1
+ name = "${var.name}-${local.peer_network}"
+ network = local.network.self_link
+ peer_network = lookup(
+ local.ctx.networks,
+ var.peering_config.peer_vpc_self_link,
+ var.peering_config.peer_vpc_self_link
+ )
export_custom_routes = var.peering_config.export_routes
import_custom_routes = var.peering_config.import_routes
}
@@ -97,8 +113,12 @@ resource "google_compute_network_peering" "remote" {
? 1
: 0
)
- name = "${local.peer_network}-${var.name}"
- network = var.peering_config.peer_vpc_self_link
+ name = "${local.peer_network}-${var.name}"
+ network = lookup(
+ local.ctx.networks,
+ var.peering_config.peer_vpc_self_link,
+ var.peering_config.peer_vpc_self_link
+ )
peer_network = local.network.self_link
export_custom_routes = var.peering_config.import_routes
import_custom_routes = var.peering_config.export_routes
@@ -108,7 +128,7 @@ resource "google_compute_network_peering" "remote" {
resource "google_compute_shared_vpc_host_project" "shared_vpc_host" {
provider = google-beta
count = var.shared_vpc_host ? 1 : 0
- project = var.project_id
+ project = local.project_id
depends_on = [local.network]
}
@@ -119,14 +139,14 @@ resource "google_compute_shared_vpc_service_project" "service_projects" {
? var.shared_vpc_service_projects
: []
)
- host_project = var.project_id
- service_project = each.value
+ host_project = local.project_id
+ service_project = lookup(local.ctx.project_ids, each.value, each.value)
depends_on = [google_compute_shared_vpc_host_project.shared_vpc_host]
}
resource "google_dns_policy" "default" {
count = var.dns_policy == null ? 0 : 1
- project = var.project_id
+ project = local.project_id
name = var.name
enable_inbound_forwarding = try(var.dns_policy.inbound, null)
enable_logging = try(var.dns_policy.logging, null)
@@ -145,7 +165,7 @@ resource "google_dns_policy" "default" {
)
iterator = ns
content {
- ipv4_address = ns.value
+ ipv4_address = lookup(local.ctx.addresses, ns.value, ns.value)
forwarding_path = "private"
}
}
@@ -157,7 +177,7 @@ resource "google_dns_policy" "default" {
)
iterator = ns
content {
- ipv4_address = ns.value
+ ipv4_address = lookup(local.ctx.addresses, ns.value, ns.value)
}
}
}
diff --git a/modules/net-vpc/psa.tf b/modules/net-vpc/psa.tf
index 959193896..8b9855896 100644
--- a/modules/net-vpc/psa.tf
+++ b/modules/net-vpc/psa.tf
@@ -44,7 +44,8 @@ locals {
})
}
psa_configs_ranges = {
- for v in local._psa_configs_ranges : v.key => v.value
+ for v in local._psa_configs_ranges :
+ v.key => lookup(local.ctx.cidr_ranges, v.value, v.value)
}
psa_peered_domains = {
for v in local._psa_peered_domains : v.key => v
@@ -53,7 +54,7 @@ locals {
resource "google_compute_global_address" "psa_ranges" {
for_each = local.psa_configs_ranges
- project = var.project_id
+ project = local.project_id
network = local.network.id
name = each.key
purpose = "VPC_PEERING"
diff --git a/modules/net-vpc/routes.tf b/modules/net-vpc/routes.tf
index e8fd8812b..c31440aee 100644
--- a/modules/net-vpc/routes.tf
+++ b/modules/net-vpc/routes.tf
@@ -50,36 +50,42 @@ locals {
}
resource "google_compute_route" "gateway" {
- for_each = local.routes.gateway
- project = var.project_id
- network = local.network.name
- name = "${var.name}-${each.key}"
- description = each.value.description
- dest_range = each.value.dest_range
+ for_each = local.routes.gateway
+ project = local.project_id
+ network = local.network.name
+ name = "${var.name}-${each.key}"
+ description = each.value.description
+ dest_range = lookup(
+ local.ctx.cidr_ranges, each.value.dest_range, each.value.dest_range
+ )
priority = each.value.priority
tags = each.value.tags
next_hop_gateway = each.value.next_hop
}
resource "google_compute_route" "ilb" {
- for_each = local.routes.ilb
- project = var.project_id
- network = local.network.name
- name = "${var.name}-${each.key}"
- description = each.value.description
- dest_range = each.value.dest_range
+ for_each = local.routes.ilb
+ project = local.project_id
+ network = local.network.name
+ name = "${var.name}-${each.key}"
+ description = each.value.description
+ dest_range = lookup(
+ local.ctx.cidr_ranges, each.value.dest_range, each.value.dest_range
+ )
priority = each.value.priority
tags = each.value.tags
next_hop_ilb = each.value.next_hop
}
resource "google_compute_route" "instance" {
- for_each = local.routes.instance
- project = var.project_id
- network = local.network.name
- name = "${var.name}-${each.key}"
- description = each.value.description
- dest_range = each.value.dest_range
+ for_each = local.routes.instance
+ project = local.project_id
+ network = local.network.name
+ name = "${var.name}-${each.key}"
+ description = each.value.description
+ dest_range = lookup(
+ local.ctx.cidr_ranges, each.value.dest_range, each.value.dest_range
+ )
priority = each.value.priority
tags = each.value.tags
next_hop_instance = each.value.next_hop
@@ -89,23 +95,29 @@ resource "google_compute_route" "instance" {
resource "google_compute_route" "ip" {
for_each = local.routes.ip
- project = var.project_id
+ project = local.project_id
network = local.network.name
name = "${var.name}-${each.key}"
description = each.value.description
- dest_range = each.value.dest_range
- priority = each.value.priority
- tags = each.value.tags
- next_hop_ip = each.value.next_hop
+ dest_range = lookup(
+ local.ctx.cidr_ranges, each.value.dest_range, each.value.dest_range
+ )
+ priority = each.value.priority
+ tags = each.value.tags
+ next_hop_ip = lookup(
+ local.ctx.addresses, each.value.next_hop, each.value.next_hop
+ )
}
resource "google_compute_route" "vpn_tunnel" {
- for_each = local.routes.vpn_tunnel
- project = var.project_id
- network = local.network.name
- name = "${var.name}-${each.key}"
- description = each.value.description
- dest_range = each.value.dest_range
+ for_each = local.routes.vpn_tunnel
+ project = local.project_id
+ network = local.network.name
+ name = "${var.name}-${each.key}"
+ description = each.value.description
+ dest_range = lookup(
+ local.ctx.cidr_ranges, each.value.dest_range, each.value.dest_range
+ )
priority = each.value.priority
tags = each.value.tags
next_hop_vpn_tunnel = each.value.next_hop
@@ -113,7 +125,7 @@ resource "google_compute_route" "vpn_tunnel" {
resource "google_network_connectivity_policy_based_route" "default" {
for_each = var.policy_based_routes
- project = var.project_id
+ project = local.project_id
network = local.network.id
name = "${var.name}-${each.key}"
description = each.value.description
diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf
index 5d3ff70f0..6d6f5891e 100644
--- a/modules/net-vpc/subnets.tf
+++ b/modules/net-vpc/subnets.tf
@@ -23,7 +23,7 @@ locals {
}
_factory_data = {
for k, v in local._factory_data_raw : k => merge(v, {
- region_computed = lookup(local.ctx.regions, v.region, v.region)
+ region_computed = lookup(local.ctx.locations, v.region, v.region)
})
}
_factory_path = try(pathexpand(var.factories_config.subnets_folder), null)
@@ -88,7 +88,9 @@ locals {
_is_proxy_only = try(v.proxy_only == true, false)
}
}
-
+ _iam_subnets = concat(
+ var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)
+ )
all_subnets = merge(
{ for k, v in google_compute_subnetwork.subnetwork : k => v },
{ for k, v in google_compute_subnetwork.proxy_only : k => v },
@@ -96,22 +98,21 @@ locals {
)
subnet_iam = flatten(concat(
[
- for s in concat(var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)) : [
- for role, members in s.iam :
- {
- role = role
+ for s in local._iam_subnets : [
+ for role, members in s.iam : {
+ role = lookup(local.ctx.custom_roles, role, role)
members = members
- subnet = "${s.region}/${s.name}"
+ subnet = "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}"
}
]
],
))
subnet_iam_bindings = merge([
- for s in concat(var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)) : {
+ for s in local._iam_subnets : {
for key, data in s.iam_bindings :
key => {
- role = data.role
- subnet = "${s.region}/${s.name}"
+ role = lookup(local.ctx.custom_roles, data.role, data.role)
+ subnet = "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}"
members = data.members
condition = data.condition
}
@@ -121,42 +122,60 @@ locals {
# In other words, if you have multiple additive bindings with the
# same name, only one will be used
subnet_iam_bindings_additive = merge([
- for s in concat(var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)) : {
+ for s in local._iam_subnets : {
for key, data in s.iam_bindings_additive :
key => {
- role = data.role
- subnet = "${s.region}/${s.name}"
+ role = lookup(local.ctx.custom_roles, data.role, data.role)
+ subnet = "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}"
member = data.member
condition = data.condition
}
}
]...)
subnets = merge(
- { for s in var.subnets : "${s.region}/${s.name}" => s },
+ {
+ for s in var.subnets :
+ "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}" => s
+ },
{ for k, v in local._factory_subnets : k => v if v._is_regular }
)
subnets_proxy_only = merge(
- { for s in var.subnets_proxy_only : "${s.region}/${s.name}" => s },
+ {
+ for s in var.subnets_proxy_only :
+ "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}" => s
+ },
{ for k, v in local._factory_subnets : k => v if v._is_proxy_only },
)
subnets_private_nat = merge(
- { for s in var.subnets_private_nat : "${s.region}/${s.name}" => s },
+ {
+ for s in var.subnets_private_nat :
+ "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}" => s
+ },
# { for k, v in local._factory_subnets : k => v if v._is_proxy_only },
)
subnets_psc = merge(
- { for s in var.subnets_psc : "${s.region}/${s.name}" => s },
+ {
+ for s in var.subnets_psc :
+ "${lookup(local.ctx.locations, s.region, s.region)}/${s.name}" => s
+ },
{ for k, v in local._factory_subnets : k => v if v._is_psc }
)
}
resource "google_compute_subnetwork" "subnetwork" {
- provider = google-beta
- for_each = local.subnets
- project = var.project_id
- network = local.network.name
- name = each.value.name
- region = each.value.region
- ip_cidr_range = try(each.value.ipv6.ipv6_only, false) ? null : each.value.ip_cidr_range
+ provider = google-beta
+ for_each = local.subnets
+ project = local.project_id
+ network = local.network.name
+ name = each.value.name
+ region = lookup(
+ local.ctx.locations, each.value.region, each.value.region
+ )
+ ip_cidr_range = (
+ try(each.value.ipv6.ipv6_only, false)
+ ? null
+ : try(local.ctx.cidr_ranges[each.value.ip_cidr_range], each.value.ip_cidr_range)
+ )
allow_subnet_cidr_routes_overlap = each.value.allow_subnet_cidr_routes_overlap
reserved_internal_range = (
each.value.reserved_internal_range != null
@@ -189,8 +208,13 @@ resource "google_compute_subnetwork" "subnetwork" {
dynamic "secondary_ip_range" {
for_each = each.value.secondary_ip_ranges == null ? {} : each.value.secondary_ip_ranges
content {
- range_name = secondary_ip_range.key
- ip_cidr_range = try(secondary_ip_range.value.ip_cidr_range, secondary_ip_range.value)
+ range_name = secondary_ip_range.key
+ ip_cidr_range = try(
+ local.ctx.cidr_ranges[secondary_ip_range.value.ip_cidr_range],
+ secondary_ip_range.value.ip_cidr_range,
+ local.ctx.cidr_ranges[secondary_ip_range.value],
+ secondary_ip_range.value
+ )
reserved_internal_range = (
try(secondary_ip_range.value.reserved_internal_range, null) != null
? "networkconnectivity.googleapis.com/${try(local.internal_ranges_ids[secondary_ip_range.value.reserved_internal_range], secondary_ip_range.value.reserved_internal_range)}"
@@ -215,12 +239,16 @@ resource "google_compute_subnetwork" "subnetwork" {
}
resource "google_compute_subnetwork" "proxy_only" {
- for_each = local.subnets_proxy_only
- project = var.project_id
- network = local.network.name
- name = each.value.name
- region = each.value.region
- ip_cidr_range = each.value.ip_cidr_range
+ for_each = local.subnets_proxy_only
+ project = local.project_id
+ network = local.network.name
+ name = each.value.name
+ region = lookup(
+ local.ctx.locations, each.value.region, each.value.region
+ )
+ ip_cidr_range = lookup(
+ local.ctx.cidr_ranges, each.value.ip_cidr_range, each.value.ip_cidr_range
+ )
description = (
# Set description to an empty string (eg "") to create subnet without a description.
each.value.description == null
@@ -232,12 +260,16 @@ resource "google_compute_subnetwork" "proxy_only" {
}
resource "google_compute_subnetwork" "private_nat" {
- for_each = local.subnets_private_nat
- project = var.project_id
- network = local.network.name
- name = each.value.name
- region = each.value.region
- ip_cidr_range = each.value.ip_cidr_range
+ for_each = local.subnets_private_nat
+ project = local.project_id
+ network = local.network.name
+ name = each.value.name
+ region = lookup(
+ local.ctx.locations, each.value.region, each.value.region
+ )
+ ip_cidr_range = lookup(
+ local.ctx.cidr_ranges, each.value.ip_cidr_range, each.value.ip_cidr_range
+ )
description = (
# Set description to an empty string (eg "") to create subnet without a description.
each.value.description == null
@@ -248,12 +280,16 @@ resource "google_compute_subnetwork" "private_nat" {
}
resource "google_compute_subnetwork" "psc" {
- for_each = local.subnets_psc
- project = var.project_id
- network = local.network.name
- name = each.value.name
- region = each.value.region
- ip_cidr_range = each.value.ip_cidr_range
+ for_each = local.subnets_psc
+ project = local.project_id
+ network = local.network.name
+ name = each.value.name
+ region = lookup(
+ local.ctx.locations, each.value.region, each.value.region
+ )
+ ip_cidr_range = lookup(
+ local.ctx.cidr_ranges, each.value.ip_cidr_range, each.value.ip_cidr_range
+ )
description = (
# Set description to an empty string (eg "") to create subnet without a description.
each.value.description == null
@@ -269,24 +305,30 @@ resource "google_compute_subnetwork_iam_binding" "authoritative" {
for binding in local.subnet_iam :
"${binding.subnet}.${binding.role}" => binding
}
- project = var.project_id
+ project = local.project_id
subnetwork = local.all_subnets[each.value.subnet].name
region = local.all_subnets[each.value.subnet].region
role = each.value.role
- members = each.value.members
+ members = [
+ for m in each.value.members : lookup(local.ctx.iam_principals, m, m)
+ ]
}
resource "google_compute_subnetwork_iam_binding" "bindings" {
for_each = local.subnet_iam_bindings
- project = var.project_id
+ project = local.project_id
subnetwork = local.all_subnets[each.value.subnet].name
region = local.all_subnets[each.value.subnet].region
role = each.value.role
- members = each.value.members
+ members = [
+ for m in each.value.members : lookup(local.ctx.iam_principals, m, m)
+ ]
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
- expression = each.value.condition.expression
+ expression = templatestring(
+ each.value.condition.expression, var.context.condition_vars
+ )
title = each.value.condition.title
description = each.value.condition.description
}
@@ -295,15 +337,19 @@ resource "google_compute_subnetwork_iam_binding" "bindings" {
resource "google_compute_subnetwork_iam_member" "bindings" {
for_each = local.subnet_iam_bindings_additive
- project = var.project_id
+ project = local.project_id
subnetwork = local.all_subnets[each.value.subnet].name
region = local.all_subnets[each.value.subnet].region
role = each.value.role
- member = each.value.member
+ member = lookup(
+ local.ctx.iam_principals, each.value.member, each.value.member
+ )
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
- expression = each.value.condition.expression
+ expression = templatestring(
+ each.value.condition.expression, var.context.condition_vars
+ )
title = each.value.condition.title
description = each.value.condition.description
}
@@ -313,7 +359,7 @@ resource "google_compute_subnetwork_iam_member" "bindings" {
resource "google_compute_network_attachment" "default" {
provider = google-beta
for_each = var.network_attachments
- project = var.project_id
+ project = local.project_id
region = google_compute_subnetwork.subnetwork[each.value.subnet].region
name = each.key
description = each.value.description
diff --git a/modules/net-vpc/variables.tf b/modules/net-vpc/variables.tf
index 646a75212..1f7c2e02f 100644
--- a/modules/net-vpc/variables.tf
+++ b/modules/net-vpc/variables.tf
@@ -23,10 +23,23 @@ variable "auto_create_subnetworks" {
variable "context" {
description = "Context-specific interpolations."
type = object({
- regions = optional(map(string), {})
+ addresses = optional(map(string), {})
+ cidr_ranges = optional(map(string), {})
+ condition_vars = optional(map(map(string)), {})
+ custom_roles = optional(map(string), {})
+ iam_principals = optional(map(string), {})
+ locations = optional(map(string), {})
+ networks = optional(map(string), {})
+ # legacy context
+ regions = optional(map(string), {})
+ project_ids = optional(map(string), {})
})
default = {}
nullable = false
+ validation {
+ condition = length(var.context.regions) == 0 || length(var.context.locations) == 0
+ error_message = "Only one of locations, regions can be used."
+ }
}
variable "create_googleapis_routes" {
diff --git a/tests/modules/net_lb_int/context.tfvars b/tests/modules/net_lb_int/context.tfvars
new file mode 100644
index 000000000..c2aff4baf
--- /dev/null
+++ b/tests/modules/net_lb_int/context.tfvars
@@ -0,0 +1,42 @@
+context = {
+ addresses = {
+ test = "10.0.0.10"
+ }
+ locations = {
+ ew8 = "europe-west8"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+ subnets = {
+ test = "projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/gce"
+ test-nat = "projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/test-nat"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+}
+project_id = "$project_ids:test"
+region = "$locations:ew8"
+name = "test"
+vpc_config = {
+ network = "$networks:test"
+ subnetwork = "$subnets:test"
+}
+backends = [{
+ group = "foo"
+ failover = false
+}]
+forwarding_rules_config = {
+ "" = {
+ address = "$addresses:test"
+ }
+}
+service_attachments = {
+ "" = {
+ nat_subnets = ["$subnets:test-nat"]
+ }
+}
diff --git a/tests/modules/net_lb_int/context.yaml b/tests/modules/net_lb_int/context.yaml
new file mode 100644
index 000000000..ceebc8374
--- /dev/null
+++ b/tests/modules/net_lb_int/context.yaml
@@ -0,0 +1,126 @@
+# Copyright 2025 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_compute_forwarding_rule.default[""]:
+ all_ports: true
+ allow_global_access: true
+ allow_psc_global_access: null
+ description: null
+ ip_address: 10.0.0.10
+ ip_collection: null
+ ip_protocol: TCP
+ is_mirroring_collector: null
+ labels: null
+ load_balancing_scheme: INTERNAL
+ name: test
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ no_automate_dns_zone: null
+ ports: null
+ project: foo-test-0
+ recreate_closed_psc: false
+ region: europe-west8
+ service_label: null
+ source_ip_ranges: null
+ subnetwork: projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/gce
+ target: null
+ timeouts: null
+ google_compute_health_check.default[0]:
+ check_interval_sec: 5
+ description: Terraform managed.
+ grpc_health_check: []
+ grpc_tls_health_check: []
+ healthy_threshold: 2
+ http2_health_check: []
+ http_health_check: []
+ https_health_check: []
+ name: test
+ project: foo-test-0
+ source_regions: null
+ ssl_health_check: []
+ tcp_health_check:
+ - port: null
+ port_name: null
+ port_specification: USE_SERVING_PORT
+ proxy_header: NONE
+ request: null
+ response: null
+ timeout_sec: 5
+ timeouts: null
+ unhealthy_threshold: 2
+ google_compute_region_backend_service.default:
+ affinity_cookie_ttl_sec: null
+ backend:
+ - balancing_mode: CONNECTION
+ capacity_scaler: null
+ custom_metrics: []
+ description: Terraform managed.
+ failover: false
+ group: foo
+ max_connections: null
+ max_connections_per_endpoint: null
+ max_connections_per_instance: null
+ max_rate: null
+ max_rate_per_endpoint: null
+ max_rate_per_instance: null
+ max_utilization: null
+ circuit_breakers: []
+ connection_draining_timeout_sec: 300
+ connection_tracking_policy: []
+ consistent_hash: []
+ custom_metrics: []
+ description: Terraform managed.
+ dynamic_forwarding: []
+ enable_cdn: null
+ failover_policy: []
+ ha_policy: []
+ iap:
+ - enabled: false
+ oauth2_client_id: null
+ oauth2_client_secret: null
+ ip_address_selection_policy: null
+ load_balancing_scheme: INTERNAL
+ locality_lb_policy: null
+ name: test
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ outlier_detection: []
+ project: foo-test-0
+ protocol: UNSPECIFIED
+ region: europe-west8
+ security_policy: null
+ strong_session_affinity_cookie: []
+ subsetting: []
+ timeouts: null
+ google_compute_service_attachment.default[""]:
+ connection_preference: ACCEPT_MANUAL
+ consumer_accept_lists: []
+ consumer_reject_lists: null
+ description: Terraform managed.
+ domain_names: null
+ enable_proxy_protocol: false
+ name: test
+ nat_subnets:
+ - projects/foo-dev-net-spoke-0/regions/europe-west8/subnetworks/test-nat
+ project: foo-test-0
+ region: europe-west8
+ send_propagated_connection_limit_if_zero: false
+ timeouts: null
+
+counts:
+ google_compute_forwarding_rule: 1
+ google_compute_health_check: 1
+ google_compute_region_backend_service: 1
+ google_compute_service_attachment: 1
+ modules: 0
+ resources: 4
diff --git a/tests/modules/net_lb_int/tftest.yaml b/tests/modules/net_lb_int/tftest.yaml
index 5cc14ee22..0837391d7 100644
--- a/tests/modules/net_lb_int/tftest.yaml
+++ b/tests/modules/net_lb_int/tftest.yaml
@@ -15,5 +15,6 @@
module: modules/net-lb-int
tests:
+ context:
defaults:
forwarding-rule:
diff --git a/tests/modules/net_vpc/context.tfvars b/tests/modules/net_vpc/context.tfvars
new file mode 100644
index 000000000..c54ff5fef
--- /dev/null
+++ b/tests/modules/net_vpc/context.tfvars
@@ -0,0 +1,96 @@
+context = {
+ addresses = {
+ dns-external = "8.8.8.8"
+ dns-internal = "10.10.10.10"
+ test = "10.20.20.20"
+ }
+ cidr_ranges = {
+ rfc1918-10 = "10.0.0.0/8"
+ rfc1918-172 = "172.16.10.0/12"
+ rfc1918-192 = "192.168.0.0/16"
+ test = "8.8.8.8/32"
+ }
+ condition_vars = {
+ organization = {
+ id = 1234567890
+ }
+ }
+ custom_roles = {
+ myrole = "organizations/366118655033/roles/myRoleOne"
+ }
+ iam_principals = {
+ test = "serviceAccount:test@test-project.iam.gserviceaccount.com"
+ }
+ locations = {
+ ew8 = "europe-west8"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+}
+dns_policy = {
+ inbound = true
+ outbound = {
+ private_ns = ["$addresses:dns-internal"]
+ public_ns = ["$addresses:dns-external"]
+ }
+}
+internal_ranges = [
+ {
+ name = "pods-range"
+ usage = "FOR_VPC"
+ peering = "FOR_SELF"
+ ip_cidr_range = "$cidr_ranges:rfc1918-172"
+ }
+]
+project_id = "$project_ids:test"
+routes = {
+ next-hop = {
+ description = "Route to internal range."
+ dest_range = "$cidr_ranges:test"
+ next_hop_type = "ip"
+ next_hop = "$addresses:test"
+ }
+}
+subnets = [
+ {
+ name = "production"
+ region = "$locations:ew8"
+ reserved_internal_range = "pods-range"
+ iam = {
+ "$custom_roles:myrole" = [
+ "iam_principals:test"
+ ]
+ }
+ iam_bindings = {
+ myrole_two = {
+ role = "$custom_roles:myrole"
+ members = [
+ "$iam_principals:test"
+ ]
+ condition = {
+ title = "Test"
+ expression = "resource.matchTag('$${organization.id}/environment', 'development')"
+ }
+ }
+ }
+ iam_bindings_additive = {
+ myrole_two = {
+ role = "$custom_roles:myrole"
+ member = "$iam_principals:test"
+ }
+ }
+ secondary_ip_ranges = {
+ pods = {
+ reserved_internal_range = "pods-range"
+ }
+ # Mixed configuration: some ranges use internal ranges, others use CIDR
+ traditional = {
+ ip_cidr_range = "$cidr_ranges:rfc1918-192"
+ }
+ }
+ }
+]
diff --git a/tests/modules/net_vpc/context.yaml b/tests/modules/net_vpc/context.yaml
new file mode 100644
index 000000000..36beb5c4c
--- /dev/null
+++ b/tests/modules/net_vpc/context.yaml
@@ -0,0 +1,175 @@
+# Copyright 2025 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_compute_network.network[0]:
+ auto_create_subnetworks: false
+ delete_default_routes_on_create: false
+ description: Terraform-managed.
+ enable_ula_internal_ipv6: null
+ name: test
+ network_firewall_policy_enforcement_order: AFTER_CLASSIC_FIREWALL
+ network_profile: null
+ params: []
+ project: foo-test-0
+ routing_mode: GLOBAL
+ timeouts: null
+ google_compute_route.gateway["directpath-googleapis"]:
+ description: Terraform-managed.
+ dest_range: 34.126.0.0/18
+ name: test-directpath-googleapis
+ network: test
+ next_hop_gateway: default-internet-gateway
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_vpn_tunnel: null
+ params: []
+ priority: 1000
+ project: foo-test-0
+ tags: null
+ timeouts: null
+ google_compute_route.gateway["private-googleapis"]:
+ description: Terraform-managed.
+ dest_range: 199.36.153.8/30
+ name: test-private-googleapis
+ network: test
+ next_hop_gateway: default-internet-gateway
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_vpn_tunnel: null
+ params: []
+ priority: 1000
+ project: foo-test-0
+ tags: null
+ timeouts: null
+ google_compute_route.gateway["restricted-googleapis"]:
+ description: Terraform-managed.
+ dest_range: 199.36.153.4/30
+ name: test-restricted-googleapis
+ network: test
+ next_hop_gateway: default-internet-gateway
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_vpn_tunnel: null
+ params: []
+ priority: 1000
+ project: foo-test-0
+ tags: null
+ timeouts: null
+ google_compute_route.ip["next-hop"]:
+ description: Route to internal range.
+ dest_range: 8.8.8.8/32
+ name: test-next-hop
+ network: test
+ next_hop_gateway: null
+ next_hop_ilb: null
+ next_hop_instance: null
+ next_hop_ip: 10.20.20.20
+ next_hop_vpn_tunnel: null
+ params: []
+ priority: 1000
+ project: foo-test-0
+ tags: null
+ timeouts: null
+ google_compute_subnetwork.subnetwork["europe-west8/production"]:
+ description: Terraform-managed.
+ ip_collection: null
+ ipv6_access_type: null
+ log_config: []
+ name: production
+ network: test
+ params: []
+ private_ip_google_access: true
+ project: foo-test-0
+ region: europe-west8
+ role: null
+ secondary_ip_range:
+ - range_name: pods
+ - ip_cidr_range: 192.168.0.0/16
+ range_name: traditional
+ reserved_internal_range: null
+ send_secondary_ip_range_if_empty: true
+ timeouts: null
+ google_compute_subnetwork_iam_binding.authoritative["europe-west8/production.organizations/366118655033/roles/myRoleOne"]:
+ condition: []
+ members:
+ - iam_principals:test
+ project: foo-test-0
+ region: europe-west8
+ role: organizations/366118655033/roles/myRoleOne
+ subnetwork: production
+ google_compute_subnetwork_iam_binding.bindings["myrole_two"]:
+ condition:
+ - description: null
+ expression: resource.matchTag('1234567890/environment', 'development')
+ title: Test
+ members:
+ - serviceAccount:test@test-project.iam.gserviceaccount.com
+ project: foo-test-0
+ region: europe-west8
+ role: organizations/366118655033/roles/myRoleOne
+ subnetwork: production
+ google_compute_subnetwork_iam_member.bindings["myrole_two"]:
+ condition: []
+ member: serviceAccount:test@test-project.iam.gserviceaccount.com
+ project: foo-test-0
+ region: europe-west8
+ role: organizations/366118655033/roles/myRoleOne
+ subnetwork: production
+ google_dns_policy.default[0]:
+ alternative_name_server_config:
+ - target_name_servers:
+ - forwarding_path: ''
+ ipv4_address: 8.8.8.8
+ - forwarding_path: private
+ ipv4_address: 10.10.10.10
+ description: Managed by Terraform
+ enable_inbound_forwarding: true
+ enable_logging: null
+ name: test
+ networks:
+ - {}
+ project: foo-test-0
+ timeouts: null
+ google_network_connectivity_internal_range.internal_range["pods-range"]:
+ allocation_options: []
+ description: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ exclude_cidr_ranges: null
+ immutable: null
+ ip_cidr_range: 172.16.10.0/12
+ labels: null
+ migration: []
+ name: pods-range
+ overlaps: null
+ peering: FOR_SELF
+ prefix_length: null
+ project: foo-test-0
+ target_cidr_range: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ usage: FOR_VPC
+
+counts:
+ google_compute_network: 1
+ google_compute_route: 4
+ google_compute_subnetwork: 1
+ google_compute_subnetwork_iam_binding: 2
+ google_compute_subnetwork_iam_member: 1
+ google_dns_policy: 1
+ google_network_connectivity_internal_range: 1
+ modules: 0
+ resources: 11
diff --git a/tests/modules/net_vpc/tftest.yaml b/tests/modules/net_vpc/tftest.yaml
index 5e9668ea4..a8cfbe17b 100644
--- a/tests/modules/net_vpc/tftest.yaml
+++ b/tests/modules/net_vpc/tftest.yaml
@@ -17,6 +17,7 @@ common_tfvars:
- common.tfvars
tests:
+ context:
shared_vpc:
psa_routes_export:
psa_routes_import:
diff --git a/tests/modules/net_vpc_firewall/context.tfvars b/tests/modules/net_vpc_firewall/context.tfvars
new file mode 100644
index 000000000..782617fe3
--- /dev/null
+++ b/tests/modules/net_vpc_firewall/context.tfvars
@@ -0,0 +1,47 @@
+context = {
+ cidr_ranges = {
+ rfc1918-10 = "10.0.0.0/8"
+ }
+ iam_principals = {
+ test = "serviceAccount:test@test-project.iam.gserviceaccount.com"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+}
+project_id = "$project_ids:test"
+network = "$networks:test"
+attachments = {
+ test = "$networks:test"
+}
+default_rules_config = {
+ admin_ranges = ["$cidr_ranges:rfc1918-10"]
+ http_ranges = ["$cidr_ranges:rfc1918-10"]
+ https_ranges = ["$cidr_ranges:rfc1918-10"]
+ ssh_ranges = ["$cidr_ranges:rfc1918-10"]
+}
+egress_rules = {
+ allow-egress-rfc1918 = {
+ deny = false
+ description = "Allow egress."
+ destination_ranges = [
+ "$cidr_ranges:rfc1918-10", "172.16.0.0/12", "192.168.0.0/16"
+ ]
+ source_ranges = ["$cidr_ranges:rfc1918-10"]
+ targets = ["$iam_principals:test"]
+ use_service_accounts = true
+ }
+}
+ingress_rules = {
+ allow-ingress-tag = {
+ description = "Allow ingress."
+ destination_ranges = ["$cidr_ranges:rfc1918-10"]
+ source_ranges = ["$cidr_ranges:rfc1918-10"]
+ sources = ["$iam_principals:test"]
+ targets = ["$iam_principals:test"]
+ use_service_accounts = true
+ }
+}
diff --git a/tests/modules/net_vpc_firewall/context.yaml b/tests/modules/net_vpc_firewall/context.yaml
new file mode 100644
index 000000000..2ad022a5a
--- /dev/null
+++ b/tests/modules/net_vpc_firewall/context.yaml
@@ -0,0 +1,157 @@
+# Copyright 2025 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_compute_firewall.allow-admins[0]:
+ allow:
+ - ports: []
+ protocol: all
+ deny: []
+ description: Access from the admin subnet to all subnets.
+ disabled: null
+ log_config: []
+ name: dev-spoke-0-ingress-admins
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts: null
+ source_tags: null
+ target_service_accounts: null
+ target_tags: null
+ timeouts: null
+ google_compute_firewall.allow-tag-http[0]:
+ allow:
+ - ports:
+ - '80'
+ protocol: tcp
+ deny: []
+ description: Allow http to machines with matching tags.
+ disabled: null
+ log_config: []
+ name: dev-spoke-0-ingress-tag-http
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts: null
+ source_tags: null
+ target_service_accounts: null
+ target_tags:
+ - http-server
+ timeouts: null
+ google_compute_firewall.allow-tag-https[0]:
+ allow:
+ - ports:
+ - '443'
+ protocol: tcp
+ deny: []
+ description: Allow http to machines with matching tags.
+ disabled: null
+ log_config: []
+ name: dev-spoke-0-ingress-tag-https
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts: null
+ source_tags: null
+ target_service_accounts: null
+ target_tags:
+ - https-server
+ timeouts: null
+ google_compute_firewall.allow-tag-ssh[0]:
+ allow:
+ - ports:
+ - '22'
+ protocol: tcp
+ deny: []
+ description: Allow SSH to machines with matching tags.
+ disabled: null
+ log_config: []
+ name: dev-spoke-0-ingress-tag-ssh
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts: null
+ source_tags: null
+ target_service_accounts: null
+ target_tags:
+ - ssh
+ timeouts: null
+ google_compute_firewall.custom-rules["allow-egress-rfc1918"]:
+ allow:
+ - ports: []
+ protocol: all
+ deny: []
+ description: Allow egress.
+ destination_ranges:
+ - 10.0.0.0/8
+ - 172.16.0.0/12
+ - 192.168.0.0/16
+ direction: EGRESS
+ disabled: false
+ log_config: []
+ name: allow-egress-rfc1918
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts: null
+ source_tags: null
+ target_service_accounts:
+ - serviceAccount:test@test-project.iam.gserviceaccount.com
+ target_tags: null
+ timeouts: null
+ google_compute_firewall.custom-rules["allow-ingress-tag"]:
+ allow:
+ - ports: []
+ protocol: all
+ deny: []
+ description: Allow ingress.
+ destination_ranges:
+ - 10.0.0.0/8
+ direction: INGRESS
+ disabled: false
+ log_config: []
+ name: allow-ingress-tag
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ params: []
+ priority: 1000
+ project: foo-test-0
+ source_ranges:
+ - 10.0.0.0/8
+ source_service_accounts:
+ - serviceAccount:test@test-project.iam.gserviceaccount.com
+ source_tags: null
+ target_service_accounts:
+ - serviceAccount:test@test-project.iam.gserviceaccount.com
+ target_tags: null
+ timeouts: null
+
+counts:
+ google_compute_firewall: 6
+ modules: 0
+ resources: 6
diff --git a/tests/modules/net_vpc_firewall/tftest.yaml b/tests/modules/net_vpc_firewall/tftest.yaml
new file mode 100644
index 000000000..5223867ff
--- /dev/null
+++ b/tests/modules/net_vpc_firewall/tftest.yaml
@@ -0,0 +1,17 @@
+# Copyright 2025 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.
+
+module: modules/net-vpc-firewall
+tests:
+ context: