Add perimeter factory to modules/vpc-sc (#2919)
* Add perimeter factory Proposal to allow the management of perimeters in yaml factory. Project discovery is extended to multiple perimeters with query filtering. Doc clean uo * default perimeters desc to null * linting * Revert changes to FAST * Remove test and schema from FAST * Align vars and perimeter factory * Interpolate resource_sets in more places * Silence linter * Update README.md --------- Co-authored-by: Julio Castillo <jccb@google.com> Co-authored-by: Ludovico Magnocavallo <ludo@qix.it>
This commit is contained in:
@@ -198,7 +198,7 @@ module "test" {
|
||||
r1 = {
|
||||
status = {
|
||||
access_levels = ["a1", "a2"]
|
||||
resources = ["projects/11111", "projects/111111"]
|
||||
resources = ["projects/1111", "projects/2222"]
|
||||
restricted_services = ["storage.googleapis.com"]
|
||||
egress_policies = ["gcs-sa-foo"]
|
||||
ingress_policies = ["sa-tf-test"]
|
||||
@@ -215,11 +215,11 @@ module "test" {
|
||||
|
||||
## Factories
|
||||
|
||||
This module implements support for three distinct factories, used to create and manage access levels, egress policies and ingress policies via YAML files. The YAML files syntax is a 1:1 match for the corresponding variables, and the factory data is merged at runtime with any data set in variables, which take precedence in case of key overlaps.
|
||||
This module implements support for five distinct factories, used to create and manage perimeters, bridges, access levels, egress policies, and ingress policies via YAML files.
|
||||
|
||||
JSON Schema files for each factory object are available in the [`schemas`](./schemas/) folder, and can be used to validate input YAML data with [`validate-yaml`](https://github.com/gerald1248/validate-yaml) or any of the available tools and libraries.
|
||||
|
||||
This is an example that uses all three factories. Note that the factory configuration points to folders, where each file represents one resource.
|
||||
This is an example that uses only three factories and leave perimeter management in tfvars. Note that the factory configuration points to folders, where each file represents one resource.
|
||||
|
||||
```hcl
|
||||
module "test" {
|
||||
@@ -229,12 +229,18 @@ module "test" {
|
||||
access_levels = "data/access-levels"
|
||||
egress_policies = "data/egress-policies"
|
||||
ingress_policies = "data/ingress-policies"
|
||||
context = {
|
||||
resource_sets = {
|
||||
foo_projects = ["projects/321", "projects/654"]
|
||||
}
|
||||
}
|
||||
}
|
||||
service_perimeters_regular = {
|
||||
r1 = {
|
||||
perimeter-north = {
|
||||
description = "Main perimeter"
|
||||
status = {
|
||||
access_levels = ["geo-it", "identity-user1"]
|
||||
resources = ["projects/11111", "projects/111111"]
|
||||
resources = ["projects/1111", "projects/2222"]
|
||||
restricted_services = ["storage.googleapis.com"]
|
||||
egress_policies = ["gcs-sa-foo"]
|
||||
ingress_policies = ["sa-tf-test-geo", "sa-tf-test"]
|
||||
@@ -308,9 +314,55 @@ to:
|
||||
- service_name: "*"
|
||||
resources:
|
||||
- projects/1234567890
|
||||
- foo_projects
|
||||
# tftest-file id=i2 path=data/ingress-policies/sa-tf-test-geo.yaml schema=ingress-policy.schema.json
|
||||
```
|
||||
|
||||
But perimeters could also defined in a yaml file.
|
||||
|
||||
```hcl
|
||||
module "test" {
|
||||
source = "./fabric/modules/vpc-sc"
|
||||
access_policy = "12345678"
|
||||
factories_config = {
|
||||
access_levels = "data/access-levels"
|
||||
egress_policies = "data/egress-policies"
|
||||
ingress_policies = "data/ingress-policies"
|
||||
perimeters = "data/perimeters"
|
||||
context = {
|
||||
resource_sets = {
|
||||
foo_projects = ["projects/321", "projects/654"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=3 files=a1,a2,e1,i1,i2,r1 inventory=factory.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
description: Main perimeter
|
||||
status:
|
||||
access_levels:
|
||||
- "geo-it"
|
||||
- "identity-user1"
|
||||
resources:
|
||||
- "projects/1111"
|
||||
- "projects/2222"
|
||||
restricted_services:
|
||||
- "storage.googleapis.com"
|
||||
egress_policies:
|
||||
- "gcs-sa-foo"
|
||||
ingress_policies:
|
||||
- "sa-tf-test-geo"
|
||||
- "sa-tf-test"
|
||||
vpc_accessible_services:
|
||||
allowed_services:
|
||||
- "storage.googleapis.com"
|
||||
enable_restriction: yes
|
||||
|
||||
# tftest-file id=r1 path=data/perimeters/perimeter-north.yaml schema=perimeters.schema.json
|
||||
````
|
||||
|
||||
## Notes
|
||||
|
||||
- To remove an access level, first remove the binding between perimeter and the access level in `status` and/or `spec` without removing the access level itself. Once you have run `terraform apply`, you'll then be able to remove the access level and run `terraform apply` again.
|
||||
@@ -339,17 +391,17 @@ to:
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [access_policy](variables.tf#L67) | Access Policy name, set to null if creating one. | <code>string</code> | ✓ | |
|
||||
| [access_levels](variables.tf#L17) | Access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) vpc_subnets = optional(map(list(string)), {}) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy_create](variables.tf#L72) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format, scopes are in 'folders/456789' or 'projects/project_id' format. | <code title="object({ parent = string title = string scopes = optional(list(string), null) })">object({…})</code> | | <code>null</code> |
|
||||
| [egress_policies](variables.tf#L82) | Egress policy definitions that can be referenced in perimeters. | <code title="map(object({ title = optional(string) from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ external_resources = optional(list(string)) operations = optional(list(object({ method_selectors = optional(list(string)) permission_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [factories_config](variables.tf#L124) | Paths to folders that enable factory functionality. | <code title="object({ access_levels = optional(string) egress_policies = optional(string) ingress_policies = optional(string) restricted_services = optional(string, "data/restricted-services.yaml") })">object({…})</code> | | <code>{}</code> |
|
||||
| [iam](variables.tf#L136) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [iam_bindings](variables.tf#L142) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [iam_bindings_additive](variables.tf#L157) | Individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [ingress_policies](variables.tf#L172) | Ingress policy definitions that can be referenced in perimeters. | <code title="map(object({ title = optional(string) from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) permission_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_bridge](variables.tf#L213) | Bridge service perimeters. | <code title="map(object({ spec_resources = optional(list(string)) status_resources = optional(list(string)) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_regular](variables.tf#L223) | Regular service perimeters. | <code title="map(object({ description = optional(string) spec = optional(object({ access_levels = optional(list(string)) resources = optional(list(string)) restricted_services = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = optional(bool, true) })) })) status = optional(object({ access_levels = optional(list(string)) resources = optional(list(string)) restricted_services = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = bool })) })) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy](variables.tf#L68) | Access Policy name, set to null if creating one. | <code>string</code> | ✓ | |
|
||||
| [access_levels](variables.tf#L17) | Access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) vpc_subnets = optional(map(list(string)), {}) })), []) description = optional(string) title = optional(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [access_policy_create](variables.tf#L73) | Access Policy configuration, fill in to create. Parent is in 'organizations/123456' format, scopes are in 'folders/456789' or 'projects/project_id' format. | <code title="object({ parent = string title = string scopes = optional(list(string), null) })">object({…})</code> | | <code>null</code> |
|
||||
| [egress_policies](variables.tf#L83) | Egress policy definitions that can be referenced in perimeters. | <code title="map(object({ title = optional(string) from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ external_resources = optional(list(string)) operations = optional(list(object({ method_selectors = optional(list(string)) permission_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [factories_config](variables.tf#L125) | Paths to folders that enable factory functionality. | <code title="object({ access_levels = optional(string) bridges = optional(string) egress_policies = optional(string) ingress_policies = optional(string) perimeters = optional(string) context = optional(object({ resource_sets = optional(map(list(string)), {}) service_sets = optional(map(list(string)), {}) }), {}) })">object({…})</code> | | <code>{}</code> |
|
||||
| [iam](variables.tf#L142) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [iam_bindings](variables.tf#L148) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [iam_bindings_additive](variables.tf#L163) | Individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [ingress_policies](variables.tf#L178) | Ingress policy definitions that can be referenced in perimeters. | <code title="map(object({ title = optional(string) from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) permission_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_bridge](variables.tf#L219) | Bridge service perimeters. | <code title="map(object({ description = optional(string) title = optional(string) spec_resources = optional(list(string)) status_resources = optional(list(string)) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [service_perimeters_regular](variables.tf#L231) | Regular service perimeters. | <code title="map(object({ description = optional(string) title = optional(string) spec = optional(object({ access_levels = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) restricted_services = optional(list(string)) resources = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = optional(bool, true) })) })) status = optional(object({ access_levels = optional(list(string)) egress_policies = optional(list(string)) ingress_policies = optional(list(string)) resources = optional(list(string)) restricted_services = optional(list(string)) vpc_accessible_services = optional(object({ allowed_services = list(string) enable_restriction = optional(bool, true) })) })) use_explicit_dry_run_spec = optional(bool, false) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
@@ -392,7 +444,7 @@ module "test" {
|
||||
default = {
|
||||
status = {
|
||||
access_levels = ["geo-it"]
|
||||
resources = ["projects/11111"]
|
||||
resources = ["projects/1111"]
|
||||
egress_policies = ["factory-egress-policy"]
|
||||
ingress_policies = ["variable-policy", "factory-ingress-policy"]
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ resource "google_access_context_manager_access_level" "basic" {
|
||||
for_each = merge(local.data.access_levels, var.access_levels)
|
||||
parent = "accessPolicies/${local.access_policy}"
|
||||
name = "accessPolicies/${local.access_policy}/accessLevels/${each.key}"
|
||||
title = each.key
|
||||
title = coalesce(each.value.title, each.key)
|
||||
description = each.value.description
|
||||
|
||||
basic {
|
||||
|
||||
@@ -22,7 +22,7 @@ locals {
|
||||
}
|
||||
}
|
||||
_data_paths = {
|
||||
for k in ["access_levels", "egress_policies", "ingress_policies"] : k => (
|
||||
for k in ["access_levels", "bridges", "egress_policies", "ingress_policies", "perimeters"] : k => (
|
||||
var.factories_config[k] == null
|
||||
? null
|
||||
: pathexpand(var.factories_config[k])
|
||||
@@ -32,7 +32,6 @@ locals {
|
||||
access_levels = {
|
||||
for k, v in local._data.access_levels : k => {
|
||||
combining_function = try(v.combining_function, null)
|
||||
description = try(v.description, null)
|
||||
conditions = [
|
||||
for c in try(v.conditions, []) : merge({
|
||||
device_policy = null
|
||||
@@ -44,6 +43,8 @@ locals {
|
||||
vpc_subnets = {}
|
||||
}, c)
|
||||
]
|
||||
description = try(v.description, null)
|
||||
title = try(v.title, null)
|
||||
}
|
||||
}
|
||||
egress_policies = {
|
||||
@@ -89,6 +90,40 @@ locals {
|
||||
}
|
||||
}
|
||||
}
|
||||
bridges = {
|
||||
for k, v in local._data.bridges :
|
||||
k => {
|
||||
description = try(v.description, null)
|
||||
title = try(v.title, null)
|
||||
spec_resources = try(v.spec_resources, null)
|
||||
status_resources = try(v.resources, null)
|
||||
use_explicit_dry_run_spec = try(v.use_explicit_dry_run_spec, false)
|
||||
}
|
||||
}
|
||||
perimeters = {
|
||||
for k, v in local._data.perimeters :
|
||||
k => {
|
||||
description = try(v.description, null)
|
||||
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, [])
|
||||
ingress_policies = try(v.spec.ingress_policies, [])
|
||||
restricted_services = try(v.spec.restricted_services, [])
|
||||
resources = try(v.spec.resources, [])
|
||||
vpc_accessible_services = try(v.spec.vpc_accessible_services, null)
|
||||
})
|
||||
status = !can(v.status) ? null : merge(v.status, {
|
||||
access_levels = try(v.status.access_levels, [])
|
||||
egress_policies = try(v.status.egress_policies, [])
|
||||
ingress_policies = try(v.status.ingress_policies, [])
|
||||
restricted_services = try(v.status.restricted_services, [])
|
||||
resources = try(v.status.resources, [])
|
||||
vpc_accessible_services = try(v.status.vpc_accessible_services, null)
|
||||
})
|
||||
use_explicit_dry_run_spec = try(v.use_explicit_dry_run_spec, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
# TODO: add checks that emulate the variable validations
|
||||
}
|
||||
|
||||
116
modules/vpc-sc/schemas/perimeters.schema.json
Normal file
116
modules/vpc-sc/schemas/perimeters.schema.json
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "perimeters",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"spec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_levels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"egress_policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ingress_policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"restricted_services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vpc_accessible_services": {
|
||||
"$ref": "#/$defs/VpcAccessibleServices"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"status": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_levels": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"egress_policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ingress_policies": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"restricted_services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vpc_accessible_services": {
|
||||
"$ref": "#/$defs/VpcAccessibleServices"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"use_explicit_dry_run_spec": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"VpcAccessibleServices": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"allowed_services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"enable_restriction": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"allowed_services"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
* 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.
|
||||
@@ -20,8 +20,12 @@
|
||||
# service perimeters are needed, switch to the
|
||||
# google_access_context_manager_service_perimeters resource
|
||||
|
||||
locals {
|
||||
bridge_perimeters = merge(local.data.bridges, var.service_perimeters_bridge)
|
||||
}
|
||||
|
||||
resource "google_access_context_manager_service_perimeter" "bridge" {
|
||||
for_each = var.service_perimeters_bridge
|
||||
for_each = local.bridge_perimeters
|
||||
parent = "accessPolicies/${local.access_policy}"
|
||||
name = "accessPolicies/${local.access_policy}/servicePerimeters/${each.key}"
|
||||
title = each.key
|
||||
@@ -31,12 +35,21 @@ resource "google_access_context_manager_service_perimeter" "bridge" {
|
||||
dynamic "spec" {
|
||||
for_each = each.value.spec_resources == null ? [] : [""]
|
||||
content {
|
||||
resources = each.value.spec_resources
|
||||
resources = flatten([
|
||||
for r in each.value.spec_resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
status {
|
||||
resources = each.value.status_resources == null ? [] : each.value.status_resources
|
||||
dynamic "status" {
|
||||
for_each = each.value.status_resources == null ? [] : [""]
|
||||
content {
|
||||
resources = flatten([
|
||||
for r in each.value.status_resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
# lifecycle {
|
||||
|
||||
@@ -21,16 +21,17 @@
|
||||
# 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)
|
||||
egress_policies = merge(local.data.egress_policies, var.egress_policies)
|
||||
ingress_policies = merge(local.data.ingress_policies, var.ingress_policies)
|
||||
regular_perimeters = merge(local.data.perimeters, var.service_perimeters_regular)
|
||||
}
|
||||
|
||||
resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
for_each = var.service_perimeters_regular
|
||||
for_each = local.regular_perimeters
|
||||
parent = "accessPolicies/${local.access_policy}"
|
||||
name = "accessPolicies/${local.access_policy}/servicePerimeters/${each.key}"
|
||||
description = each.value.description
|
||||
title = each.key
|
||||
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" {
|
||||
@@ -43,8 +44,14 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
try(google_access_context_manager_access_level.basic[k].id, k)
|
||||
]
|
||||
)
|
||||
resources = spec.value.resources
|
||||
restricted_services = spec.value.restricted_services
|
||||
resources = flatten([
|
||||
for r in spec.value.resources :
|
||||
lookup(var.factories_config.context.resource_sets, 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 ? {} : {
|
||||
@@ -75,7 +82,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
}
|
||||
}
|
||||
dynamic "sources" {
|
||||
for_each = policy.value.from.resources
|
||||
for_each = flatten([
|
||||
for r in policy.value.from.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
iterator = resource
|
||||
content {
|
||||
resource = resource.value
|
||||
@@ -87,7 +97,11 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
for_each = policy.value.to == null ? [] : [""]
|
||||
content {
|
||||
external_resources = policy.value.to.external_resources
|
||||
resources = policy.value.to.resources
|
||||
resources = flatten([
|
||||
for r in policy.value.to.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
|
||||
dynamic "operations" {
|
||||
for_each = toset(policy.value.to.operations)
|
||||
iterator = o
|
||||
@@ -135,7 +149,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
}
|
||||
}
|
||||
dynamic "sources" {
|
||||
for_each = toset(policy.value.from.resources)
|
||||
for_each = flatten([
|
||||
for r in policy.value.from.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
content {
|
||||
resource = sources.key
|
||||
}
|
||||
@@ -145,7 +162,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
dynamic "ingress_to" {
|
||||
for_each = policy.value.to == null ? [] : [""]
|
||||
content {
|
||||
resources = policy.value.to.resources
|
||||
resources = flatten([
|
||||
for r in policy.value.to.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
dynamic "operations" {
|
||||
for_each = toset(policy.value.to.operations)
|
||||
iterator = o
|
||||
@@ -173,7 +193,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
dynamic "vpc_accessible_services" {
|
||||
for_each = spec.value.vpc_accessible_services == null ? {} : { 1 = 1 }
|
||||
content {
|
||||
allowed_services = spec.value.vpc_accessible_services.allowed_services
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -190,8 +213,14 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
try(google_access_context_manager_access_level.basic[k].id, k)
|
||||
]
|
||||
)
|
||||
resources = status.value.resources
|
||||
restricted_services = status.value.restricted_services
|
||||
resources = flatten([
|
||||
for r in status.value.resources :
|
||||
lookup(var.factories_config.context.resource_sets, 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 ? {} : {
|
||||
@@ -222,7 +251,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
}
|
||||
}
|
||||
dynamic "sources" {
|
||||
for_each = policy.value.from.resources
|
||||
for_each = flatten([
|
||||
for r in policy.value.from.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
iterator = resource
|
||||
content {
|
||||
resource = resource.value
|
||||
@@ -293,7 +325,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
dynamic "ingress_to" {
|
||||
for_each = policy.value.to == null ? [] : [""]
|
||||
content {
|
||||
resources = policy.value.to.resources
|
||||
resources = flatten([
|
||||
for r in policy.value.to.resources :
|
||||
lookup(var.factories_config.context.resource_sets, r, [r])
|
||||
])
|
||||
dynamic "operations" {
|
||||
for_each = toset(policy.value.to.operations)
|
||||
iterator = o
|
||||
@@ -321,7 +356,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
|
||||
dynamic "vpc_accessible_services" {
|
||||
for_each = status.value.vpc_accessible_services == null ? {} : { 1 = 1 }
|
||||
content {
|
||||
allowed_services = status.value.vpc_accessible_services.allowed_services
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ variable "access_levels" {
|
||||
vpc_subnets = optional(map(list(string)), {})
|
||||
})), [])
|
||||
description = optional(string)
|
||||
title = optional(string)
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
@@ -124,10 +125,15 @@ variable "egress_policies" {
|
||||
variable "factories_config" {
|
||||
description = "Paths to folders that enable factory functionality."
|
||||
type = object({
|
||||
access_levels = optional(string)
|
||||
egress_policies = optional(string)
|
||||
ingress_policies = optional(string)
|
||||
restricted_services = optional(string, "data/restricted-services.yaml")
|
||||
access_levels = optional(string)
|
||||
bridges = optional(string)
|
||||
egress_policies = optional(string)
|
||||
ingress_policies = optional(string)
|
||||
perimeters = optional(string)
|
||||
context = optional(object({
|
||||
resource_sets = optional(map(list(string)), {})
|
||||
service_sets = optional(map(list(string)), {})
|
||||
}), {})
|
||||
})
|
||||
nullable = false
|
||||
default = {}
|
||||
@@ -213,6 +219,8 @@ variable "ingress_policies" {
|
||||
variable "service_perimeters_bridge" {
|
||||
description = "Bridge service perimeters."
|
||||
type = map(object({
|
||||
description = optional(string)
|
||||
title = optional(string)
|
||||
spec_resources = optional(list(string))
|
||||
status_resources = optional(list(string))
|
||||
use_explicit_dry_run_spec = optional(bool, false)
|
||||
@@ -224,12 +232,13 @@ variable "service_perimeters_regular" {
|
||||
description = "Regular service perimeters."
|
||||
type = map(object({
|
||||
description = optional(string)
|
||||
title = optional(string)
|
||||
spec = optional(object({
|
||||
access_levels = optional(list(string))
|
||||
resources = optional(list(string))
|
||||
restricted_services = optional(list(string))
|
||||
egress_policies = optional(list(string))
|
||||
ingress_policies = optional(list(string))
|
||||
restricted_services = optional(list(string))
|
||||
resources = optional(list(string))
|
||||
vpc_accessible_services = optional(object({
|
||||
allowed_services = list(string)
|
||||
enable_restriction = optional(bool, true)
|
||||
@@ -237,13 +246,13 @@ variable "service_perimeters_regular" {
|
||||
}))
|
||||
status = optional(object({
|
||||
access_levels = optional(list(string))
|
||||
resources = optional(list(string))
|
||||
restricted_services = optional(list(string))
|
||||
egress_policies = optional(list(string))
|
||||
ingress_policies = optional(list(string))
|
||||
resources = optional(list(string))
|
||||
restricted_services = optional(list(string))
|
||||
vpc_accessible_services = optional(object({
|
||||
allowed_services = list(string)
|
||||
enable_restriction = bool
|
||||
enable_restriction = optional(bool, true)
|
||||
}))
|
||||
}))
|
||||
use_explicit_dry_run_spec = optional(bool, false)
|
||||
|
||||
@@ -44,13 +44,7 @@ values:
|
||||
- projects/222221
|
||||
restricted_services: null
|
||||
vpc_accessible_services: []
|
||||
status:
|
||||
- access_levels: null
|
||||
egress_policies: []
|
||||
ingress_policies: []
|
||||
resources: null
|
||||
restricted_services: null
|
||||
vpc_accessible_services: []
|
||||
status: []
|
||||
title: b2
|
||||
use_explicit_dry_run_spec: true
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@ values:
|
||||
parent: accessPolicies/12345678
|
||||
timeouts: null
|
||||
title: identity-user1
|
||||
module.test.google_access_context_manager_service_perimeter.regular["r1"]:
|
||||
description: null
|
||||
name: accessPolicies/12345678/servicePerimeters/r1
|
||||
module.test.google_access_context_manager_service_perimeter.regular["perimeter-north"]:
|
||||
description: Main perimeter
|
||||
name: accessPolicies/12345678/servicePerimeters/perimeter-north
|
||||
parent: accessPolicies/12345678
|
||||
perimeter_type: PERIMETER_TYPE_REGULAR
|
||||
spec: []
|
||||
@@ -62,7 +62,7 @@ values:
|
||||
- serviceAccount:bar@myproject.iam.gserviceaccount.com
|
||||
- serviceAccount:foo@myproject.iam.gserviceaccount.com
|
||||
identity_type: null
|
||||
source_restriction: 'SOURCE_RESTRICTION_DISABLED'
|
||||
source_restriction: SOURCE_RESTRICTION_DISABLED
|
||||
sources: []
|
||||
egress_to:
|
||||
- external_resources: null
|
||||
@@ -104,9 +104,11 @@ values:
|
||||
service_name: '*'
|
||||
resources:
|
||||
- projects/1234567890
|
||||
- projects/321
|
||||
- projects/654
|
||||
resources:
|
||||
- projects/11111
|
||||
- projects/111111
|
||||
- projects/1111
|
||||
- projects/2222
|
||||
restricted_services:
|
||||
- storage.googleapis.com
|
||||
vpc_accessible_services:
|
||||
@@ -114,7 +116,7 @@ values:
|
||||
- storage.googleapis.com
|
||||
enable_restriction: true
|
||||
timeouts: null
|
||||
title: r1
|
||||
title: perimeter-north
|
||||
use_explicit_dry_run_spec: false
|
||||
|
||||
counts:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2023 Google LLC
|
||||
# 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.
|
||||
@@ -78,8 +78,8 @@ values:
|
||||
resources:
|
||||
- '*'
|
||||
resources:
|
||||
- projects/11111
|
||||
- projects/111111
|
||||
- projects/1111
|
||||
- projects/2222
|
||||
restricted_services:
|
||||
- storage.googleapis.com
|
||||
vpc_accessible_services:
|
||||
|
||||
Reference in New Issue
Block a user