Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix subnet iam_bindings to use arbitrary keys #1683

Merged
merged 3 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions modules/net-vpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ module "vpc" {
]
}
iam_bindings = {
"roles/compute.networkUser" = {
subnet-1-iam = {
members = ["group:[email protected]"]
role = "roles/compute.networkUser"
condition = {
expression = "resource.matchTag('123456789012/env', 'prod')"
title = "test_condition"
Expand All @@ -132,7 +133,7 @@ module "vpc" {
region = "europe-west1"
ip_cidr_range = "10.0.1.0/24"
iam_bindings_additive = {
subnet-2-am1 = {
subnet-2-iam = {
member = "user:[email protected]"
role = "roles/compute.networkUser"
subnet = "europe-west1/subnet-2"
Expand Down Expand Up @@ -553,10 +554,10 @@ module "vpc" {
| [routing_mode](variables.tf#L147) | The network routing mode (default 'GLOBAL'). | <code>string</code> | | <code>&#34;GLOBAL&#34;</code> |
| [shared_vpc_host](variables.tf#L157) | Enable shared VPC for this project. | <code>bool</code> | | <code>false</code> |
| [shared_vpc_service_projects](variables.tf#L163) | Shared VPC service projects to register with this host. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets](variables.tf#L169) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; &#125;&#41;&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_proxy_only](variables.tf#L215) | 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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; optional&#40;bool, true&#41;&#10; global &#61; optional&#40;bool, false&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_psc](variables.tf#L248) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [vpc_create](variables.tf#L279) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
| [subnets](variables.tf#L169) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; &#125;&#41;&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_proxy_only](variables.tf#L216) | 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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; optional&#40;bool, true&#41;&#10; global &#61; optional&#40;bool, false&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_psc](variables.tf#L250) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#10;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings &#61; optional&#40;map&#40;object&#40;&#123;&#10; role &#61; string&#10; members &#61; list&#40;string&#41;&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; iam_bindings_additive &#61; optional&#40;map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [vpc_create](variables.tf#L282) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |

## Outputs

Expand Down
39 changes: 19 additions & 20 deletions modules/net-vpc/subnets.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,36 +36,37 @@ locals {
} : null
global = try(v.global, false)
ip_cidr_range = v.ip_cidr_range
ipv6 = can(v.ipv6) ? {
ipv6 = !can(v.ipv6) ? null : {
access_type = try(v.ipv6.access_type, "INTERNAL")
} : null
}
name = try(v.name, k)
region = v.region
secondary_ip_ranges = try(v.secondary_ip_ranges, null)
iam = try(v.iam, {})
iam_bindings = can(v.iam_bindings) ? {
iam_bindings = !can(v.iam_bindings) ? {} : {
for k2, v2 in v.iam_bindings :
k2 => {
role = v2.role
members = v2.members
condition = can(v2.condition) ? {
condition = !can(v2.condition) ? null : {
expression = v2.condition.expression
title = v2.condition.title
description = try(v2.condition.description, null)
} : null
}
}
} : {}
iam_bindings_additive = can(v.iam_bindings_additive) ? {
}
iam_bindings_additive = !can(v.iam_bindings_additive) ? {} : {
for k2, v2 in v.iam_bindings_additive :
k2 => {
member = v2.member
role = v2.role
condition = can(v2.condition) ? {
condition = !can(v2.condition) ? null : {
expression = v2.condition.expression
title = v2.condition.title
description = try(v2.condition.description, null)
} : null
}
}
} : {}
}
_is_regular = !try(v.psc == true, false) && !try(v.proxy_only == true, false)
_is_psc = try(v.psc == true, false)
_is_proxy_only = try(v.proxy_only == true, false)
Expand All @@ -89,16 +90,17 @@ locals {
]
],
))
subnet_iam_bindings = flatten([
for s in concat(var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)) : [
for role, data in s.iam_bindings : {
role = role
subnet_iam_bindings = merge([
for s in concat(var.subnets, var.subnets_psc, var.subnets_proxy_only, values(local._factory_subnets)) : {
for key, data in s.iam_bindings :
key => {
role = data.role
subnet = "${s.region}/${s.name}"
members = data.members
condition = data.condition
}
]
])
}
]...)
# note: all additive bindings share a single namespace for the key.
# In other words, if you have multiple additive bindings with the
# same name, only one will be used
Expand Down Expand Up @@ -210,10 +212,7 @@ resource "google_compute_subnetwork_iam_binding" "authoritative" {
}

resource "google_compute_subnetwork_iam_binding" "bindings" {
for_each = {
for binding in local.subnet_iam_bindings :
"${binding.subnet}.${binding.role}.${try(binding.condition.title, "")}" => binding
}
for_each = local.subnet_iam_bindings
project = var.project_id
subnetwork = local.all_subnets[each.value.subnet].name
region = local.all_subnets[each.value.subnet].region
Expand Down
3 changes: 3 additions & 0 deletions modules/net-vpc/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ variable "subnets" {

iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
role = string
members = list(string)
condition = optional(object({
expression = string
Expand Down Expand Up @@ -224,6 +225,7 @@ variable "subnets_proxy_only" {

iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
role = string
members = list(string)
condition = optional(object({
expression = string
Expand Down Expand Up @@ -255,6 +257,7 @@ variable "subnets_psc" {

iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
role = string
members = list(string)
condition = optional(object({
expression = string
Expand Down
2 changes: 1 addition & 1 deletion tests/modules/net_vpc/examples/subnet-iam.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ values:
region: europe-west1
role: roles/compute.networkUser
subnetwork: subnet-1
module.vpc.google_compute_subnetwork_iam_binding.bindings["europe-west1/subnet-1.roles/compute.networkUser.test_condition"]:
module.vpc.google_compute_subnetwork_iam_binding.bindings["subnet-1-iam"]:
condition:
- description: null
expression: resource.matchTag('123456789012/env', 'prod')
Expand Down