Merge remote-tracking branch 'origin/master' into fast-dev

This commit is contained in:
Ludovico Magnocavallo
2026-02-10 15:59:57 +00:00
16 changed files with 434 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
# FAST Installation on Google Cloud Dedicated (GCD)
This document serves as an extension to the main **[FAST Organization Setup README](../README.md)**, detailing the specific configurations and steps required to deploy the Fabric FAST landing zone on **Google Cloud Dedicated (GCD)**.
This document serves as an extension to the main **[FAST Organization Setup README](./README.md)**, detailing the specific configurations and steps required to deploy the Fabric FAST landing zone on **Google Cloud Dedicated (GCD)**.
It assumes familiarity with the standard FAST bootstrap flow but highlights the critical divergences required for the Google Cloud Dedicated (GCD) environment.
@@ -31,7 +31,7 @@ The core stages are:
## 2. Prerequisites
In addition to the [standard FAST prerequisites](../README.md#prerequisites), ensure the following GCD-specific requirements are met.
In addition to the [standard FAST prerequisites](./README.md#prerequisites), ensure the following GCD-specific requirements are met.
### Identity Provider
@@ -84,7 +84,7 @@ gcloud auth application-default login \
## 3. Bootstrap: Manual Temporary Project
*This step replaces the standard [Default project](../README.md#default-project) creation flow.*
*This step replaces the standard [Default project](./README.md#default-project) creation flow.*
GCD requires a manual bootstrap project because organization policy services are not automatically available at the organization root during the initial setup.
@@ -113,7 +113,7 @@ GCD requires a manual bootstrap project because organization policy services are
## 4. Terraform Configuration Updates
*This section details specific modifications to the [Configure defaults](../README.md#configure-defaults) step.*
*This section details specific modifications to the [Configure defaults](./README.md#configure-defaults) step.*
### Provider Configuration
@@ -134,7 +134,16 @@ provider "google-beta" {
Update your `defaults.yaml` file to include a `universe` block within the `overrides` section. This configures the correct API domains and disables service identities that are not available in GCD.
Additionally, you must provide valid values for the following fields in the context section:
* `context.email_addresses.gcp-organization-admins`: used to set the [essential contact](https://docs.cloud.google.com/resource-manager/docs/manage-essential-contacts) for the core projects
* `context.iam_principals.gcp-organization-admins`: Used to grant administrative permissions to the administrators.
**Note on Principals:** If you use a group for the admin principal, ensure your user identity is a member of that group. Otherwise, set this field to your own user identity (e.g., `principal://iam.googleapis.com/locations/global/workforcePools/...`) instead of a group. For further details, refer to the [Configure defaults](./README.md#configure-defaults) section in the standard README.
Your `defaults.yaml should` contain sections that look like this:
```yaml
# ... existing configuration ...
projects:
defaults:
# customize prefix as per usual FAST instructions
@@ -154,6 +163,15 @@ projects:
- dns.googleapis.com
- monitoring.googleapis.com
- networksecurity.googleapis.com
context:
email_addresses:
gcp-organization-admins: gcp-organization-admins@example.com
iam_principals:
gcp-organization-admins: group:gcp-organization-admins@example.com
locations:
# Replace with values from the Configuration Reference table
primary: <UNIVERSE_REGION>
# ... existing configuration ...
```
### Switch to GCD Dataset
@@ -259,4 +277,3 @@ Once the **Organization Setup** stage is fully deployed:
```
2. **Proceed to Next Stages:** Continue with the subsequent FAST stages (VPC-SC, Security, Networking, Project Factory). The universe configuration established here is automatically propagated to these stages via the FAST cross-stage output mechanism.

View File

@@ -1,4 +1,4 @@
# Copyright 2025 Google LLC
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ iam_by_principals:
- roles/owner
services:
- bigquery.googleapis.com
- bigquerydatatransfer.googleapis.com
# - bigquerydatatransfer.googleapis.com
- storage.googleapis.com
datasets:
billing_export:

View File

@@ -0,0 +1,63 @@
# Copyright 2026 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/observability.schema.json
notification_channels:
email-security:
type: email
display_name: Security Team Email
labels:
email_address: $email_addresses:gcp-organization-admins
enabled: true
logging_metrics:
sa-impersonation:
filter: |
protoPayload.serviceName="iamcredentials.googleapis.com"
(protoPayload.methodName="GenerateAccessToken" OR protoPayload.methodName="GenerateIdToken")
label_extractors:
email_id: EXTRACT(resource.labels.email_id)
metric_descriptor:
metric_kind: DELTA
value_type: INT64
unit: "1"
display_name: Service Account Impersonation
labels:
- key: email_id
value_type: STRING
alerts:
sa-impersonation-alert:
display_name: Service Account Impersonation Alert
combiner: OR
conditions:
- display_name: Impersonation Detected
condition_threshold:
filter: |
metric.type="logging.googleapis.com/user/sa-impersonation" AND
resource.type="global"
comparison: COMPARISON_GT
threshold_value: 0
duration: 60s
trigger:
count: 1
aggregations:
alignment_period: 60s
per_series_aligner: ALIGN_COUNT
cross_series_reducer: REDUCE_SUM
group_by_fields: ["metric.label.email_id"]
notification_channels:
- email-security
enabled: true

View File

@@ -1,4 +1,4 @@
# Copyright 2025 Google LLC
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -83,6 +83,8 @@ org_policies:
- https://token.actions.githubusercontent.com
- https://gitlab.com
- https://app.terraform.io
factories_config:
observability: datasets/classic/observability/iac-0
data_access_logs:
storage.googleapis.com:
DATA_READ: {}
@@ -90,6 +92,10 @@ data_access_logs:
sts.googleapis.com:
DATA_READ: {}
DATA_WRITE: {}
# required to capture service account impersonation events
iam.googleapis.com:
DATA_READ: {}
DATA_WRITE: {}
buckets:
# Terraform state bucket for this stage
iac-org-state:

View File

@@ -19,6 +19,7 @@ is no terraform support for these resources.
- [Examples](#examples)
- [Simple example](#simple-example)
- [Looker Core private instance with PSA](#looker-core-private-instance-with-psa)
- [Looker Core with PSC](#looker-core-with-psc)
- [Looker Core full example](#looker-core-full-example)
- [Variables](#variables)
- [Outputs](#outputs)
@@ -90,6 +91,29 @@ module "looker" {
# tftest modules=3 resources=17 inventory=psa.yaml
```
### Looker Core with PSC
```hcl
module "looker" {
source = "./fabric/modules/looker-core"
project_id = var.project_id
region = var.region
name = "looker-psc"
network_config = {
psc_config = {
allowed_vpcs = ["projects/test-project/global/networks/test"]
}
}
oauth_config = {
client_id = "xxxxxxxxx"
client_secret = "xxxxxxxx"
}
platform_edition = "LOOKER_CORE_ENTERPRISE_ANNUAL"
}
# tftest inventory=psc.yaml
```
### Looker Core full example
```hcl
@@ -160,23 +184,22 @@ module "looker" {
}
# tftest modules=4 resources=23 inventory=full.yaml
```
<!-- BEGIN TFDOC -->
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L91) | Name of the looker core instance. | <code>string</code> | ✓ | |
| [network_config](variables.tf#L96) | Network configuration for cluster and instance. Only one between psa_config and psc_config can be used. | <code title="object&#40;&#123;&#10; psa_config &#61; optional&#40;object&#40;&#123;&#10; network &#61; string&#10; allocated_ip_range &#61; optional&#40;string&#41;&#10; enable_public_ip &#61; optional&#40;bool, false&#41;&#10; enable_private_ip &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; public &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [oauth_config](variables.tf#L114) | Looker Core Oauth config. Either client ID and secret (existing oauth client) or support email (temporary internal oauth client setup) must be specified. | <code title="object&#40;&#123;&#10; client_id &#61; optional&#40;string, null&#41;&#10; client_secret &#61; optional&#40;string, null&#41;&#10; support_email &#61; optional&#40;string, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [project_id](variables.tf#L147) | The ID of the project where this instances will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L152) | Region for the Looker core instance. | <code>string</code> | ✓ | |
| [network_config](variables.tf#L96) | Network configuration for cluster and instance. Only one between psa_config, psc_config and public can be used. | <code title="object&#40;&#123;&#10; psa_config &#61; optional&#40;object&#40;&#123;&#10; network &#61; string&#10; allocated_ip_range &#61; optional&#40;string&#41;&#10; enable_public_ip &#61; optional&#40;bool, false&#41;&#10; enable_private_ip &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;&#10; psc_config &#61; optional&#40;object&#40;&#123;&#10; allowed_vpcs &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#41;&#10; public &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [oauth_config](variables.tf#L121) | Looker Core Oauth config. Either client ID and secret (existing oauth client) or support email (temporary internal oauth client setup) must be specified. | <code title="object&#40;&#123;&#10; client_id &#61; optional&#40;string, null&#41;&#10; client_secret &#61; optional&#40;string, null&#41;&#10; support_email &#61; optional&#40;string, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [project_id](variables.tf#L154) | The ID of the project where this instances will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L159) | Region for the Looker core instance. | <code>string</code> | ✓ | |
| [admin_settings](variables.tf#L17) | Looker Core admins settings. | <code title="object&#40;&#123;&#10; allowed_email_domains &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [custom_domain](variables.tf#L26) | Looker core instance custom domain. | <code>string</code> | | <code>null</code> |
| [encryption_config](variables.tf#L32) | Set encryption configuration. KMS name format: 'projects/[PROJECT]/locations/[REGION]/keyRings/[RING]/cryptoKeys/[KEY_NAME]'. | <code title="object&#40;&#123;&#10; kms_key_name &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [maintenance_config](variables.tf#L41) | Set maintenance window configuration and maintenance deny period (up to 90 days). Date format: 'yyyy-mm-dd'. | <code title="object&#40;&#123;&#10; maintenance_window &#61; optional&#40;object&#40;&#123;&#10; day &#61; optional&#40;string, &#34;SUNDAY&#34;&#41;&#10; start_time &#61; optional&#40;object&#40;&#123;&#10; hours &#61; optional&#40;number, 23&#41;&#10; minutes &#61; optional&#40;number, 0&#41;&#10; seconds &#61; optional&#40;number, 0&#41;&#10; nanos &#61; optional&#40;number, 0&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, null&#41;&#10; deny_maintenance_period &#61; optional&#40;object&#40;&#123;&#10; start_date &#61; object&#40;&#123;&#10; year &#61; number&#10; month &#61; number&#10; day &#61; number&#10; &#125;&#41;&#10; end_date &#61; object&#40;&#123;&#10; year &#61; number&#10; month &#61; number&#10; day &#61; number&#10; &#125;&#41;&#10; start_time &#61; optional&#40;object&#40;&#123;&#10; hours &#61; optional&#40;number, 23&#41;&#10; minutes &#61; optional&#40;number, 0&#41;&#10; seconds &#61; optional&#40;number, 0&#41;&#10; nanos &#61; optional&#40;number, 0&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, null&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [platform_edition](variables.tf#L127) | Platform editions for a Looker instance. Each edition maps to a set of instance features, like its size. | <code>string</code> | | <code>&#34;LOOKER_CORE_TRIAL&#34;</code> |
| [prefix](variables.tf#L137) | Optional prefix used to generate instance names. | <code>string</code> | | <code>null</code> |
| [platform_edition](variables.tf#L134) | Platform editions for a Looker instance. Each edition maps to a set of instance features, like its size. | <code>string</code> | | <code>&#34;LOOKER_CORE_TRIAL&#34;</code> |
| [prefix](variables.tf#L144) | Optional prefix used to generate instance names. | <code>string</code> | | <code>null</code> |
## Outputs

View File

@@ -29,6 +29,7 @@ resource "google_looker_instance" "looker" {
platform_edition = var.platform_edition
private_ip_enabled = try(var.network_config.psa_config.enable_private_ip, null)
public_ip_enabled = coalesce(var.network_config.public, false) || try(var.network_config.psa_config.enable_public_ip, false)
psc_enabled = var.network_config.psc_config != null
region = var.region
reserved_range = try(var.network_config.psa_config.allocated_ip_range, null)
@@ -37,6 +38,13 @@ resource "google_looker_instance" "looker" {
client_secret = local.oauth_client_secret
}
dynamic "psc_config" {
for_each = var.network_config.psc_config != null ? [""] : []
content {
allowed_vpcs = var.network_config.psc_config.allowed_vpcs
}
}
dynamic "admin_settings" {
for_each = var.admin_settings != null ? [""] : []
content {

View File

@@ -94,7 +94,7 @@ variable "name" {
}
variable "network_config" {
description = "Network configuration for cluster and instance. Only one between psa_config and psc_config can be used."
description = "Network configuration for cluster and instance. Only one between psa_config, psc_config and public can be used."
type = object({
psa_config = optional(object({
network = string
@@ -102,12 +102,19 @@ variable "network_config" {
enable_public_ip = optional(bool, false)
enable_private_ip = optional(bool, true)
}))
psc_config = optional(object({
allowed_vpcs = optional(list(string), [])
}))
public = optional(bool, false)
})
nullable = false
validation {
condition = (coalesce(var.network_config.public, false)) == (var.network_config.psa_config == null)
error_message = "Please specify either psa_config or public to true."
condition = (
(coalesce(var.network_config.public, false) ? 1 : 0) +
(var.network_config.psa_config != null ? 1 : 0) +
(var.network_config.psc_config != null ? 1 : 0)
) == 1
error_message = "Please specify exactly one of psa_config, psc_config or public."
}
}

View File

@@ -135,7 +135,7 @@ resource "google_monitoring_alert_policy" "alerts" {
# first try to get a channel created by this module
google_monitoring_notification_channel.channels[x].name,
# otherwise check the context
var.context.notification_channels[x],
local.ctx.notification_channels[x],
# if nothing else, use the provided channel as is
x
)

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2025 Google LLC
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ resource "google_logging_metric" "metrics" {
disabled = each.value.disabled
bucket_name = try(
# first try to check the context
var.context.log_buckets[each.value.bucket_name],
local.ctx.log_buckets[each.value.bucket_name],
# if nothing else, use the provided channel as is
each.value.bucket_name
)

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2025 Google LLC
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,8 +45,16 @@ resource "google_monitoring_notification_channel" "channels" {
description = each.value.description
display_name = each.value.display_name
enabled = each.value.enabled
labels = each.value.labels
user_labels = each.value.user_labels
labels = each.value.labels == null ? null : {
for k, v in each.value.labels :
# allow interpolation of email addresses and pubsub topics
k => try(
local.ctx.email_addresses[v],
local.ctx.pubsub_topics[v],
v
)
}
user_labels = each.value.user_labels
dynamic "sensitive_labels" {
for_each = each.value.sensitive_labels[*]
content {

View File

@@ -1,4 +1,4 @@
# Copyright 2025 Google LLC
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -65,6 +66,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -97,6 +99,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -129,6 +132,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -161,6 +165,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -193,6 +198,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -211,6 +217,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -228,6 +235,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -245,6 +253,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -357,6 +366,7 @@ values:
content_disposition: null
content_encoding: null
content_language: null
contexts: []
customer_encryption: []
deletion_policy: null
detect_md5hash: null
@@ -1112,6 +1122,14 @@ values:
condition: []
project: ft0-prod-billing-exp-0
role: roles/viewer
module.factory.module.projects-iam["iac-0"].google_project_iam_audit_config.default["iam.googleapis.com"]:
audit_log_config:
- exempted_members: []
log_type: DATA_READ
- exempted_members: []
log_type: DATA_WRITE
project: ft0-prod-iac-core-0
service: iam.googleapis.com
module.factory.module.projects-iam["iac-0"].google_project_iam_audit_config.default["storage.googleapis.com"]:
audit_log_config:
- exempted_members: []
@@ -1241,6 +1259,82 @@ values:
module.factory.module.projects["iac-0"].data.google_storage_project_service_account.gcs_sa[0]:
project: ft0-prod-iac-core-0
user_project: null
module.factory.module.projects["iac-0"].google_logging_metric.metrics["sa-impersonation"]:
bucket_name: null
bucket_options: []
description: null
disabled: null
filter: 'protoPayload.serviceName="iamcredentials.googleapis.com"
(protoPayload.methodName="GenerateAccessToken" OR protoPayload.methodName="GenerateIdToken")
'
label_extractors:
email_id: EXTRACT(resource.labels.email_id)
metric_descriptor:
- display_name: Service Account Impersonation
labels:
- description: ''
key: email_id
value_type: STRING
metric_kind: DELTA
unit: '1'
value_type: INT64
name: sa-impersonation
project: ft0-prod-iac-core-0
timeouts: null
value_extractor: null
module.factory.module.projects["iac-0"].google_monitoring_alert_policy.alerts["sa-impersonation-alert"]:
alert_strategy: []
combiner: OR
conditions:
- condition_absent: []
condition_matched_log: []
condition_monitoring_query_language: []
condition_prometheus_query_language: []
condition_sql: []
condition_threshold:
- aggregations:
- alignment_period: 60s
cross_series_reducer: REDUCE_SUM
group_by_fields:
- metric.label.email_id
per_series_aligner: ALIGN_COUNT
comparison: COMPARISON_GT
denominator_aggregations: []
denominator_filter: null
duration: 60s
evaluation_missing_data: null
filter: 'metric.type="logging.googleapis.com/user/sa-impersonation" AND
resource.type="global"
'
forecast_options: []
threshold_value: 0
trigger:
- count: 1
percent: null
display_name: Impersonation Detected
display_name: Service Account Impersonation Alert
documentation: []
enabled: true
project: ft0-prod-iac-core-0
severity: null
timeouts: null
user_labels: null
module.factory.module.projects["iac-0"].google_monitoring_notification_channel.channels["email-security"]:
description: null
display_name: Security Team Email
enabled: true
force_delete: false
labels:
email_address: $email_addresses:gcp-organization-admins
project: ft0-prod-iac-core-0
sensitive_labels: []
timeouts: null
type: email
user_labels: null
module.factory.module.projects["iac-0"].google_org_policy_policy.default["iam.workloadIdentityPoolProviders"]:
dry_run_spec: []
name: projects/ft0-prod-iac-core-0/policies/iam.workloadIdentityPoolProviders
@@ -2862,6 +2956,7 @@ values:
stage: GA
title: Custom role tagViewer
module.organization[0].google_tags_tag_key.default["context"]:
allowed_values_regex: null
description: Organization-level contexts.
parent: organizations/1234567890
purpose: null
@@ -2869,6 +2964,7 @@ values:
short_name: context
timeouts: null
module.organization[0].google_tags_tag_key.default["environment"]:
allowed_values_regex: null
description: Organization-level environments.
parent: organizations/1234567890
purpose: null
@@ -2876,6 +2972,7 @@ values:
short_name: environment
timeouts: null
module.organization[0].google_tags_tag_key.default["org-policies"]:
allowed_values_regex: null
description: Organization policy condition tags.
parent: organizations/1234567890
purpose: null
@@ -2910,7 +3007,6 @@ values:
input: null
output: null
triggers_replace: null
counts:
google_bigquery_dataset: 1
google_bigquery_default_service_account: 2
@@ -2918,17 +3014,20 @@ counts:
google_essential_contacts_contact: 1
google_folder: 10
google_folder_iam_binding: 44
google_logging_metric: 1
google_logging_organization_settings: 1
google_logging_organization_sink: 3
google_logging_project_bucket_config: 3
google_logging_project_settings: 2
google_monitoring_alert_policy: 1
google_monitoring_notification_channel: 1
google_org_policy_custom_constraint: 1
google_org_policy_policy: 37
google_organization_iam_audit_config: 1
google_organization_iam_binding: 37
google_organization_iam_custom_role: 9
google_project: 3
google_project_iam_audit_config: 2
google_project_iam_audit_config: 3
google_project_iam_binding: 17
google_project_iam_member: 15
google_project_service: 33
@@ -2948,5 +3047,5 @@ counts:
google_tags_tag_value_iam_binding: 4
local_file: 9
modules: 50
resources: 324
resources: 328
terraform_data: 4

View File

@@ -0,0 +1,51 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
values:
module.looker.google_looker_instance.looker:
admin_settings: []
consumer_network: null
controlled_egress_config: []
controlled_egress_enabled: null
custom_domain: []
deletion_policy: DEFAULT
deny_maintenance_period: []
fips_enabled: null
gemini_enabled: null
maintenance_window: []
name: looker-psc
oauth_config:
- client_id: xxxxxxxxx
client_secret: xxxxxxxx
periodic_export_config: []
platform_edition: LOOKER_CORE_ENTERPRISE_ANNUAL
private_ip_enabled: false
project: project-id
psc_config:
- allowed_vpcs:
- projects/test-project/global/networks/test
service_attachments: []
psc_enabled: true
public_ip_enabled: false
region: europe-west8
reserved_range: null
timeouts: null
user_metadata: []
counts:
google_looker_instance: 1
modules: 1
resources: 1
outputs: {}

View File

@@ -31,6 +31,12 @@ context = {
tag_values = {
"test/one" = "tagValues/1234567890"
}
log_buckets = {
audit = "logging.googleapis.com/projects/my-project/locations/global/buckets/audit-bucket"
}
notification_channels = {
email = "projects/my-project/notificationChannels/12345"
}
vpc_sc_perimeters = {
default = "accessPolicies/888933661165/servicePerimeters/default"
}
@@ -38,6 +44,41 @@ context = {
test = "projects/test-prod-audit-logs-0/topics/audit-logs"
}
}
alerts = {
test-alert = {
combiner = "OR"
display_name = "Test Alert"
conditions = [{
display_name = "test-condition"
condition_threshold = {
comparison = "COMPARISON_GT"
duration = "60s"
filter = "resource.type=\"gce_instance\" AND metric.type=\"compute.googleapis.com/instance/cpu/utilization\""
}
}]
notification_channels = ["$notification_channels:email"]
}
}
logging_metrics = {
test-metric = {
filter = "resource.type=\"gce_instance\""
bucket_name = "$log_buckets:audit"
}
}
notification_channels = {
new-email = {
type = "email"
labels = {
email_address = "$email_addresses:default"
}
}
new-pubsub = {
type = "pubsub"
labels = {
topic = "$pubsub_topics:test"
}
}
}
asset_feeds = {
test = {
billing_project = "test-project"

View File

@@ -44,6 +44,17 @@ values:
condition: []
crypto_key_id: projects/kms-central-prj/locations/europe-west1/keyRings/my-keyring/cryptoKeys/ew1-compute
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
google_logging_metric.metrics["test-metric"]:
bucket_name: logging.googleapis.com/projects/my-project/locations/global/buckets/audit-bucket
bucket_options: []
description: null
disabled: null
filter: resource.type="gce_instance"
label_extractors: null
name: test-metric
project: my-project
timeouts: null
value_extractor: null
google_logging_project_sink.sink["test-pubsub"]:
custom_writer_identity: null
description: test-pubsub (Terraform-managed).
@@ -54,6 +65,60 @@ values:
name: test-pubsub
project: my-project
unique_writer_identity: true
google_monitoring_alert_policy.alerts["test-alert"]:
alert_strategy: []
combiner: OR
conditions:
- condition_absent: []
condition_matched_log: []
condition_monitoring_query_language: []
condition_prometheus_query_language: []
condition_sql: []
condition_threshold:
- aggregations: []
comparison: COMPARISON_GT
denominator_aggregations: []
denominator_filter: null
duration: 60s
evaluation_missing_data: null
filter: resource.type="gce_instance" AND metric.type="compute.googleapis.com/instance/cpu/utilization"
forecast_options: []
threshold_value: null
trigger: []
display_name: test-condition
display_name: Test Alert
documentation: []
enabled: true
notification_channels:
- projects/my-project/notificationChannels/12345
project: my-project
severity: null
timeouts: null
user_labels: null
google_monitoring_notification_channel.channels["new-email"]:
description: null
display_name: null
enabled: true
force_delete: false
labels:
email_address: foo@example.com
project: my-project
sensitive_labels: []
timeouts: null
type: email
user_labels: null
google_monitoring_notification_channel.channels["new-pubsub"]:
description: null
display_name: null
enabled: true
force_delete: false
labels:
topic: projects/test-prod-audit-logs-0/topics/audit-logs
project: my-project
sensitive_labels: []
timeouts: null
type: pubsub
user_labels: null
google_privileged_access_manager_entitlement.default["net-admins"]:
additional_notification_targets: []
approval_workflow:
@@ -253,7 +318,10 @@ counts:
google_compute_shared_vpc_service_project: 1
google_essential_contacts_contact: 1
google_kms_crypto_key_iam_member: 1
google_logging_metric: 1
google_logging_project_sink: 1
google_monitoring_alert_policy: 1
google_monitoring_notification_channel: 2
google_privileged_access_manager_entitlement: 1
google_project: 1
google_project_iam_audit_config: 1
@@ -267,4 +335,4 @@ counts:
google_tags_tag_value_iam_binding: 2
google_tags_tag_value_iam_member: 1
modules: 0
resources: 32
resources: 36

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# Copyright 2023 Google LLC
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,6 +13,15 @@
# 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.
#
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "click",
# "marko",
# "requests",
# ]
# ///
'''Recursively check link destination validity in Markdown files.
This tool recursively checks that local links in Markdown files point to valid

View File

@@ -60,6 +60,10 @@ duplicates = [
"fast/stages/2-security/schemas/folder.schema.json",
"modules/project-factory/schemas/folder.schema.json",
],
[
"fast/stages/0-org-setup/schemas/observability.schema.json",
"modules/project/schemas/observability.schema.json",
],
[
"fast/stages/1-vpcsc/schemas/ingress-policy.schema.json",
"modules/vpc-sc/schemas/ingress-policy.schema.json",