Add support for additive perimeter resources to vpc-sc module (#3093)

* add support for additive perimeter resources

* FAST stage variable
This commit is contained in:
Ludovico Magnocavallo
2025-05-19 11:05:05 +02:00
committed by GitHub
parent bb5426128e
commit e50b02d404
9 changed files with 439 additions and 24 deletions

View File

@@ -310,8 +310,8 @@ Some references that might be useful in setting up this stage:
| [ingress_policies](variables.tf#L134) | Ingress policy definitions that can be referenced in perimeters. | <code title="map&#40;object&#40;&#123;&#10; title &#61; optional&#40;string&#41;&#10; from &#61; object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; identity_type &#61; optional&#40;string&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; permission_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; roles &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [logging](variables-fast.tf#L25) | Log writer identities for organization / folders. | <code title="object&#40;&#123;&#10; project_number &#61; string&#10; writer_identities &#61; map&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>0-bootstrap</code> |
| [outputs_location](variables.tf#L176) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
| [perimeters](variables.tf#L182) | Perimeter definitions. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; spec &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; status &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; use_explicit_dry_run_spec &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [resource_discovery](variables.tf#L215) | Automatic discovery of perimeter projects. | <code title="object&#40;&#123;&#10; enabled &#61; optional&#40;bool, true&#41;&#10; ignore_folders &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; ignore_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; include_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [perimeters](variables.tf#L182) | Perimeter definitions. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; ignore_resource_changes &#61; optional&#40;bool, false&#41;&#10; title &#61; optional&#40;string&#41;&#10; use_explicit_dry_run_spec &#61; optional&#40;bool, false&#41;&#10; spec &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; status &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [resource_discovery](variables.tf#L216) | Automatic discovery of perimeter projects. | <code title="object&#40;&#123;&#10; enabled &#61; optional&#40;bool, true&#41;&#10; ignore_folders &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; ignore_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; include_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [root_node](variables-fast.tf#L45) | Root node for the hierarchy, if running in tenant mode. | <code>string</code> | | <code>null</code> | <code>0-bootstrap</code> |
## Outputs

View File

@@ -182,8 +182,10 @@ variable "outputs_location" {
variable "perimeters" {
description = "Perimeter definitions."
type = map(object({
description = optional(string)
title = optional(string)
description = optional(string)
ignore_resource_changes = optional(bool, false)
title = optional(string)
use_explicit_dry_run_spec = optional(bool, false)
spec = optional(object({
access_levels = optional(list(string))
egress_policies = optional(list(string))
@@ -206,7 +208,6 @@ variable "perimeters" {
enable_restriction = optional(bool, true)
}))
}))
use_explicit_dry_run_spec = optional(bool, false)
}))
nullable = false
default = {}

View File

@@ -112,6 +112,10 @@ module "test" {
### Perimeters
Perimeters are defined via `perimeters` variable, or the dedicated factory.
Perimeters by default manage all their attributes authoritatively. To have perimeter resources managed externally (e.g. from the project factory) set the perimeter-level attribute `ignore_resource_changes` at the perimeter level.
```hcl
module "test" {
source = "./fabric/modules/vpc-sc"
@@ -388,6 +392,7 @@ to:
| [iam.tf](./iam.tf) | IAM bindings | <code>google_access_context_manager_access_policy_iam_binding</code> · <code>google_access_context_manager_access_policy_iam_member</code> |
| [main.tf](./main.tf) | Module-level locals and resources. | <code>google_access_context_manager_access_policy</code> |
| [outputs.tf](./outputs.tf) | Module outputs. | |
| [perimeters-additive.tf](./perimeters-additive.tf) | Regular service perimeter resources which ignore resource changes. | <code>google_access_context_manager_service_perimeter</code> |
| [perimeters.tf](./perimeters.tf) | Regular service perimeter resources. | <code>google_access_context_manager_service_perimeter</code> |
| [variables.tf](./variables.tf) | Module variables. | |
| [versions.tf](./versions.tf) | Version pins. | |
@@ -405,8 +410,8 @@ to:
| [iam_bindings](variables.tf#L149) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map&#40;object&#40;&#123;&#10; members &#61; list&#40;string&#41;&#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;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings_additive](variables.tf#L164) | Individual additive IAM bindings. Keys are arbitrary. | <code title="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;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [ingress_policies](variables.tf#L179) | Ingress policy definitions that can be referenced in perimeters. | <code title="map&#40;object&#40;&#123;&#10; title &#61; optional&#40;string&#41;&#10; from &#61; object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; identity_type &#61; optional&#40;string&#41;&#10; identities &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#10; to &#61; object&#40;&#123;&#10; operations &#61; optional&#40;list&#40;object&#40;&#123;&#10; method_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; permission_selectors &#61; optional&#40;list&#40;string&#41;&#41;&#10; service_name &#61; string&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; roles &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [perimeters](variables.tf#L221) | Regular service perimeters. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; spec &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; status &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; use_explicit_dry_run_spec &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [project_id_search_scope](variables.tf#L254) | Set this to an organization or folder ID to use Cloud Asset Inventory to automatically translate project ids to numbers. | <code>string</code> | | <code>null</code> |
| [perimeters](variables.tf#L221) | Regular service perimeters. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; ignore_resource_changes &#61; optional&#40;bool, false&#41;&#10; title &#61; optional&#40;string&#41;&#10; use_explicit_dry_run_spec &#61; optional&#40;bool, false&#41;&#10; spec &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10; status &#61; optional&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; restricted_services &#61; optional&#40;list&#40;string&#41;&#41;&#10; vpc_accessible_services &#61; optional&#40;object&#40;&#123;&#10; allowed_services &#61; list&#40;string&#41;&#10; enable_restriction &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [project_id_search_scope](variables.tf#L255) | Set this to an organization or folder ID to use Cloud Asset Inventory to automatically translate project ids to numbers. | <code>string</code> | | <code>null</code> |
## Outputs

View File

@@ -95,8 +95,9 @@ locals {
perimeters = {
for k, v in local._data.perimeters :
k => {
description = try(v.description, null)
title = try(v.title, null)
description = try(v.description, null)
ignore_resource_changes = try(v.ignore_resource_changes, false)
title = try(v.title, null)
spec = !can(v.spec) ? null : merge(v.spec, {
access_levels = try(v.spec.access_levels, [])
egress_policies = try(v.spec.egress_policies, [])

View File

@@ -46,5 +46,8 @@ output "id" {
output "perimeters" {
description = "Regular service perimeter resources."
value = google_access_context_manager_service_perimeter.regular
value = merge(
google_access_context_manager_service_perimeter.regular,
google_access_context_manager_service_perimeter.additive
)
}

View File

@@ -0,0 +1,405 @@
/**
* 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.
*/
# tfdoc:file:description Regular service perimeter resources which ignore resource changes.
resource "google_access_context_manager_service_perimeter" "additive" {
for_each = {
for k, v in local.perimeters : k => v if v.ignore_resource_changes
}
parent = "accessPolicies/${local.access_policy}"
name = "accessPolicies/${local.access_policy}/servicePerimeters/${each.key}"
description = each.value.description
title = coalesce(each.value.title, each.key)
perimeter_type = "PERIMETER_TYPE_REGULAR"
use_explicit_dry_run_spec = each.value.use_explicit_dry_run_spec
dynamic "spec" {
for_each = each.value.spec == null ? [] : [each.value.spec]
iterator = spec
content {
access_levels = (
spec.value.access_levels == null ? null : [
for k in spec.value.access_levels :
try(google_access_context_manager_access_level.basic[k].id, k)
]
)
resources = flatten([
for r in spec.value.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
restricted_services = flatten([
for r in coalesce(spec.value.restricted_services, []) :
lookup(var.factories_config.context.service_sets, r, [r])
])
dynamic "egress_policies" {
for_each = spec.value.egress_policies == null ? [] : [
for k in spec.value.egress_policies :
merge(local.egress_policies[k], { key = k })
]
iterator = policy
content {
title = coalesce(policy.value.title, policy.value.key)
dynamic "egress_from" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = flatten([
for i in policy.value.from.identities :
lookup(var.factories_config.context.identity_sets, i, [i])
])
source_restriction = (
length(policy.value.from.access_levels) > 0 || length(policy.value.from.resources) > 0
? "SOURCE_RESTRICTION_ENABLED"
: "SOURCE_RESTRICTION_DISABLED"
)
dynamic "sources" {
for_each = policy.value.from.access_levels
iterator = access_level
content {
access_level = try(
google_access_context_manager_access_level.basic[access_level.value].id,
access_level.value
)
}
}
dynamic "sources" {
for_each = flatten([
for r in policy.value.from.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
iterator = resource
content {
resource = resource.value
}
}
}
}
dynamic "egress_to" {
for_each = policy.value.to == null ? [] : [""]
content {
external_resources = policy.value.to.external_resources
resources = flatten([
for r in policy.value.to.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
roles = policy.value.to.roles
dynamic "operations" {
for_each = toset(policy.value.to.operations)
iterator = o
content {
service_name = o.value.service_name
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.method_selectors, []))
content {
method = method_selectors.key
}
}
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.permission_selectors, []))
content {
permission = method_selectors.key
}
}
}
}
}
}
}
}
dynamic "ingress_policies" {
for_each = spec.value.ingress_policies == null ? [] : [
for k in spec.value.ingress_policies :
merge(local.ingress_policies[k], { key = k })
]
iterator = policy
content {
title = coalesce(policy.value.title, policy.value.key)
dynamic "ingress_from" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = flatten([
for i in policy.value.from.identities :
lookup(var.factories_config.context.identity_sets, i, [i])
])
dynamic "sources" {
for_each = toset(policy.value.from.access_levels)
iterator = s
content {
access_level = try(
google_access_context_manager_access_level.basic[s.value].id, s.value
)
}
}
dynamic "sources" {
for_each = flatten([
for r in policy.value.from.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
content {
resource = sources.value
}
}
}
}
dynamic "ingress_to" {
for_each = policy.value.to == null ? [] : [""]
content {
resources = flatten([
for r in policy.value.to.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
roles = policy.value.to.roles
dynamic "operations" {
for_each = toset(policy.value.to.operations)
iterator = o
content {
service_name = o.value.service_name
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.method_selectors, []))
content {
method = method_selectors.value
}
}
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.permission_selectors, []))
content {
permission = method_selectors.value
}
}
}
}
}
}
}
}
dynamic "vpc_accessible_services" {
for_each = spec.value.vpc_accessible_services == null ? [] : [""]
content {
allowed_services = flatten([
for r in spec.value.vpc_accessible_services.allowed_services :
lookup(var.factories_config.context.service_sets, r, [r])
])
enable_restriction = spec.value.vpc_accessible_services.enable_restriction
}
}
}
}
dynamic "status" {
for_each = each.value.status == null ? [] : [each.value.status]
iterator = status
content {
access_levels = (
status.value.access_levels == null ? null : [
for k in status.value.access_levels :
try(google_access_context_manager_access_level.basic[k].id, k)
]
)
resources = flatten([
for r in status.value.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
restricted_services = flatten([
for r in coalesce(status.value.restricted_services, []) :
lookup(var.factories_config.context.service_sets, r, [r])
])
dynamic "egress_policies" {
for_each = status.value.egress_policies == null ? [] : [
for k in status.value.egress_policies :
merge(local.egress_policies[k], { key = k })
]
iterator = policy
content {
title = coalesce(policy.value.title, policy.value.key)
dynamic "egress_from" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = flatten([
for i in policy.value.from.identities :
lookup(var.factories_config.context.identity_sets, i, [i])
])
source_restriction = (
length(policy.value.from.access_levels) > 0 || length(policy.value.from.resources) > 0
? "SOURCE_RESTRICTION_ENABLED"
: "SOURCE_RESTRICTION_DISABLED"
)
dynamic "sources" {
for_each = policy.value.from.access_levels
iterator = access_level
content {
access_level = try(
google_access_context_manager_access_level.basic[access_level.value].id,
access_level.value
)
}
}
dynamic "sources" {
for_each = flatten([
for r in policy.value.from.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
iterator = resource
content {
resource = resource.value
}
}
}
}
dynamic "egress_to" {
for_each = policy.value.to == null ? [] : [""]
content {
external_resources = policy.value.to.external_resources
resources = policy.value.to.resources
roles = policy.value.to.roles
dynamic "operations" {
for_each = toset(policy.value.to.operations)
iterator = o
content {
service_name = o.value.service_name
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.method_selectors, []))
content {
method = method_selectors.key
}
}
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.permission_selectors, []))
content {
permission = method_selectors.key
}
}
}
}
}
}
}
}
dynamic "ingress_policies" {
for_each = status.value.ingress_policies == null ? [] : [
for k in status.value.ingress_policies :
merge(local.ingress_policies[k], { key = k })
]
iterator = policy
content {
title = coalesce(policy.value.title, policy.value.key)
dynamic "ingress_from" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = flatten([
for i in policy.value.from.identities :
lookup(var.factories_config.context.identity_sets, i, [i])
])
dynamic "sources" {
for_each = toset(policy.value.from.access_levels)
iterator = s
content {
access_level = try(
google_access_context_manager_access_level.basic[s.value].id,
s.value
)
}
}
dynamic "sources" {
for_each = flatten([
for r in policy.value.from.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
content {
resource = sources.value
}
}
}
}
dynamic "ingress_to" {
for_each = policy.value.to == null ? [] : [""]
content {
resources = flatten([
for r in policy.value.to.resources : try(
var.factories_config.context.resource_sets[r],
[local.project_number[r]], [r]
)
])
roles = policy.value.to.roles
dynamic "operations" {
for_each = toset(policy.value.to.operations)
iterator = o
content {
service_name = o.value.service_name
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.method_selectors, []))
content {
method = method_selectors.value
}
}
dynamic "method_selectors" {
for_each = toset(coalesce(o.value.permission_selectors, []))
content {
permission = method_selectors.value
}
}
}
}
}
}
}
}
dynamic "vpc_accessible_services" {
for_each = status.value.vpc_accessible_services == null ? [] : [""]
content {
allowed_services = flatten([
for r in status.value.vpc_accessible_services.allowed_services :
lookup(var.factories_config.context.service_sets, r, [r])
])
enable_restriction = status.value.vpc_accessible_services.enable_restriction
}
}
}
}
lifecycle {
ignore_changes = [spec[0].resources, status[0].resources]
}
depends_on = [
google_access_context_manager_access_policy.default,
google_access_context_manager_access_level.basic
]
}

View File

@@ -16,10 +16,6 @@
# tfdoc:file:description Regular service perimeter resources.
# this code implements "additive" service perimeters, if "authoritative"
# service perimeters are needed, switch to the
# google_access_context_manager_service_perimeters resource
locals {
egress_policies = merge(local.data.egress_policies, var.egress_policies)
ingress_policies = merge(local.data.ingress_policies, var.ingress_policies)
@@ -27,7 +23,9 @@ locals {
}
resource "google_access_context_manager_service_perimeter" "regular" {
for_each = local.perimeters
for_each = {
for k, v in local.perimeters : k => v if !v.ignore_resource_changes
}
parent = "accessPolicies/${local.access_policy}"
name = "accessPolicies/${local.access_policy}/servicePerimeters/${each.key}"
description = each.value.description
@@ -403,9 +401,6 @@ resource "google_access_context_manager_service_perimeter" "regular" {
}
}
# lifecycle {
# ignore_changes = [spec[0].resources, status[0].resources]
# }
depends_on = [
google_access_context_manager_access_policy.default,
google_access_context_manager_access_level.basic

View File

@@ -7,8 +7,9 @@
"description": {
"type": "string"
},
"title": {
"type": "string"
"ignore_resource_changes": {
"type": "boolean",
"default": false
},
"spec": {
"type": "object",
@@ -88,6 +89,9 @@
},
"additionalProperties": false
},
"title": {
"type": "string"
},
"use_explicit_dry_run_spec": {
"type": "boolean",
"default": false
@@ -113,4 +117,4 @@
]
}
}
}
}

View File

@@ -221,8 +221,10 @@ variable "ingress_policies" {
variable "perimeters" {
description = "Regular service perimeters."
type = map(object({
description = optional(string)
title = optional(string)
description = optional(string)
ignore_resource_changes = optional(bool, false)
title = optional(string)
use_explicit_dry_run_spec = optional(bool, false)
spec = optional(object({
access_levels = optional(list(string))
egress_policies = optional(list(string))
@@ -245,7 +247,6 @@ variable "perimeters" {
enable_restriction = optional(bool, true)
}))
}))
use_explicit_dry_run_spec = optional(bool, false)
}))
default = {}
nullable = false