Use VPC-SC perimeter factory in FAST 1-vpcsc stage (#2928)

* Use VPC-SC perimeter factory in FAST 1-vpcsc stage

* Add boilerplate

* Fix linter and schema checks

* Fix tests

* Fix schemas
This commit is contained in:
Julio Castillo
2025-02-24 13:29:51 +01:00
committed by GitHub
parent 5688a4da8c
commit 3ed801c464
27 changed files with 296 additions and 114 deletions

View File

@@ -306,12 +306,12 @@ Some references that might be useful in setting up this stage:
| [access_levels](variables.tf#L17) | Access level definitions. | <code title="map&#40;object&#40;&#123;&#10; combining_function &#61; optional&#40;string&#41;&#10; conditions &#61; optional&#40;list&#40;object&#40;&#123;&#10; device_policy &#61; optional&#40;object&#40;&#123;&#10; allowed_device_management_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; allowed_encryption_statuses &#61; optional&#40;list&#40;string&#41;&#41;&#10; require_admin_approval &#61; bool&#10; require_corp_owned &#61; bool&#10; require_screen_lock &#61; optional&#40;bool&#41;&#10; os_constraints &#61; optional&#40;list&#40;object&#40;&#123;&#10; os_type &#61; string&#10; minimum_version &#61; optional&#40;string&#41;&#10; require_verified_chrome_os &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#41;&#10; ip_subnetworks &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; members &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; negate &#61; optional&#40;bool&#41;&#10; regions &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; required_access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; vpc_subnets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [access_policy](variables.tf#L67) | Access policy id (used for tenant-level VPC-SC configurations). | <code>number</code> | | <code>null</code> | |
| [egress_policies](variables.tf#L73) | Egress 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; external_resources &#61; optional&#40;list&#40;string&#41;&#41;&#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; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [factories_config](variables.tf#L115) | Paths to folders that enable factory functionality. | <code title="object&#40;&#123;&#10; access_levels &#61; optional&#40;string, &#34;data&#47;access-levels&#34;&#41;&#10; egress_policies &#61; optional&#40;string, &#34;data&#47;egress-policies&#34;&#41;&#10; ingress_policies &#61; optional&#40;string, &#34;data&#47;ingress-policies&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [ingress_policies](variables.tf#L126) | 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; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [factories_config](variables.tf#L115) | Paths to folders that enable factory functionality. | <code title="object&#40;&#123;&#10; access_levels &#61; optional&#40;string, &#34;data&#47;access-levels&#34;&#41;&#10; egress_policies &#61; optional&#40;string, &#34;data&#47;egress-policies&#34;&#41;&#10; ingress_policies &#61; optional&#40;string, &#34;data&#47;ingress-policies&#34;&#41;&#10; perimeters &#61; optional&#40;string, &#34;data&#47;perimeters&#34;&#41;&#10; context &#61; optional&#40;object&#40;&#123;&#10; identity_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; resource_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; service_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [ingress_policies](variables.tf#L132) | 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; &#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#L167) | 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#L173) | Perimeter definitions. | <code title="map&#40;object&#40;&#123;&#10; access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; dry_run &#61; optional&#40;bool, true&#41;&#10; egress_policies &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; ingress_policies &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; resources &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#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;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code title="&#123;&#10; default &#61; &#123;&#10; access_levels &#61; &#91;&#34;geo&#34;&#93;&#10; ingress_policies &#61; &#91;&#34;fast-org-log-sinks&#34;&#93;&#10; &#125;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [resource_discovery](variables.tf#L196) | 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> | |
| [outputs_location](variables.tf#L173) | 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#L179) | 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#L212) | 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

@@ -1,4 +1,4 @@
# Copyright 2024 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.

View File

@@ -0,0 +1,26 @@
# 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.
# yaml-language-server: $schema=../../schemas/ingress-policy.schema.json
from:
access_levels:
- "*"
identities:
- org_logging_writer_identities
to:
operations:
- service_name: "*"
resources:
- logging_project

View File

@@ -0,0 +1,26 @@
# 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.
# yaml-language-server: $schema=../../schemas/perimeter.schema.json
use_explicit_dry_run_spec: true
spec:
access_levels:
- geo
resources:
- discovered_projects
ingress_policies:
- fast-org-log-sinks
restricted_services:
- restricted_services

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2024 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.
@@ -15,35 +15,25 @@
*/
locals {
fast_ingress_policies = var.logging == null ? {} : {
fast-org-log-sinks = {
from = {
access_levels = ["*"]
identities = values(var.logging.writer_identities)
}
to = {
operations = [{ service_name = "*" }]
resources = ["projects/${var.logging.project_number}"]
}
}
}
perimeters = {
for k, v in var.perimeters : k => merge(v, {
restricted_services = (
v.restricted_services == null
? local.restricted_services
: v.restricted_services
)
resources = distinct(concat(
v.resources,
k != "default" || var.resource_discovery.enabled != true ? [] : [
for v in module.vpc-sc-discovery[0].project_numbers :
"projects/${v}"
]
))
discovered_projects = var.resource_discovery.enabled != true ? [] : [
for v in module.vpc-sc-discovery[0].project_numbers :
"projects/${v}"
]
restricted_services = yamldecode(file("data/restricted-services.yaml"))
# extend context with our own data
context = {
identity_sets = merge(var.factories_config.context.identity_sets, {
org_logging_writer_identities = distinct(values(var.logging.writer_identities))
})
resource_sets = merge(var.factories_config.context.resource_sets, {
discovered_projects = local.discovered_projects
logging_project = ["projects/${var.logging.project_number}"]
})
service_sets = merge(var.factories_config.context.service_sets, {
restricted_services = local.restricted_services
})
}
restricted_services = yamldecode(file("data/restricted-services.yaml"))
}
module "vpc-sc-discovery" {
@@ -56,26 +46,19 @@ module "vpc-sc-discovery" {
}
module "vpc-sc" {
source = "../../../modules/vpc-sc"
# only enable if the default perimeter is defined
count = var.perimeters.default == null ? 0 : 1
source = "../../../modules/vpc-sc"
access_policy = var.access_policy
access_policy_create = var.access_policy != null ? null : {
parent = "organizations/${var.organization.id}"
title = "default"
}
access_levels = var.access_levels
egress_policies = var.egress_policies
factories_config = var.factories_config
ingress_policies = merge(
local.fast_ingress_policies,
var.ingress_policies
)
service_perimeters_regular = {
for k, v in local.perimeters : k => {
spec = v.dry_run ? v : null
status = !v.dry_run ? v : null
use_explicit_dry_run_spec = v.dry_run
access_levels = var.access_levels
egress_policies = var.egress_policies
factories_config = merge(
var.factories_config, {
context = local.context
}
}
)
ingress_policies = var.ingress_policies
service_perimeters_regular = var.perimeters
}

View File

@@ -0,0 +1,30 @@
/**
* 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.
*/
moved {
from = module.vpc-sc[0].google_access_context_manager_service_perimeter.regular["default"]
to = module.vpc-sc.google_access_context_manager_service_perimeter.regular["default"]
}
moved {
from = module.vpc-sc[0].google_access_context_manager_access_level.basic["geo"]
to = module.vpc-sc.google_access_context_manager_access_level.basic["geo"]
}
moved {
from = module.vpc-sc[0].google_access_context_manager_access_policy.default[0]
to = module.vpc-sc.google_access_context_manager_access_policy.default[0]
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2024 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.

View File

@@ -0,0 +1 @@
../../../../modules/vpc-sc/schemas/perimeters.schema.json

View File

@@ -118,6 +118,12 @@ variable "factories_config" {
access_levels = optional(string, "data/access-levels")
egress_policies = optional(string, "data/egress-policies")
ingress_policies = optional(string, "data/ingress-policies")
perimeters = optional(string, "data/perimeters")
context = optional(object({
identity_sets = optional(map(list(string)), {})
resource_sets = optional(map(list(string)), {})
service_sets = optional(map(list(string)), {})
}), {})
})
nullable = false
default = {}
@@ -173,24 +179,34 @@ variable "outputs_location" {
variable "perimeters" {
description = "Perimeter definitions."
type = map(object({
access_levels = optional(list(string), [])
dry_run = optional(bool, true)
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)
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)
}))
nullable = false
default = {
default = {
access_levels = ["geo"]
ingress_policies = ["fast-org-log-sinks"]
}
}
default = {}
}
variable "resource_discovery" {

View File

@@ -395,13 +395,13 @@ status:
| [access_levels](variables.tf#L17) | Access level definitions. | <code title="map&#40;object&#40;&#123;&#10; combining_function &#61; optional&#40;string&#41;&#10; conditions &#61; optional&#40;list&#40;object&#40;&#123;&#10; device_policy &#61; optional&#40;object&#40;&#123;&#10; allowed_device_management_levels &#61; optional&#40;list&#40;string&#41;&#41;&#10; allowed_encryption_statuses &#61; optional&#40;list&#40;string&#41;&#41;&#10; require_admin_approval &#61; bool&#10; require_corp_owned &#61; bool&#10; require_screen_lock &#61; optional&#40;bool&#41;&#10; os_constraints &#61; optional&#40;list&#40;object&#40;&#123;&#10; os_type &#61; string&#10; minimum_version &#61; optional&#40;string&#41;&#10; require_verified_chrome_os &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#41;&#10; ip_subnetworks &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; members &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; negate &#61; optional&#40;bool&#41;&#10; regions &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; required_access_levels &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; vpc_subnets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; description &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</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&#40;&#123;&#10; parent &#61; string&#10; title &#61; string&#10; scopes &#61; optional&#40;list&#40;string&#41;, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [egress_policies](variables.tf#L83) | Egress 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; external_resources &#61; optional&#40;list&#40;string&#41;&#41;&#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; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [factories_config](variables.tf#L125) | Paths to folders that enable factory functionality. | <code title="object&#40;&#123;&#10; access_levels &#61; optional&#40;string&#41;&#10; bridges &#61; optional&#40;string&#41;&#10; egress_policies &#61; optional&#40;string&#41;&#10; ingress_policies &#61; optional&#40;string&#41;&#10; perimeters &#61; optional&#40;string&#41;&#10; context &#61; optional&#40;object&#40;&#123;&#10; resource_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; service_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables.tf#L142) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_bindings](variables.tf#L148) | 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#L163) | 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#L178) | 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; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_perimeters_bridge](variables.tf#L219) | Bridge 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_resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; status_resources &#61; optional&#40;list&#40;string&#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> |
| [service_perimeters_regular](variables.tf#L231) | 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> |
| [factories_config](variables.tf#L125) | Paths to folders that enable factory functionality. | <code title="object&#40;&#123;&#10; access_levels &#61; optional&#40;string&#41;&#10; bridges &#61; optional&#40;string&#41;&#10; egress_policies &#61; optional&#40;string&#41;&#10; ingress_policies &#61; optional&#40;string&#41;&#10; perimeters &#61; optional&#40;string&#41;&#10; context &#61; optional&#40;object&#40;&#123;&#10; resource_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; service_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; identity_sets &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables.tf#L143) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [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; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_perimeters_bridge](variables.tf#L220) | Bridge 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_resources &#61; optional&#40;list&#40;string&#41;&#41;&#10; status_resources &#61; optional&#40;list&#40;string&#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> |
| [service_perimeters_regular](variables.tf#L232) | 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> |
## Outputs

View File

@@ -34,8 +34,11 @@ resource "google_access_context_manager_access_level" "basic" {
for_each = toset(each.value.conditions)
iterator = c
content {
ip_subnetworks = c.value.ip_subnetworks
members = c.value.members
ip_subnetworks = c.value.ip_subnetworks
members = flatten([
for i in c.value.members :
lookup(var.factories_config.context.identity_sets, i, [i])
])
negate = c.value.negate
regions = c.value.regions
required_access_levels = coalesce(c.value.required_access_levels, [])

View File

@@ -74,8 +74,7 @@
"members": {
"type": "array",
"items": {
"type": "string",
"pattern": "^(?:serviceAccount:|user:)"
"type": "string"
}
},
"negate": {

View File

@@ -33,8 +33,7 @@
"identities": {
"type": "array",
"items": {
"type": "string",
"pattern": "^(?:serviceAccount:|user:|group:|principal:)"
"type": "string"
}
},
"resources": {

View File

@@ -65,7 +65,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = policy.value.from.identities
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"
@@ -138,7 +141,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = policy.value.from.identities
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
@@ -234,7 +240,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = policy.value.from.identities
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"
@@ -303,7 +312,10 @@ resource "google_access_context_manager_service_perimeter" "regular" {
for_each = policy.value.from == null ? [] : [""]
content {
identity_type = policy.value.from.identity_type
identities = policy.value.from.identities
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

View File

@@ -133,6 +133,7 @@ variable "factories_config" {
context = optional(object({
resource_sets = optional(map(list(string)), {})
service_sets = optional(map(list(string)), {})
identity_sets = optional(map(list(string)), {})
}), {})
})
nullable = false

View File

@@ -1,4 +1,4 @@
# Copyright 2024 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.
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/access-level.schema.json
conditions:
- regions:
- IT
- IT

View File

@@ -1,4 +1,4 @@
# Copyright 2024 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.
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/access-level.schema.json
conditions:
- members:
- user:user@fast.example.com
- user:user@fast.example.com

View File

@@ -1,4 +1,4 @@
# Copyright 2024 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.
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/egress-policy.schema.json
from:
identities:
- user:user@fast.example.com
@@ -24,4 +26,4 @@ to:
method_selectors:
- "*"
resources:
- "*"
- "*"

View File

@@ -0,0 +1,26 @@
# 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.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/ingress-policy.schema.json
from:
access_levels:
- "*"
identities:
- org_logging_writer_identities
to:
operations:
- service_name: "*"
resources:
- logging_project

View File

@@ -1,4 +1,4 @@
# Copyright 2024 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.
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/ingress-policy.schema.json
from:
access_levels:
- "*"
@@ -26,4 +28,4 @@ to:
method_selectors:
- "*"
resources:
- "*"
- "*"

View File

@@ -0,0 +1,30 @@
# 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.
# yaml-language-server: $schema=../../../../../../../modules/vpc-sc/schemas/perimeters.schema.json
use_explicit_dry_run_spec: true
spec:
access_levels:
- geo_it
- identity_me
ingress_policies:
- fast-org-log-sinks
- test
egress_policies:
- test
restricted_services:
- restricted_services
resources:
- projects/1234567890

View File

@@ -0,0 +1,27 @@
automation = {
outputs_bucket = "test"
}
logging = {
project_number = "1234567890"
writer_identities = {
audit-logs = "serviceAccount:service-org-1234567890@gcp-sa-logging.iam.gserviceaccount.com"
iam = "serviceAccount:service-org-1234567890@gcp-sa-logging.iam.gserviceaccount.com"
vpc-sc = "serviceAccount:service-org-1234567890@gcp-sa-logging.iam.gserviceaccount.com"
workspace-audit-logs = "serviceAccount:o1234567890-1234567890@gcp-sa-logging.iam.gserviceaccount.com"
}
}
organization = {
domain = "fast.example.com"
id = 123456789012
customer_id = "C00000000"
}
prefix = "fast"
factories_config = {
access_levels = "../../../tests/fast/stages/s1_vpcsc/data/vpc-sc/access-levels"
egress_policies = "../../../tests/fast/stages/s1_vpcsc/data/vpc-sc/egress-policies"
ingress_policies = "../../../tests/fast/stages/s1_vpcsc/data/vpc-sc/ingress-policies"
perimeters = "../../../tests/fast/stages/s1_vpcsc/data/vpc-sc/perimeters"
}
resource_discovery = {
enabled = false
}

View File

@@ -23,12 +23,16 @@ factories_config = {
}
perimeters = {
default = {
access_levels = ["geo_it", "identity_me"]
egress_policies = ["test"]
ingress_policies = ["fast-org-log-sinks", "test"]
resources = [
"projects/1234567890"
]
use_explicit_dry_run_spec = true
spec = {
access_levels = ["geo_it", "identity_me"]
egress_policies = ["test"]
ingress_policies = ["fast-org-log-sinks", "test"]
restricted_services = ["restricted_services"]
resources = [
"projects/1234567890"
]
}
}
}
resource_discovery = {

View File

@@ -28,7 +28,7 @@ values:
source: null
temporary_hold: null
timeouts: null
module.vpc-sc[0].google_access_context_manager_access_level.basic["geo_it"]:
module.vpc-sc.google_access_context_manager_access_level.basic["geo_it"]:
basic:
- combining_function: AND
conditions:
@@ -44,7 +44,7 @@ values:
description: null
timeouts: null
title: geo_it
module.vpc-sc[0].google_access_context_manager_access_level.basic["identity_me"]:
module.vpc-sc.google_access_context_manager_access_level.basic["identity_me"]:
basic:
- combining_function: AND
conditions:
@@ -60,12 +60,12 @@ values:
description: null
timeouts: null
title: identity_me
module.vpc-sc[0].google_access_context_manager_access_policy.default[0]:
module.vpc-sc.google_access_context_manager_access_policy.default[0]:
parent: organizations/123456789012
scopes: null
timeouts: null
title: default
module.vpc-sc[0].google_access_context_manager_service_perimeter.regular["default"]:
module.vpc-sc.google_access_context_manager_service_perimeter.regular["default"]:
description: null
perimeter_type: PERIMETER_TYPE_REGULAR
spec:

View File

@@ -1,4 +1,4 @@
# Copyright 2024 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.
@@ -16,3 +16,6 @@ module: fast/stages/1-vpcsc
tests:
simple:
factory:
inventory:
- simple.yaml

View File

@@ -1,6 +0,0 @@
# skip boilerplate check
# tftest schema=modules/vpc-sc/schemas/access-level.schema.json fail
# fails because members must be prefixed with serviceAccount: or user:
conditions:
- members:
- "group:group@example.com"

View File

@@ -1,6 +0,0 @@
# skip boilerplate check
# tftest schema=modules/vpc-sc/schemas/access-level.schema.json fail
# fails because members must be prefixed with serviceAccount: or user:
conditions:
- members:
- "user@example.com"