Merge remote-tracking branch 'origin/master' into fast-dev
This commit is contained in:
@@ -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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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({ psa_config = optional(object({ network = string allocated_ip_range = optional(string) enable_public_ip = optional(bool, false) enable_private_ip = optional(bool, true) })) public = optional(bool, false) })">object({…})</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({ client_id = optional(string, null) client_secret = optional(string, null) support_email = optional(string, null) })">object({…})</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({ psa_config = optional(object({ network = string allocated_ip_range = optional(string) 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) })">object({…})</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({ client_id = optional(string, null) client_secret = optional(string, null) support_email = optional(string, null) })">object({…})</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({ allowed_email_domains = list(string) })">object({…})</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({ kms_key_name = string })">object({…})</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({ maintenance_window = optional(object({ day = optional(string, "SUNDAY") start_time = optional(object({ hours = optional(number, 23) minutes = optional(number, 0) seconds = optional(number, 0) nanos = optional(number, 0) }), {}) }), null) deny_maintenance_period = optional(object({ start_date = object({ year = number month = number day = number }) end_date = object({ year = number month = number day = number }) start_time = optional(object({ hours = optional(number, 23) minutes = optional(number, 0) seconds = optional(number, 0) nanos = optional(number, 0) }), {}) }), null) })">object({…})</code> | | <code>{}</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>"LOOKER_CORE_TRIAL"</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>"LOOKER_CORE_TRIAL"</code> |
|
||||
| [prefix](variables.tf#L144) | Optional prefix used to generate instance names. | <code>string</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
51
tests/modules/looker_core/examples/psc.yaml
Normal file
51
tests/modules/looker_core/examples/psc.yaml
Normal 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: {}
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user