diff --git a/.github/actions/fabric-tests/action.yml b/.github/actions/fabric-tests/action.yml
index a25438da81..f31e77e742 100644
--- a/.github/actions/fabric-tests/action.yml
+++ b/.github/actions/fabric-tests/action.yml
@@ -72,7 +72,7 @@ runs:
shell: bash
run: |
for f in $(find . -name versions.tf); do
- sed -i -e 's/>=\(.*# tftest\)/=\1/g' -e 's/required_version = .*$/required_version = ">= ${{ inputs.TERRAFORM_VERSION }}"/g' $f;
+ sed -i 's/>=\(.*# tftest\)/=\1/g' $f;
done
- name: Install Python Dependencies
shell: bash
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 786cfbcbed..91976968ba 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -105,6 +105,18 @@ jobs:
- name: Check modules versions
id: versions
run: |
- OUTPUT=$(find . -type f -name 'versions.tf' -exec diff -ub default-versions.tf {} \;)
- echo "${OUTPUT}"
- [[ -z "${OUTPUT}" ]]
+ OUTPUT_TF=$(find . -type f -name 'versions.tf' -exec diff -ub default-versions.tf {} \;)
+ if [[ -n "${OUTPUT_TF}" ]] ; then
+ echo "Terraform versions.tf:"
+ echo "${OUTPUT_TF}"
+ fi
+ OUTPUT_TOFU=$(find . -type f -name 'versions.tofu' -exec diff -ub default-versions.tofu {} \;)
+ if [[ -n "${OUTPUT_TOFU}" ]] ; then
+ echo "Terraform versions.tofu:"
+ echo "${OUTPUT_TOFU}"
+ fi
+ grep -v required_version default-versions.tf > /tmp/versions.tf
+ grep -v required_version default-versions.tofu > /tmp/versions.tofu
+ diff -rub /tmp/versions.tf /tmp/versions.tofu
+ DIFF_EC=$?
+ [[ "${DIFF_EC}" -eq "0" || -z "${OUTPUT_TF}" || -z "${OUTPUT_TOFU}" ]]
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 05121ca16e..ac445f7856 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -38,7 +38,7 @@ env:
TFTEST_COPY: 1
DEFAULT_TERRAFORM_FLAVOUR: terraform
DEFAULT_TERRAFORM_VERSION: ${{ inputs.terraform_version || '1.10.2' }}
- DEFAULT_TOFU_VERSION: "1.7.2"
+ DEFAULT_TOFU_VERSION: "1.8.0"
jobs:
compute-matrix:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fd92568759..d12df74c86 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -56,6 +56,12 @@ repos:
files: (versions.tf|^default-versions.tf)$
pass_filenames: false
entry: /usr/bin/find . -type f -name 'versions.tf' -exec cp default-versions.tf {} \;
+ - id: versions_tofu
+ name: Align OpenTofu provider versions
+ language: script
+ files: (versions.tofu|^default-versions.tofu)$
+ pass_filenames: false
+ entry: /usr/bin/find . -type f -name 'versions.tofu' -exec cp default-versions.tofu {} \;
- id: validate_metadata
name: Validate blueprints metadata
language: system
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d9b40e69bf..b203310dd7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,9 +4,12 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+- [[#2777](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2777)] Document `tag_bindings` definition as `map(string)` ([juliocc](https://github.com/juliocc))
### BLUEPRINTS
+- [[#2721](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2721)] New BindPlane OP Management console on GKE SecOps blueprint ([simonebruzzechesse](https://github.com/simonebruzzechesse))
+- [[#2771](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2771)] Use separate versions.tofu for OpenTofu constraints ([wiktorn](https://github.com/wiktorn))
- [[#2768](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2768)] Support customizable resource names in FAST stage 0 ([ludoo](https://github.com/ludoo))
- [[#2761](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2761)] Refactor GKE cluster modules access configurations, add support for DNS endpoint ([ludoo](https://github.com/ludoo))
- [[#2736](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2736)] Add confidential compute support to google_dataproc_cluster module, bump provider versions ([steenblik](https://github.com/steenblik))
@@ -17,6 +20,7 @@ All notable changes to this project will be documented in this file.
### FAST
+- [[#2774](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2774)] [FAST] Remove unused stage 1 CICD variables ([LucaPrete](https://github.com/LucaPrete))
- [[#2769](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2769)] Support customizable resource names to fast stage 1 ([ludoo](https://github.com/ludoo))
- [[#2768](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2768)] Support customizable resource names in FAST stage 0 ([ludoo](https://github.com/ludoo))
- [[#2767](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2767)] Fix workspace logs sink in FAST bootstrap stage ([ludoo](https://github.com/ludoo))
@@ -27,6 +31,13 @@ All notable changes to this project will be documented in this file.
### MODULES
+- [[#2784](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2784)] Fix validation message in cas module ([ludoo](https://github.com/ludoo))
+- [[#2783](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2783)] Update net-lb-app-ext security_settings variables ([wenzizone](https://github.com/wenzizone))
+- [[#2781](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2781)] Fix bindplane cos module ([simonebruzzechesse](https://github.com/simonebruzzechesse))
+- [[#2780](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2780)] Fix handling of SSL certificates in external load balancer modules ([rodriguezsergio](https://github.com/rodriguezsergio))
+- [[#2776](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2776)] Add support for log views and log scopes ([juliocc](https://github.com/juliocc))
+- [[#2772](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2772)] Fix for perma-diff when using PSC NEGs. ([wiktorn](https://github.com/wiktorn))
+- [[#2771](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2771)] Use separate versions.tofu for OpenTofu constraints ([wiktorn](https://github.com/wiktorn))
- [[#2768](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2768)] Support customizable resource names in FAST stage 0 ([ludoo](https://github.com/ludoo))
- [[#2761](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2761)] **incompatible change:** Refactor GKE cluster modules access configurations, add support for DNS endpoint ([ludoo](https://github.com/ludoo))
- [[#2764](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2764)] Ignore ssl certificates if none are passed in net-lb-app-int module ([ludoo](https://github.com/ludoo))
@@ -47,6 +58,9 @@ All notable changes to this project will be documented in this file.
### TOOLS
+- [[#2778](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2778)] Fix failing tests for OpenTofu ([wiktorn](https://github.com/wiktorn))
+- [[#2721](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2721)] New BindPlane OP Management console on GKE SecOps blueprint ([simonebruzzechesse](https://github.com/simonebruzzechesse))
+- [[#2771](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2771)] Use separate versions.tofu for OpenTofu constraints ([wiktorn](https://github.com/wiktorn))
- [[#2769](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2769)] Support customizable resource names to fast stage 1 ([ludoo](https://github.com/ludoo))
- [[#2768](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2768)] Support customizable resource names in FAST stage 0 ([ludoo](https://github.com/ludoo))
- [[#2765](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/2765)] Update issue templates ([juliocc](https://github.com/juliocc))
diff --git a/adrs/20241029-versioning.md b/adrs/20241029-versioning.md
index 2911cbeaed..7dcc3a1931 100644
--- a/adrs/20241029-versioning.md
+++ b/adrs/20241029-versioning.md
@@ -1,6 +1,6 @@
# Versioning Scheme Tied to FAST Releases
-**authors:** [Ludo](https://github.com/ludoo), [Julio](https://github.com/jccb), [Simone](https://github.com/sruffilli) \
+**authors:** [Ludo](https://github.com/ludoo), [Julio](https://github.com/juliocc), [Simone](https://github.com/sruffilli) \
**date:** Oct 29, 2024
**last update**: Oct 30, 2024
diff --git a/adrs/20241219-tag-bindings.md b/adrs/20241219-tag-bindings.md
new file mode 100644
index 0000000000..421289205f
--- /dev/null
+++ b/adrs/20241219-tag-bindings.md
@@ -0,0 +1,35 @@
+# Using `map(string)` for `tag_bindings` variables
+
+**authors:** [Julio](https://github.com/juliocc)
+**date:** Dec 19, 2024
+
+## Status
+
+Accepted and implemented.
+
+## Context
+
+We need to define a variable to manage tag bindings in our Terraform modules. This variable will be used across various modules and within the FAST framework to attach tags to resources via the `google_tags_tag_binding` resource. This variable needs to support both statically defined tags and tags that are dynamically generated during the apply phase of Terraform.
+
+## Decision:
+
+We will use the `map(string)` type for the `tag_bindings` variable across all modules where it's needed.
+
+## Consequences
+
+Minimal. This is already an established practice across the repository.
+
+Note that the keys of the map are ignored by our code and only used to bypass Terraform limitations with dynamic values in a `for_each` argument. See [Using Expressions in for_each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#using-expressions-in-for_each) in Terraform's documentation for more details.
+
+## Reasoning
+
+The primary reason for choosing `map(string)` is to enable the use of dynamic tags without encountering Terraform errors related to dynamic values. By using a map, we avoid the limitations imposed by lists or sets and ensure that our modules and FAST can handle both static and dynamic tag values.
+
+## Alternatives Considered:
+
+- `list(string)`: Lists would enforce a fixed number of tags defined at plan time, limiting flexibility and hindering the management of dynamic tags.
+- `set(string)`: Similar to lists, sets would require all tag values to be known at plan time, which is not suitable for scenarios with dynamic tag generation.
+
+## Implementation:
+
+At the time of writing this ADR, all modules and FAST stages already use `map(string)`. The purpose of this ADR is to document an existing practice.
diff --git a/adrs/fast/1-network-ranges.md b/adrs/fast/1-network-ranges.md
index 2a5c647547..5d33f14062 100644
--- a/adrs/fast/1-network-ranges.md
+++ b/adrs/fast/1-network-ranges.md
@@ -1,6 +1,6 @@
# IP ranges for network stages
-**authors:** [Ludo](https://github.com/ludoo), [Roberto](https://github.com/drebes), [Julio](https://github.com/jccb) \
+**authors:** [Ludo](https://github.com/ludoo), [Roberto](https://github.com/drebes), [Julio](https://github.com/juliocc) \
**date:** Sept 20, 2023
## Status
diff --git a/adrs/fast/addon-stages.md b/adrs/fast/addon-stages.md
new file mode 100644
index 0000000000..325e1c71d1
--- /dev/null
+++ b/adrs/fast/addon-stages.md
@@ -0,0 +1,76 @@
+# Add-on stages
+
+**authors:** [Ludo](https://github.com/ludoo), [Julio](https://github.com/juliocc)
+**date:** Jan 5, 2025
+
+## Status
+
+Under implementation
+
+## Context
+
+Some optional features are too complex to directly embed in stages, as they would complicate the variable scope, need to be replicated across parallel stages, and introduce a lot of nested code for the benefit of a small subset of users.
+
+This need has surfaced with the network security stage, which has taken the approach of spreading its resources across different stages (security, networking, and its own netsec) and resulted in very layered, complicated code which is not easy to deploy or maintain.
+
+This is how the current netsec stage looks like from a resource perspective:
+
+![image](https://github.com/user-attachments/assets/c9778cd8-8dd4-4f7c-b74b-c5d8ad7e7d30)
+
+Furthermore, the stage also tries to do "too much", by behaving as a full stage and adopting a design that statically maps its resources onto all FAST environments and networks. This results in code that is really hard to adapt for real life use cases and impossible to keep forward compatible, as changes are extensive and spread out across three stages.
+
+## Proposal
+
+The proposal is to adopt a completely different approach, where large optional featuresets that we don't want to embed in our default stages should become "addon stages" that:
+
+- reuse the IaC service account and bucket of the stage they interact with (e.g. networking for network security) to eliminate the need for custom IAM
+- encapsulate all their resources in a single root module (the add-on stage)
+- don't implement a static design but deal with the smallest possible unit of work, so that they can be cloned to implement different designs via tfvars
+- provide optional FAST output variables for the main stages
+
+This is what the network security stage looks like, once refactored according this proposal:
+
+![image](https://github.com/user-attachments/assets/748b8b53-8df7-444e-9c71-f74e462a96f1)
+
+With this approach
+
+- there are no dependencies in resman except for a providers file that adds a prefix to the state backend and reuses networking service accounts and bucket
+- the stage design does not deal with environments, but simply implements one complete set of NGFW resources in a given project (typically the net landing or shared environment project) and allows free configuration of zones and VPC attachments
+- any relevant resource already defined in the "main" stages can be referred to via interpolation, by using the stages outputs as contexts
+
+The code then becomes really simple to use, read and evolve since it's essentially decoupled from the main stages except for a handful of FAST interface variables.
+
+Add-on stages should live in a separate folder from stages, and once we finally manage to reafctor networking into a simple stage, we go back to having a clear progression for main stages that should make it easier for users to get to grips with FAST's complexity. We might also want to scrap the plugins folder, and replace with a short document explaining the pattern.
+
+```bash
+fast
+├── addons
+ ├── 1-tenant-factory
+ └── 2-network-security
+├── assets
+│ └── templates
+├── extras
+│ ├── 0-cicd-github
+│ └── 0-cicd-gitlab
+├── plugins
+│ └── 2-networking-serverless-connector
+└── stages
+ ├── 0-bootstrap
+ ├── 1-resman
+ ├── 1-vpcsc
+ ├── 2-networking-a-simple
+ ├── 2-networking-b-nva
+ ├── 2-networking-c-separate-envs
+ ├── 2-project-factory
+ ├── 2-security
+ ├── 3-gcve-dev
+ └── 3-gke-dev
+```
+
+## Decision
+
+TBD
+
+## Consequences
+
+This approach also maps well to the current tenant factory stage, which essentially acts as a parallel resman stage reusing the same set of IaC resources.
diff --git a/adrs/modules/20231106-factories.md b/adrs/modules/20231106-factories.md
index 857f9b7a3b..8786d86f81 100644
--- a/adrs/modules/20231106-factories.md
+++ b/adrs/modules/20231106-factories.md
@@ -5,7 +5,7 @@
## Status
-Under discussion.
+Accepted and implemented.
## Context
diff --git a/blueprints/data-solutions/bq-ml/README.md b/blueprints/data-solutions/bq-ml/README.md
index eabfe9d69b..39a9c0decc 100644
--- a/blueprints/data-solutions/bq-ml/README.md
+++ b/blueprints/data-solutions/bq-ml/README.md
@@ -97,5 +97,5 @@ module "test" {
prefix = "prefix"
}
-# tftest modules=9 resources=68
+# tftest modules=9 resources=69
```
diff --git a/blueprints/data-solutions/data-playground/README.md b/blueprints/data-solutions/data-playground/README.md
index 34824bf695..9890619d38 100644
--- a/blueprints/data-solutions/data-playground/README.md
+++ b/blueprints/data-solutions/data-playground/README.md
@@ -84,5 +84,5 @@ module "test" {
parent = "folders/467898377"
}
}
-# tftest modules=8 resources=67
+# tftest modules=8 resources=68
```
diff --git a/blueprints/data-solutions/vertex-mlops/README.md b/blueprints/data-solutions/vertex-mlops/README.md
index 6277c4f528..6c4e5913de 100644
--- a/blueprints/data-solutions/vertex-mlops/README.md
+++ b/blueprints/data-solutions/vertex-mlops/README.md
@@ -72,7 +72,7 @@ module "test" {
project_id = "test-dev"
}
}
-# tftest modules=11 resources=89
+# tftest modules=11 resources=90
```
## Variables
@@ -128,5 +128,5 @@ module "test" {
project_id = "test-dev"
}
}
-# tftest modules=13 resources=94 e2e
+# tftest modules=13 resources=95 e2e
```
diff --git a/blueprints/data-solutions/vertex-mlops/vertex.tf b/blueprints/data-solutions/vertex-mlops/vertex.tf
index 19e5ca7c58..90e57f3914 100644
--- a/blueprints/data-solutions/vertex-mlops/vertex.tf
+++ b/blueprints/data-solutions/vertex-mlops/vertex.tf
@@ -124,4 +124,7 @@ resource "google_workbench_instance" "playground" {
depends_on = [
google_project_iam_member.shared_vpc,
]
+ lifecycle {
+ ignore_changes = [gce_setup[0].metadata["resource-url"]]
+ }
}
diff --git a/blueprints/gke/patterns/autopilot-cluster/cluster.tf b/blueprints/gke/patterns/autopilot-cluster/cluster.tf
index 69285b2bc9..e2b94c647c 100644
--- a/blueprints/gke/patterns/autopilot-cluster/cluster.tf
+++ b/blueprints/gke/patterns/autopilot-cluster/cluster.tf
@@ -22,7 +22,7 @@ locals {
)
cluster_sa = (
local._cluster_sa == "default"
- ? module.project.service_accounts.default.compute
+ ? module.project.default_service_accounts.compute
: local._cluster_sa
)
cluster_sa_roles = [
diff --git a/blueprints/gke/patterns/autopilot-cluster/versions.tofu b/blueprints/gke/patterns/autopilot-cluster/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/autopilot-cluster/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/gke/patterns/batch/versions.tofu b/blueprints/gke/patterns/batch/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/batch/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/gke/patterns/kafka/versions.tofu b/blueprints/gke/patterns/kafka/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/kafka/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/gke/patterns/kong-cloudrun/versions.tofu b/blueprints/gke/patterns/kong-cloudrun/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/kong-cloudrun/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/gke/patterns/mysql/versions.tofu b/blueprints/gke/patterns/mysql/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/mysql/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/gke/patterns/redis-cluster/versions.tofu b/blueprints/gke/patterns/redis-cluster/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/gke/patterns/redis-cluster/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/blueprints/secops/README.md b/blueprints/secops/README.md
index 0d42455f68..04082de5d8 100644
--- a/blueprints/secops/README.md
+++ b/blueprints/secops/README.md
@@ -2,6 +2,13 @@
This repository provides a collection of Terraform blueprints designed to automate the implementation of custom integrations, agents and configurations for Google Cloud Security and Operations SecOps (aka Chronicle).
+## BindPlane OP Management on GKE
+
+ This [blueprint](./bindplane-gke/) is a modular and scalable solution for deployment of the BindPlane OP Management Console within a Google Kubernetes Engine (GKE) environment.
+
+
+
+
## SecOps GKE Forwarder
This [blueprint](./secops-gke-forwarder/) is a modular and scalable solution for setting up a SecOps forwarder on Google Kubernetes Engine (GKE). This forwarder is designed to handle multi-tenant data ingestion, ensuring secure and efficient log forwarding to your SecOps SIEM instances.
diff --git a/blueprints/secops/bindplane-gke/OWNERS b/blueprints/secops/bindplane-gke/OWNERS
new file mode 100644
index 0000000000..65c8fc162f
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/OWNERS
@@ -0,0 +1 @@
+simonebruzzechesse
diff --git a/blueprints/secops/bindplane-gke/README.md b/blueprints/secops/bindplane-gke/README.md
new file mode 100644
index 0000000000..a89beeb99a
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/README.md
@@ -0,0 +1,162 @@
+# BindPlane OP Management console on GKE
+
+This Terraform module simplifies the deployment of the BindPlane OP Management Console within a Google Kubernetes Engine (GKE) environment. It's specifically engineered for organizations seeking a scalable and highly available solution, capitalizing on the strengths of containerization and managed platform services like Cloud SQL for PostgreSQL.
+
+This module streamlines the process of deploying BindPlane OP, by leveraging GKE, PubSub and Cloud SQL, this module provides:
+
+- **Simplified Deployment**: Deploy a production-ready BindPlane OP environment with minimal manual configuration.
+- **Enhanced Scalability**: Easily adapt to increasing demands and data volumes as your needs evolve.
+- **Increased Resilience**: Benefit from the high availability and fault tolerance offered by GKE and Cloud SQL.
+- **Operational Efficiency**: Reduce operational overhead by utilizing managed Kubernetes and database services.
+
+This module encapsulates best practices for deploying BindPlane OP in a cloud-native environment, ensuring a robust and reliable foundation for your observability platform.
+
+### High level architecture
+
+The following diagram illustrates the high-level design of created resources, which can be adapted to specific requirements via variables:
+
+![Bindplane OP Management console on GKE](./images/diagram.png)
+
+BindPlane OP Management console will be exposed via Internal HTTPS Load Balancer, this module assume a private connection to GCP environment is in place to reach the BindPlane management console over private IPs.
+In case no private connection is in place it should be pretty straightforward to setup a proxy VM to proxy the connection towards the bindplane console. Of course such a deployment can only deal with agents running on the same GCP infrastructure.
+
+### Deployment
+
+#### Step 0: Cloning the repository
+
+If you want to deploy from your Cloud Shell, click on the image below, sign in
+if required and when the prompt appears, click on “confirm”.
+
+[![Open Cloudshell](./images/cloud-shell-button.png)](https://shell.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fcloud-foundation-fabric&cloudshell_workspace=blueprints%2Fthird-party-solutions%2Fwordpress%2Fcloudrun)
+
+Otherwise, in your console of choice:
+
+```bash
+git clone https://github.com/GoogleCloudPlatform/cloud-foundation-fabric.git
+```
+
+Before you deploy the architecture, you will need at least the following
+information/configurations in place (for more precise configuration see the Variables section):
+
+* The project ID
+* The VPC host project
+* VPC and subnets should already exist
+* Subnet must be configured with pods and services secondary ranges (default names for secondary ranges is "pod" and "services")
+
+#### Step 2: Prepare the variables
+
+Once you have the required information, head back to your cloned repository.
+Make sure you’re in the directory of this tutorial (where this README is in).
+
+Configure the Terraform variables in your `terraform.tfvars` file.
+See the example test at the end of this README.md as starting point - just
+copy it to `terraform.tfvars` and edit the latter. See the variables
+documentation below.
+
+> **Warning**
+>
+> BindPlane secrets (such as license and admin password) specified as variables within this Terraform configuration will be stored in plain text within the Terraform state file.
+
+#### Step 3: Prepare the providers in the root module
+
+Setup terraform providers in the root module to deal with kubernetes resources as follows:
+
+```terraform
+data "google_client_config" "identity" {
+ count = module.bindplane-gke.fleet_host != null ? 1 : 0
+}
+
+provider "kubernetes" {
+ host = module.bindplane-gke.fleet_host
+ token = try(data.google_client_config.identity.0.access_token, null)
+}
+
+provider "kubectl" {
+ host = module.bindplane-gke.fleet_host
+ token = try(data.google_client_config.identity.0.access_token, null)
+}
+```
+
+#### Step 4: Deploy resources
+
+Initialize your Terraform environment and deploy the resources:
+
+```shell
+terraform init
+terraform apply
+```
+
+Get kubeconfig to connect to the cluster using the command below:
+
+```shell
+gcloud container fleet memberships get-credentials CLUSTER_NAME --project PROJECT
+```
+
+Then running the command `kubectl get pods` you should receive the following message:
+
+```
+"No resources found in default namespace."
+```
+
+In case private connection is available and DNS configuration is properly in place you should be able to reach the BindPlane OP Management console navigating the url (e.g. https://bindplane.example.com/), the following login page should show up.
+
+![Bindplane OP Management console login page](./images/login.png)
+
+Access the management console leveraging credentials bootstrapped via terraform (user and password in `bindplane_secrets` variable).
+
+## Variables
+
+| name | description | type | required | default |
+|---|---|:---:|:---:|:---:|
+| [bindplane_secrets](variables.tf#L27) | Bindplane secrets. | object({…})
| ✓ | |
+| [network_config](variables.tf#L58) | Shared VPC network configurations to use for GKE cluster. | object({…})
| ✓ | |
+| [prefix](variables.tf#L80) | Prefix used for resource names. | string
| ✓ | |
+| [project_id](variables.tf#L99) | Project id, references existing project if `project_create` is null. | string
| ✓ | |
+| [region](variables.tf#L104) | GCP region. | string
| ✓ | |
+| [bindplane_config](variables.tf#L17) | Bindplane config. | object({…})
| | {}
|
+| [cluster_config](variables.tf#L37) | GKE cluster configuration. | object({…})
| | {}
|
+| [dns_config](variables.tf#L48) | DNS config. | object({…})
| | {}
|
+| [postgresql_config](variables.tf#L70) | Cloud SQL postgresql config. | object({…})
| | {}
|
+| [project_create](variables.tf#L90) | Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | object({…})
| | null
|
+
+## Outputs
+
+| name | description | sensitive |
+|---|---|:---:|
+| [bindplane_hostname](outputs.tf#L17) | BindPlane OP Management console hostname. | |
+| [ca_cert](outputs.tf#L22) | TLS CA certificate. | |
+| [cluster_ca_certificate](outputs.tf#L27) | GKE CA Certificate. | |
+| [fleet_host](outputs.tf#L32) | GKE Fleet host. | |
+| [lb_ip_address](outputs.tf#L37) | Ingress LB address. | |
+
+## Test
+
+```hcl
+module "bindplane-gke" {
+ source = "./fabric/blueprints/secops/bindplane-gke"
+ project_id = "test"
+ project_create = {
+ billing_account_id = "12345-ABCDEF-12345"
+ parent = "folders/2345678901"
+ }
+ bindplane_secrets = {
+ user = "admin"
+ password = "thisisnotasecret"
+ sessions_secret = "xxxxxx-xxxxxxx-xxxxxx"
+ license = "XXXXXXXXXXXXXXXXXXXXXX"
+ }
+ dns_config = {
+ bootstrap_private_zone = true
+ domain = "example.com"
+ hostname = "bindplane"
+ }
+ network_config = {
+ network_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/global/networks/prod-landing-0"
+ subnet_self_link = "https://www.googleapis.com/compute/v1/projects/prod-net-landing-0/regions/europe-west1/subnetworks/gke"
+ ip_range_gke_master = "192.168.0.0/28"
+ }
+ region = "europe-west8"
+ prefix = "tmp"
+}
+# tftest modules=10 resources=45
+```
diff --git a/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf b/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf
new file mode 100644
index 0000000000..abdeb4de1c
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/bindplane-deployment/main.tf
@@ -0,0 +1,59 @@
+/**
+ * Copyright 2024 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.
+ */
+
+locals {
+ bindplane_password = coalesce(var.bindplane_secrets.password, try(random_password.password.0.result, null))
+}
+
+resource "random_password" "password" {
+ count = var.bindplane_secrets.password == null ? 1 : 0
+ length = 16
+ special = true
+ override_special = "_!%^"
+}
+
+resource "kubernetes_namespace" "namespace" {
+ metadata {
+ name = "bindplane"
+ }
+}
+
+resource "kubernetes_secret" "bindplane_secret" {
+ metadata {
+ name = "bindplane"
+ namespace = kubernetes_namespace.namespace.metadata[0].name
+ }
+
+ data = {
+ username = var.bindplane_secrets.user
+ password = local.bindplane_password
+ sessions_secret = var.bindplane_secrets.sessions_secret
+ license = var.bindplane_secrets.license
+ }
+ type = "Opaque"
+}
+
+resource "kubernetes_secret" "tls" {
+ metadata {
+ name = "bindplane-tls"
+ namespace = kubernetes_namespace.namespace.metadata[0].name
+ }
+ data = {
+ "tls.crt" = var.bindplane_tls.cer
+ "tls.key" = var.bindplane_tls.key
+ }
+ type = "kubernetes.io/tls"
+}
diff --git a/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf b/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf
new file mode 100644
index 0000000000..4d15bfacf7
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/bindplane-deployment/variables.tf
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2024 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.
+ */
+
+variable "bindplane_secrets" {
+ description = "Bindplane configuration."
+ type = object({
+ license = string
+ user = optional(string, "admin")
+ password = optional(string, null)
+ sessions_secret = string
+ })
+}
+
+variable "bindplane_tls" {
+ description = "Bindplane TLS certificates."
+ type = object({
+ cer = string
+ key = string
+ })
+}
diff --git a/blueprints/secops/bindplane-gke/config/values.yaml.tpl b/blueprints/secops/bindplane-gke/config/values.yaml.tpl
new file mode 100644
index 0000000000..496f1e160b
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/config/values.yaml.tpl
@@ -0,0 +1,91 @@
+# This ingress example uses Ingress NGINX and Cert Manager
+# for creating Lets Encrypt signed certificates.
+#
+# - https://kubernetes.github.io/ingress-nginx/deploy/#gce-gke
+# - https://cert-manager.io/docs/tutorials/getting-started-with-cert-manager-on-google-kubernetes-engine-using-lets-encrypt-for-ingress-ssl/
+#
+ingress:
+ enable: true
+ host: ${hostname}
+ class: "gce-internal"
+ tls:
+ enable: true
+ secret: bindplane-tls
+ annotations:
+ # cert-manager.io/issuer: letsencrypt
+ kubernetes.io/ingress.regional-static-ip-name: ${address}
+
+config:
+ # Use the secret named "bindplane", which contains
+ # the license, username, password, secret_key, and sessions_secret.
+ # If you do not want to use a secret, see the comment below and
+ # disable this option.
+ licenseUseSecret: true
+
+ # Defaults to wss://bindplane.bindplane.svc.cluster.local:3001/v1/opamp,
+ # which is the bindplane namespace's bindplane service. This is suitable
+ # for connecting agents within the same cluster. We are using ingress
+ # so server_url needs to be updated to the ingress host.
+ # NOTE: server_url maps to bindplane's network.remoteURL option.
+ server_url: https://${hostname}
+
+# Fixed number of pods. BindPlane CPU usage is bursty, using
+# a pod autoscaler can be tricky. Generally a fixed number
+# of pods is recommended.
+replicas: 2
+
+image:
+ # -- Image name to be used. Defaults to `ghcr.io/observiq/bindplane-ee`.
+ name: ""
+ # Overrides the image tag whose default is {{ .Chart.AppVersion }}
+ # -- Image tag to use. Defaults to the version defined in the Chart's release.
+ tag: ${tag}
+
+resources:
+ # Allow cpu bursting by leaving limits.cpu unset
+ requests:
+ cpu: '1000m'
+ memory: '4096Mi'
+ limits:
+ memory: '4096Mi'
+
+# Node pools must be authenticated to Pub/Sub with one of the following options
+# - Pub/Sub scope enabled
+# - GKE Service Account with Pub/Sub permissions
+# - Service Account key file and the GOOGLE_APPLICATION_CREDENTIALS environment variable set
+# to the path of the key file. You can use extraVolumes, extraVolumeMounts, extraEnv to
+# mount a configMap or secret containing the key file.
+eventbus:
+ type: 'pubsub'
+ pubsub:
+ projectid: '${gcp_project_id}'
+ topic: 'bindplane'
+
+backend:
+ type: postgres
+ postgres:
+ host: '${postgresql_ip}'
+ port: 5432
+ database: 'bindplane'
+ username: '${postgresql_username}'
+ password: '${postgresql_password}'
+ # Replicas * max connections should not exceed
+ # your Postgres instance's max connections.
+ # This option defaults to 100, which is too high
+ # for an environment with 7 replicas.
+ maxConnections: 20
+
+transform_agent:
+ replicas: 2
+
+# Prometheus is deployed and managed by the Helm chart. At scale
+# it will require additional resources which can be set here.
+prometheus:
+ resources:
+ requests:
+ cpu: '2000m'
+ memory: '8192Mi'
+ limits:
+ memory: '8192Mi'
+ storage:
+ volumeSize: '120Gi'
diff --git a/blueprints/secops/bindplane-gke/images/cloud-shell-button.png b/blueprints/secops/bindplane-gke/images/cloud-shell-button.png
new file mode 100644
index 0000000000..21a3f3de9d
Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/cloud-shell-button.png differ
diff --git a/blueprints/secops/bindplane-gke/images/diagram.png b/blueprints/secops/bindplane-gke/images/diagram.png
new file mode 100644
index 0000000000..ff1902c171
Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/diagram.png differ
diff --git a/blueprints/secops/bindplane-gke/images/login.png b/blueprints/secops/bindplane-gke/images/login.png
new file mode 100644
index 0000000000..2681ce887a
Binary files /dev/null and b/blueprints/secops/bindplane-gke/images/login.png differ
diff --git a/blueprints/secops/bindplane-gke/main.tf b/blueprints/secops/bindplane-gke/main.tf
new file mode 100644
index 0000000000..6f84c781db
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/main.tf
@@ -0,0 +1,225 @@
+/**
+ * Copyright 2024 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.
+ */
+
+locals {
+ fleet_host = join("", [
+ "https://connectgateway.googleapis.com/v1/",
+ "projects/${module.project.number}/",
+ "locations/global/gkeMemberships/bindplane"
+ ])
+}
+
+module "project" {
+ source = "../../../modules/project"
+ billing_account = (var.project_create != null
+ ? var.project_create.billing_account_id
+ : null
+ )
+ parent = (var.project_create != null
+ ? var.project_create.parent
+ : null
+ )
+ prefix = var.prefix
+ project_create = var.project_create != null
+ name = var.project_id
+ services = concat([
+ "compute.googleapis.com",
+ "iap.googleapis.com",
+ "stackdriver.googleapis.com",
+ "chronicle.googleapis.com",
+ "container.googleapis.com",
+ "gkehub.googleapis.com",
+ "connectgateway.googleapis.com",
+ "gkeconnect.googleapis.com"
+ ])
+ iam = {
+ "roles/pubsub.editor" = ["principal://iam.googleapis.com/projects/${module.project.number}/locations/global/workloadIdentityPools/${module.project.project_id}.svc.id.goog/subject/ns/bindplane/sa/bindplane"]
+ }
+}
+
+module "fleet" {
+ source = "../../../modules/gke-hub"
+ project_id = module.project.project_id
+ clusters = {
+ "bindplane" = module.bindplane-cluster.id
+ }
+}
+
+module "bindplane-cluster" {
+ source = "../../../modules/gke-cluster-autopilot"
+ project_id = module.project.project_id
+ name = var.cluster_config.cluster_name
+ location = var.region
+ deletion_protection = false
+ vpc_config = {
+ network = var.network_config.network_self_link
+ subnetwork = var.network_config.subnet_self_link
+ secondary_range_names = {
+ pods = var.network_config.secondary_pod_range_name
+ services = var.network_config.secondary_services_range_name
+ }
+ master_ipv4_cidr_block = var.network_config.ip_range_gke_master
+ master_authorized_ranges = var.cluster_config.master_authorized_ranges
+ }
+ access_config = {
+ dns_access = false
+ ip_access = {
+ authorized_ranges = {
+ "rfc-1918-10-8" = "10.0.0.0/8"
+ }
+ private_endpoint_config = {
+ global_access = true
+ }
+ }
+ }
+ enable_features = {
+ gateway_api = true
+ }
+ logging_config = {
+ enable_api_server_logs = true
+ enable_scheduler_logs = true
+ enable_controller_manager_logs = true
+ }
+ monitoring_config = {
+ enable_daemonset_metrics = true
+ enable_deployment_metrics = true
+ enable_hpa_metrics = true
+ enable_pod_metrics = true
+ enable_statefulset_metrics = true
+ enable_storage_metrics = true
+ enable_api_server_metrics = true
+ enable_controller_manager_metrics = true
+ enable_scheduler_metrics = true
+ }
+}
+
+module "db" {
+ source = "../../../modules/cloudsql-instance"
+ project_id = module.project.project_id
+ databases = ["bindplane"]
+ network_config = {
+ connectivity = {
+ psc_allowed_consumer_projects = [module.project.project_id]
+ }
+ }
+ prefix = var.prefix
+ name = "bindplane"
+ region = var.region
+ availability_type = var.postgresql_config.availability_type
+ database_version = var.postgresql_config.database_version
+ tier = var.postgresql_config.tier
+
+ users = {
+ bindplane = {
+ password = null
+ type = "BUILT_IN"
+ }
+ }
+
+ gcp_deletion_protection = false
+ terraform_deletion_protection = false
+}
+
+module "addresses" {
+ source = "../../../modules/net-address"
+ project_id = module.project.project_id
+ internal_addresses = {
+ ingress = {
+ purpose = "SHARED_LOADBALANCER_VIP"
+ region = var.region
+ subnetwork = var.network_config.subnet_self_link
+ }
+ }
+ psc_addresses = {
+ postgresql = {
+ address = ""
+ region = var.region
+ subnet_self_link = var.network_config.subnet_self_link
+ service_attachment = {
+ psc_service_attachment_link = module.db.psc_service_attachment_link
+ global_access = true
+ }
+ }
+ }
+}
+
+module "dns" {
+ source = "../../../modules/dns"
+ count = var.dns_config.bootstrap_private_zone ? 1 : 0
+ project_id = module.project.project_id
+ name = "bindplane"
+ zone_config = {
+ domain = "${var.dns_config.domain}."
+ private = {
+ client_networks = [var.network_config.network_self_link]
+ }
+ }
+ recordsets = {
+ "A ${var.dns_config.hostname}" = { ttl = 600, records = [module.addresses.internal_addresses["ingress"].address] }
+ }
+}
+
+module "pubsub" {
+ source = "../../../modules/pubsub"
+ project_id = module.project.project_id
+ name = "bindplane"
+}
+
+module "bindplane-sa" {
+ source = "../../../modules/iam-service-account"
+ project_id = module.project.project_id
+ name = "bindplane"
+ iam = {
+ "roles/iam.workloadIdentityUser" = ["serviceAccount:${module.project.project_id}.svc.id.goog[bindplane/bindplane]"]
+ }
+ iam_project_roles = {
+ "${module.project.project_id}" = [
+ "roles/pubsub.editor"
+ ]
+ }
+}
+
+module "bindplane-deployment" {
+ source = "./bindplane-deployment"
+ depends_on = [module.bindplane-cluster]
+ bindplane_secrets = var.bindplane_secrets
+ bindplane_tls = {
+ cer = coalesce(var.bindplane_config.tls_certificate_cer, try(tls_locally_signed_cert.server_singed_cert.0.cert_pem, null))
+ key = coalesce(var.bindplane_config.tls_certificate_key, try(tls_private_key.server_key.0.private_key_pem, null))
+ }
+}
+
+resource "helm_release" "bindplane" {
+ name = "bindplane"
+ repository = "https://observiq.github.io/bindplane-op-helm"
+ chart = "bindplane"
+ namespace = "bindplane"
+ create_namespace = false
+ values = [templatefile("${path.module}/config/values.yaml.tpl", {
+ postgresql_ip = module.addresses.psc_addresses["postgresql"].address
+ postgresql_username = "bindplane"
+ postgresql_password = module.db.user_passwords["bindplane"]
+ gcp_project_id = module.project.project_id
+ hostname = "${var.dns_config.hostname}.${var.dns_config.domain}"
+ address = "ingress"
+ tag = var.bindplane_config.image_tag
+ })]
+
+ depends_on = [
+ module.bindplane-deployment,
+ module.addresses
+ ]
+}
diff --git a/blueprints/secops/bindplane-gke/outputs.tf b/blueprints/secops/bindplane-gke/outputs.tf
new file mode 100644
index 0000000000..a8ee465c33
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/outputs.tf
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2024 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.
+ */
+
+output "bindplane_hostname" {
+ description = "BindPlane OP Management console hostname."
+ value = "https://${var.dns_config.hostname}.${var.dns_config.domain}"
+}
+
+output "ca_cert" {
+ description = "TLS CA certificate."
+ value = try(tls_self_signed_cert.ca_cert.0.cert_pem, null)
+}
+
+output "cluster_ca_certificate" {
+ description = "GKE CA Certificate."
+ value = module.bindplane-cluster.ca_certificate
+}
+
+output "fleet_host" {
+ description = "GKE Fleet host."
+ value = local.fleet_host
+}
+
+output "lb_ip_address" {
+ description = "Ingress LB address."
+ value = module.addresses.internal_addresses["ingress"].address
+}
diff --git a/blueprints/secops/bindplane-gke/ssl.tf b/blueprints/secops/bindplane-gke/ssl.tf
new file mode 100644
index 0000000000..7fd460f3ed
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/ssl.tf
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2024 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.
+ */
+
+locals {
+ bootstrap_self_signed_cert = var.bindplane_config.tls_certificate_cer == null || var.bindplane_config.tls_certificate_key == null
+ cert_subjects = [
+ {
+ country = "IT"
+ province = "Lombardy"
+ locality = "Milan"
+ organization = "Example"
+ organizational_unit = "Example"
+ }
+ ]
+}
+
+#######################################################################
+# CA PRIVATE KEY #
+#######################################################################
+
+resource "tls_private_key" "ca_private_key" {
+ count = local.bootstrap_self_signed_cert ? 1 : 0
+ algorithm = "RSA"
+}
+
+#######################################################################
+# CA CERT #
+#######################################################################
+
+resource "tls_self_signed_cert" "ca_cert" {
+ count = local.bootstrap_self_signed_cert ? 1 : 0
+ private_key_pem = tls_private_key.ca_private_key.0.private_key_pem
+ is_ca_certificate = true
+ dynamic "subject" {
+ for_each = toset(local.cert_subjects)
+ content {
+ country = subject.value.country
+ province = subject.value.province
+ locality = subject.value.locality
+ common_name = "Bindplane"
+ organization = subject.value.organization
+ organizational_unit = subject.value.organization
+ }
+ }
+ validity_period_hours = 87600 // 3650 days or 10 years
+ allowed_uses = [
+ "digital_signature",
+ "cert_signing",
+ "crl_signing",
+ ]
+}
+
+#######################################################################
+# SERVER CERT SIGNED BY CA #
+#######################################################################
+
+resource "tls_private_key" "server_key" {
+ count = local.bootstrap_self_signed_cert ? 1 : 0
+ algorithm = "RSA"
+}
+
+resource "tls_cert_request" "server_csr" {
+ count = local.bootstrap_self_signed_cert ? 1 : 0
+ private_key_pem = tls_private_key.server_key.0.private_key_pem
+ dns_names = ["${var.dns_config.hostname}.${var.dns_config.domain}"]
+
+ dynamic "subject" {
+ for_each = toset(local.cert_subjects)
+ content {
+ country = subject.value.country
+ province = subject.value.province
+ locality = subject.value.locality
+ common_name = "Gitlab"
+ organization = subject.value.organization
+ organizational_unit = subject.value.organization
+ }
+ }
+}
+
+resource "tls_locally_signed_cert" "server_singed_cert" {
+ count = local.bootstrap_self_signed_cert ? 1 : 0
+ cert_request_pem = tls_cert_request.server_csr.0.cert_request_pem
+ ca_private_key_pem = tls_private_key.ca_private_key.0.private_key_pem
+ ca_cert_pem = tls_self_signed_cert.ca_cert.0.cert_pem
+
+ validity_period_hours = 87600 // 3650 days or 10 years
+
+ allowed_uses = [
+ "digital_signature",
+ "key_encipherment",
+ "server_auth",
+ "client_auth",
+ ]
+}
diff --git a/blueprints/secops/bindplane-gke/variables.tf b/blueprints/secops/bindplane-gke/variables.tf
new file mode 100644
index 0000000000..2b2ca5e115
--- /dev/null
+++ b/blueprints/secops/bindplane-gke/variables.tf
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2024 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.
+ */
+
+variable "bindplane_config" {
+ description = "Bindplane config."
+ type = object({
+ image_tag = optional(string, "")
+ tls_certificate_cer = optional(string, null)
+ tls_certificate_key = optional(string, null)
+ })
+ default = {}
+}
+
+variable "bindplane_secrets" {
+ description = "Bindplane secrets."
+ type = object({
+ license = string
+ user = optional(string, "admin")
+ password = optional(string, null)
+ sessions_secret = string
+ })
+}
+
+variable "cluster_config" {
+ description = "GKE cluster configuration."
+ type = object({
+ cluster_name = optional(string, "bindplane-op")
+ master_authorized_ranges = optional(map(string), {
+ rfc-1918-10-8 = "10.0.0.0/8"
+ })
+ })
+ default = {}
+}
+
+variable "dns_config" {
+ description = "DNS config."
+ type = object({
+ bootstrap_private_zone = optional(bool, false)
+ domain = optional(string, "example.com")
+ hostname = optional(string, "bindplane")
+ })
+ default = {}
+}
+
+variable "network_config" {
+ description = "Shared VPC network configurations to use for GKE cluster."
+ type = object({
+ host_project = optional(string)
+ network_self_link = string
+ subnet_self_link = string
+ ip_range_gke_master = string
+ secondary_pod_range_name = optional(string, "pods")
+ secondary_services_range_name = optional(string, "services")
+ })
+}
+
+variable "postgresql_config" {
+ description = "Cloud SQL postgresql config."
+ type = object({
+ availability_type = optional(string, "REGIONAL")
+ database_version = optional(string, "POSTGRES_13")
+ tier = optional(string, "db-g1-small")
+ })
+ default = {}
+}
+
+variable "prefix" {
+ description = "Prefix used for resource names."
+ type = string
+ nullable = false
+ validation {
+ condition = var.prefix != ""
+ error_message = "Prefix cannot be empty."
+ }
+}
+
+variable "project_create" {
+ description = "Provide values if project creation is needed, uses existing project if null. Parent is in 'folders/nnn' or 'organizations/nnn' format."
+ type = object({
+ billing_account_id = string
+ parent = string
+ })
+ default = null
+}
+
+variable "project_id" {
+ description = "Project id, references existing project if `project_create` is null."
+ type = string
+}
+
+variable "region" {
+ description = "GCP region."
+ type = string
+}
diff --git a/blueprints/secops/secops-gke-forwarder/versions.tofu b/blueprints/secops/secops-gke-forwarder/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/blueprints/secops/secops-gke-forwarder/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/default-versions.tofu b/default-versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/default-versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index c77e56f7a2..339b951700 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -273,8 +273,8 @@ terraform apply
| [prefix](variables-fast.tf#L147) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
| [custom_roles](variables-fast.tf#L53) | Custom roles defined at the org level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
| [factories_config](variables.tf#L20) | Configuration for the resource factories or external data. | object({…})
| | {}
| |
-| [fast_stage_2](variables-stages.tf#L17) | FAST stages 2 configurations. | object({…})
| | {}
| |
-| [fast_stage_3](variables-stages.tf#L97) | FAST stages 3 configurations. | map(object({…}))
| | {}
| |
+| [fast_stage_2](variables-stages.tf#L17) | FAST stages 2 configurations. | object({…})
| | {}
| |
+| [fast_stage_3](variables-stages.tf#L95) | FAST stages 3 configurations. | map(object({…}))
| | {}
| |
| [groups](variables-fast.tf#L88) | Group names or IAM-format principals to grant organization-level permissions. If just the name is provided, the 'group:' principal and organization domain are interpolated. | object({…})
| | {}
| 0-bootstrap
|
| [locations](variables-fast.tf#L103) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…})
| | {}
| 0-bootstrap
|
| [outputs_location](variables.tf#L31) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string
| | null
| |
diff --git a/fast/stages/1-resman/variables-stages.tf b/fast/stages/1-resman/variables-stages.tf
index d3d244a8ef..c46bdb9776 100644
--- a/fast/stages/1-resman/variables-stages.tf
+++ b/fast/stages/1-resman/variables-stages.tf
@@ -23,10 +23,9 @@ variable "fast_stage_2" {
cicd_config = optional(object({
identity_provider = string
repository = object({
- name = string
- branch = optional(string)
- parent_id = optional(string)
- type = optional(string, "github")
+ name = string
+ branch = optional(string)
+ type = optional(string, "github")
})
}))
folder_config = optional(object({
@@ -42,10 +41,9 @@ variable "fast_stage_2" {
cicd_config = optional(object({
identity_provider = string
repository = object({
- name = string
- branch = optional(string)
- parent_id = optional(string)
- type = optional(string, "github")
+ name = string
+ branch = optional(string)
+ type = optional(string, "github")
})
}))
}), {})
diff --git a/modules/__experimental_deprecated/alloydb-instance/versions.tofu b/modules/__experimental_deprecated/alloydb-instance/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/__experimental_deprecated/alloydb-instance/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/__experimental_deprecated/net-neg/versions.tofu b/modules/__experimental_deprecated/net-neg/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/__experimental_deprecated/net-neg/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/__experimental_deprecated/project-iam-magic/versions.tofu b/modules/__experimental_deprecated/project-iam-magic/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/__experimental_deprecated/project-iam-magic/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/alloydb/versions.tofu b/modules/alloydb/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/alloydb/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/analytics-hub/versions.tofu b/modules/analytics-hub/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/analytics-hub/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/api-gateway/versions.tofu b/modules/api-gateway/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/api-gateway/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/apigee/versions.tofu b/modules/apigee/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/apigee/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/artifact-registry/versions.tofu b/modules/artifact-registry/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/artifact-registry/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/bigquery-dataset/versions.tofu b/modules/bigquery-dataset/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/bigquery-dataset/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/bigtable-instance/versions.tofu b/modules/bigtable-instance/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/bigtable-instance/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/billing-account/versions.tofu b/modules/billing-account/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/billing-account/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/binauthz/versions.tofu b/modules/binauthz/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/binauthz/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/certificate-authority-service/variables.tf b/modules/certificate-authority-service/variables.tf
index 747625add7..bb7c621125 100644
--- a/modules/certificate-authority-service/variables.tf
+++ b/modules/certificate-authority-service/variables.tf
@@ -125,7 +125,7 @@ variable "ca_pool_config" {
var.ca_pool_config.ca_pool_id != null ||
var.ca_pool_config.name != null
)
- error_message = "Tier can only be `DEVOPS` or `ENTERPRISE`."
+ error_message = "Either name or id need to be provided."
}
validation {
condition = (
diff --git a/modules/certificate-authority-service/versions.tofu b/modules/certificate-authority-service/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/certificate-authority-service/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/certificate-manager/versions.tofu b/modules/certificate-manager/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/certificate-manager/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/__need_fixing/onprem/versions.tofu b/modules/cloud-config-container/__need_fixing/onprem/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/__need_fixing/onprem/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/__need_fixing/squid/versions.tofu b/modules/cloud-config-container/__need_fixing/squid/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/__need_fixing/squid/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/bindplane/README.md b/modules/cloud-config-container/bindplane/README.md
index 035722521e..055b22f229 100644
--- a/modules/cloud-config-container/bindplane/README.md
+++ b/modules/cloud-config-container/bindplane/README.md
@@ -42,12 +42,13 @@ Navigate to http://localhost:3001 to access the Bindplane console, the following
This example will create a `cloud-config` that uses the module's defaults, creating a simple bindplane server with default (latest) docker image versions and setting localhost as remote url (suited only for local development).
```hcl
-module "cos-nginx" {
- source = "./fabric/modules/cloud-config-container/bindplane"
- password = "secret"
+module "cos-bindplane" {
+ source = "./fabric/modules/cloud-config-container/bindplane"
+ bindplane_license = "XXXXXXXXX"
+ password = "secret"
}
-module "vm-nginx-tls" {
+module "bindplane" {
source = "./fabric/modules/compute-vm"
project_id = "my-project"
zone = "europe-west8-b"
@@ -57,7 +58,7 @@ module "vm-nginx-tls" {
subnetwork = "gce"
}]
metadata = {
- user-data = module.cos-nginx.cloud_config
+ user-data = module.cos-bindplane.cloud_config
google-logging-enabled = true
}
boot_disk = {
@@ -71,21 +72,21 @@ module "vm-nginx-tls" {
}
# tftest modules=2 resources=2
```
-
## Variables
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [password](variables.tf#L63) | Default admin user password. | string
| ✓ | |
+| [bindplane_license](variables.tf#L29) | BindPlane server license. | string
| ✓ | |
+| [password](variables.tf#L68) | Default admin user password. | string
| ✓ | |
| [bindplane_config](variables.tf#L17) | Bindplane configurations. | object({…})
| | {}
|
-| [cloud_config](variables.tf#L29) | Cloud config template path. If null default will be used. | string
| | null
|
-| [config_variables](variables.tf#L35) | Additional variables used to render the cloud-config and Nginx templates. | map(any)
| | {}
|
-| [file_defaults](variables.tf#L41) | Default owner and permissions for files. | object({…})
| | {…}
|
-| [files](variables.tf#L53) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…}))
| | {}
|
-| [runcmd_post](variables.tf#L68) | Extra commands to run after starting nginx. | list(string)
| | []
|
-| [runcmd_pre](variables.tf#L74) | Extra commands to run before starting nginx. | list(string)
| | []
|
-| [users](variables.tf#L80) | List of additional usernames to be created. | list(object({…}))
| | […]
|
+| [cloud_config](variables.tf#L34) | Cloud config template path. If null default will be used. | string
| | null
|
+| [config_variables](variables.tf#L40) | Additional variables used to render the cloud-config and Nginx templates. | map(any)
| | {}
|
+| [file_defaults](variables.tf#L46) | Default owner and permissions for files. | object({…})
| | {…}
|
+| [files](variables.tf#L58) | Map of extra files to create on the instance, path as key. Owner and permissions will use defaults if null. | map(object({…}))
| | {}
|
+| [runcmd_post](variables.tf#L73) | Extra commands to run after starting nginx. | list(string)
| | []
|
+| [runcmd_pre](variables.tf#L79) | Extra commands to run before starting nginx. | list(string)
| | []
|
+| [users](variables.tf#L85) | List of additional usernames to be created. | list(object({…}))
| | […]
|
## Outputs
diff --git a/modules/cloud-config-container/bindplane/cloud-config.yaml b/modules/cloud-config-container/bindplane/cloud-config.yaml
index 78f6ea6ec5..885a0af402 100644
--- a/modules/cloud-config-container/bindplane/cloud-config.yaml
+++ b/modules/cloud-config-container/bindplane/cloud-config.yaml
@@ -47,7 +47,7 @@ write_files:
volumes:
bindplane:
prometheus:
-
+
services:
prometheus:
container_name: bindplane-prometheus
@@ -57,14 +57,14 @@ write_files:
- "9090:9090"
volumes:
- prometheus:/prometheus
-
+
transform:
container_name: bindplane-transform-agent
restart: always
image: ${bindplane_transform_agent_image}
ports:
- "4568:4568"
-
+
bindplane:
container_name: bindplane-server
restart: always
@@ -72,6 +72,7 @@ write_files:
ports:
- "3001:3001"
environment:
+ - BINDPLANE_LICENSE=${license}
- BINDPLANE_USERNAME=admin
- BINDPLANE_PASSWORD=${password}
- BINDPLANE_REMOTE_URL=http://${remote_url}:3001
diff --git a/modules/cloud-config-container/bindplane/main.tf b/modules/cloud-config-container/bindplane/main.tf
index a2a11f8654..ab7ba0660e 100644
--- a/modules/cloud-config-container/bindplane/main.tf
+++ b/modules/cloud-config-container/bindplane/main.tf
@@ -21,6 +21,7 @@ locals {
bindplane_transform_agent_image = var.bindplane_config.bindplane_transform_agent_image
files = local.files
password = var.password
+ license = var.bindplane_license
remote_url = var.bindplane_config.remote_url
runcmd_pre = var.runcmd_pre
runcmd_post = var.runcmd_post
diff --git a/modules/cloud-config-container/bindplane/variables.tf b/modules/cloud-config-container/bindplane/variables.tf
index 39856f4585..92082aa8dd 100644
--- a/modules/cloud-config-container/bindplane/variables.tf
+++ b/modules/cloud-config-container/bindplane/variables.tf
@@ -26,6 +26,11 @@ variable "bindplane_config" {
nullable = false
}
+variable "bindplane_license" {
+ description = "BindPlane server license."
+ type = string
+}
+
variable "cloud_config" {
description = "Cloud config template path. If null default will be used."
type = string
diff --git a/modules/cloud-config-container/bindplane/versions.tofu b/modules/cloud-config-container/bindplane/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/bindplane/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/coredns/versions.tofu b/modules/cloud-config-container/coredns/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/coredns/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/cos-generic-metadata/versions.tofu b/modules/cloud-config-container/cos-generic-metadata/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/cos-generic-metadata/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tofu b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/envoy-sni-dyn-fwd-proxy/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/envoy-traffic-director/versions.tofu b/modules/cloud-config-container/envoy-traffic-director/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/envoy-traffic-director/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/mysql/versions.tofu b/modules/cloud-config-container/mysql/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/mysql/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/nginx-tls/versions.tofu b/modules/cloud-config-container/nginx-tls/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/nginx-tls/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/nginx/versions.tofu b/modules/cloud-config-container/nginx/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/nginx/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-config-container/simple-nva/versions.tofu b/modules/cloud-config-container/simple-nva/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-config-container/simple-nva/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-function-v1/versions.tofu b/modules/cloud-function-v1/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-function-v1/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-function-v2/versions.tofu b/modules/cloud-function-v2/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-function-v2/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-identity-group/versions.tofu b/modules/cloud-identity-group/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-identity-group/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-run-v2/versions.tofu b/modules/cloud-run-v2/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-run-v2/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloud-run/versions.tofu b/modules/cloud-run/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloud-run/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/cloudsql-instance/versions.tofu b/modules/cloudsql-instance/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/cloudsql-instance/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/compute-mig/versions.tofu b/modules/compute-mig/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/compute-mig/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/compute-vm/versions.tofu b/modules/compute-vm/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/compute-vm/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/container-registry/versions.tofu b/modules/container-registry/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/container-registry/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/data-catalog-policy-tag/versions.tofu b/modules/data-catalog-policy-tag/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/data-catalog-policy-tag/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/data-catalog-tag-template/versions.tofu b/modules/data-catalog-tag-template/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/data-catalog-tag-template/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/data-catalog-tag/versions.tofu b/modules/data-catalog-tag/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/data-catalog-tag/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dataform-repository/versions.tofu b/modules/dataform-repository/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dataform-repository/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/datafusion/versions.tofu b/modules/datafusion/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/datafusion/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dataplex-datascan/versions.tofu b/modules/dataplex-datascan/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dataplex-datascan/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dataplex/versions.tofu b/modules/dataplex/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dataplex/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dataproc/versions.tofu b/modules/dataproc/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dataproc/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dns-response-policy/versions.tofu b/modules/dns-response-policy/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dns-response-policy/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/dns/versions.tofu b/modules/dns/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/dns/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/endpoints/versions.tofu b/modules/endpoints/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/endpoints/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/firestore/versions.tofu b/modules/firestore/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/firestore/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/folder/versions.tofu b/modules/folder/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/folder/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gcs/versions.tofu b/modules/gcs/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gcs/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gcve-private-cloud/versions.tofu b/modules/gcve-private-cloud/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gcve-private-cloud/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gke-cluster-autopilot/versions.tofu b/modules/gke-cluster-autopilot/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gke-cluster-autopilot/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gke-cluster-standard/versions.tofu b/modules/gke-cluster-standard/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gke-cluster-standard/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gke-hub/versions.tofu b/modules/gke-hub/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gke-hub/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/gke-nodepool/versions.tofu b/modules/gke-nodepool/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/gke-nodepool/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/iam-service-account/versions.tofu b/modules/iam-service-account/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/iam-service-account/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/kms/versions.tofu b/modules/kms/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/kms/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/logging-bucket/README.md b/modules/logging-bucket/README.md
index 8ace8a1031..3f776e3bf1 100644
--- a/modules/logging-bucket/README.md
+++ b/modules/logging-bucket/README.md
@@ -6,9 +6,20 @@ Note that some logging buckets are automatically created for a given folder, pro
See also the `logging_sinks` argument within the [project](../project/), [folder](../folder/) and [organization](../organization) modules.
-## Examples
+## TOC
-### Create custom logging bucket in a project
+
+- [TOC](#toc)
+- [Custom logging bucket in a project](#custom-logging-bucket-in-a-project)
+- [Custom logging bucket in a project with Log Analytics](#custom-logging-bucket-in-a-project-with-log-analytics)
+- [Change retention period of a folder's _Default bucket](#change-retention-period-of-a-folders-_default-bucket)
+- [Organization and billing account buckets](#organization-and-billing-account-buckets)
+- [Custom bucket with views](#custom-bucket-with-views)
+- [Variables](#variables)
+- [Outputs](#outputs)
+
+
+## Custom logging bucket in a project
```hcl
module "bucket" {
@@ -20,7 +31,7 @@ module "bucket" {
# tftest modules=1 resources=1 inventory=project.yaml
```
-### Create custom logging bucket in a project enabling Log Analytics and dataset link
+## Custom logging bucket in a project with Log Analytics
```hcl
module "bucket" {
@@ -36,7 +47,7 @@ module "bucket" {
# tftest modules=1 resources=2 inventory=log_analytics.yaml
```
-### Change retention period of a folder's _Default bucket
+## Change retention period of a folder's _Default bucket
```hcl
module "folder" {
@@ -55,7 +66,7 @@ module "bucket-default" {
# tftest modules=2 resources=2 inventory=retention.yaml
```
-### Organization and billing account buckets
+## Organization and billing account buckets
```hcl
module "bucket-organization" {
@@ -73,6 +84,26 @@ module "bucket-billing-account" {
}
# tftest modules=2 resources=2 inventory=org-ba.yaml
```
+
+## Custom bucket with views
+
+```hcl
+module "bucket" {
+ source = "./fabric/modules/logging-bucket"
+ parent_type = "project"
+ parent = var.project_id
+ id = "mybucket"
+ views = {
+ myview = {
+ filter = "LOG_ID(\"stdout\")"
+ iam = {
+ "roles/logging.viewAccessor" = ["user:user@example.com"]
+ }
+ }
+ }
+}
+# tftest modules=1 resources=3 inventory=views.yaml
+```
## Variables
@@ -86,10 +117,13 @@ module "bucket-billing-account" {
| [location](variables.tf#L34) | Location of the bucket. | string
| | "global"
|
| [log_analytics](variables.tf#L40) | Enable and configure Analytics Log. | object({…})
| | {}
|
| [retention](variables.tf#L61) | Retention time in days for the logging bucket. | number
| | 30
|
+| [tag_bindings](variables.tf#L67) | Tag bindings for this bucket, in key => tag value id format. | map(string)
| | {}
|
+| [views](variables.tf#L74) | Log views for this bucket. | map(object({…}))
| | {}
|
## Outputs
| name | description | sensitive |
|---|---|:---:|
| [id](outputs.tf#L17) | Fully qualified logging bucket id. | |
+| [view_ids](outputs.tf#L22) | The automatic and user-created views in this bucket. | |
diff --git a/modules/logging-bucket/iam.tf b/modules/logging-bucket/iam.tf
new file mode 100644
index 0000000000..2f671b209e
--- /dev/null
+++ b/modules/logging-bucket/iam.tf
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2024 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.
+ */
+
+locals {
+ view_iam = flatten([
+ for k, v in var.views : [
+ for role, members in v.iam : {
+ view = k
+ role = role
+ members = members
+ }
+ ]
+ ])
+ view_iam_bindings = merge([
+ for k, v in var.views : {
+ for binding_key, data in v.iam_bindings :
+ binding_key => {
+ view = k
+ role = data.role
+ members = data.members
+ condition = data.condition
+ }
+ }
+ ]...)
+ view_iam_bindings_additive = merge([
+ for k, v in var.views : {
+ for binding_key, data in v.iam_bindings_additive :
+ binding_key => {
+ view = k
+ role = data.role
+ member = data.member
+ condition = data.condition
+ }
+ }
+ ]...)
+}
+
+resource "google_logging_log_view_iam_binding" "authoritative" {
+ for_each = {
+ for binding in local.view_iam :
+ "${binding.view}.${binding.role}" => binding
+ }
+ role = each.value.role
+ members = each.value.members
+ parent = google_logging_log_view.views[each.value.view].parent
+ location = google_logging_log_view.views[each.value.view].location
+ bucket = google_logging_log_view.views[each.value.view].bucket
+ name = google_logging_log_view.views[each.value.view].name
+}
+
+resource "google_logging_log_view_iam_binding" "bindings" {
+ for_each = local.view_iam_bindings
+ role = each.value.role
+ members = each.value.members
+ parent = google_logging_log_view.views[each.value.view].parent
+ location = google_logging_log_view.views[each.value.view].location
+ bucket = google_logging_log_view.views[each.value.view].bucket
+ name = google_logging_log_view.views[each.value.view].name
+
+ dynamic "condition" {
+ for_each = each.value.condition == null ? [] : [""]
+ content {
+ expression = each.value.condition.expression
+ title = each.value.condition.title
+ description = each.value.condition.description
+ }
+ }
+}
+
+resource "google_logging_log_view_iam_member" "members" {
+ for_each = local.view_iam_bindings_additive
+ role = each.value.role
+ member = each.value.member
+ parent = google_logging_log_view.views[each.value.view].parent
+ location = google_logging_log_view.views[each.value.view].location
+ bucket = google_logging_log_view.views[each.value.view].bucket
+ name = google_logging_log_view.views[each.value.view].name
+
+ dynamic "condition" {
+ for_each = each.value.condition == null ? [] : [""]
+ content {
+ expression = each.value.condition.expression
+ title = each.value.condition.title
+ description = each.value.condition.description
+ }
+ }
+}
diff --git a/modules/logging-bucket/main.tf b/modules/logging-bucket/main.tf
index 697eb4306c..6fe84adf1c 100644
--- a/modules/logging-bucket/main.tf
+++ b/modules/logging-bucket/main.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,15 @@
* limitations under the License.
*/
+locals {
+ bucket = try(
+ google_logging_project_bucket_config.bucket[0],
+ google_logging_folder_bucket_config.bucket[0],
+ google_logging_organization_bucket_config.bucket[0],
+ google_logging_billing_account_bucket_config.bucket[0],
+ )
+}
+
resource "google_logging_project_bucket_config" "bucket" {
count = var.parent_type == "project" ? 1 : 0
project = var.parent
@@ -66,3 +75,18 @@ resource "google_logging_billing_account_bucket_config" "bucket" {
bucket_id = var.id
description = var.description
}
+
+resource "google_logging_log_view" "views" {
+ for_each = var.views
+ name = each.key
+ bucket = local.bucket.id
+ description = each.value.description
+ location = coalesce(each.value.location, var.location)
+ filter = each.value.filter
+}
+
+resource "google_tags_tag_binding" "binding" {
+ for_each = var.tag_bindings
+ parent = "//logging.googleapis.com/${local.bucket.id}"
+ tag_value = each.value
+}
diff --git a/modules/logging-bucket/outputs.tf b/modules/logging-bucket/outputs.tf
index 00eed9a77e..276673a959 100644
--- a/modules/logging-bucket/outputs.tf
+++ b/modules/logging-bucket/outputs.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 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,10 +16,18 @@
output "id" {
description = "Fully qualified logging bucket id."
- value = try(
- google_logging_project_bucket_config.bucket[0].id,
- google_logging_folder_bucket_config.bucket[0].id,
- google_logging_organization_bucket_config.bucket[0].id,
- google_logging_billing_account_bucket_config.bucket[0].id,
+ value = local.bucket.id
+}
+
+output "view_ids" {
+ description = "The automatic and user-created views in this bucket."
+ value = merge(
+ {
+ for k, v in google_logging_log_view.views :
+ k => v.id
+ },
+ {
+ "_AllLogs" = "${local.bucket.id}/views/_AllLogs"
+ }
)
}
diff --git a/modules/logging-bucket/variables.tf b/modules/logging-bucket/variables.tf
index 1720ac4051..39b50bc248 100644
--- a/modules/logging-bucket/variables.tf
+++ b/modules/logging-bucket/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,3 +63,39 @@ variable "retention" {
type = number
default = 30
}
+
+variable "tag_bindings" {
+ description = "Tag bindings for this bucket, in key => tag value id format."
+ type = map(string)
+ default = {}
+ nullable = false
+}
+
+variable "views" {
+ description = "Log views for this bucket."
+ type = map(object({
+ filter = string
+ location = optional(string)
+ description = optional(string)
+ iam = optional(map(list(string)), {})
+ iam_bindings = optional(map(object({
+ members = list(string)
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ })), {})
+ iam_bindings_additive = optional(map(object({
+ member = string
+ role = string
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ })), {})
+ }))
+ default = {}
+ nullable = false
+}
diff --git a/modules/logging-bucket/versions.tofu b/modules/logging-bucket/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/logging-bucket/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/looker-core/versions.tofu b/modules/looker-core/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/looker-core/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/ncc-spoke-ra/versions.tofu b/modules/ncc-spoke-ra/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/ncc-spoke-ra/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-address/versions.tofu b/modules/net-address/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-address/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-cloudnat/versions.tofu b/modules/net-cloudnat/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-cloudnat/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-firewall-policy/versions.tofu b/modules/net-firewall-policy/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-firewall-policy/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-ipsec-over-interconnect/versions.tofu b/modules/net-ipsec-over-interconnect/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-ipsec-over-interconnect/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-app-ext-regional/main.tf b/modules/net-lb-app-ext-regional/main.tf
index edd486c178..7868a80761 100644
--- a/modules/net-lb-app-ext-regional/main.tf
+++ b/modules/net-lb-app-ext-regional/main.tf
@@ -80,7 +80,7 @@ resource "google_compute_region_target_https_proxy" "default" {
region = var.region
description = var.description
certificate_manager_certificates = var.https_proxy_config.certificate_manager_certificates
- ssl_certificates = local.proxy_ssl_certificates
+ ssl_certificates = length(local.proxy_ssl_certificates) == 0 ? null : local.proxy_ssl_certificates
ssl_policy = var.https_proxy_config.ssl_policy
url_map = google_compute_region_url_map.default.id
}
diff --git a/modules/net-lb-app-ext-regional/negs.tf b/modules/net-lb-app-ext-regional/negs.tf
index 5fbf71bcf2..1b1bb662a3 100644
--- a/modules/net-lb-app-ext-regional/negs.tf
+++ b/modules/net-lb-app-ext-regional/negs.tf
@@ -89,6 +89,10 @@ resource "google_compute_region_network_endpoint_group" "psc" {
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
+ lifecycle {
+ # ignore until https://github.com/hashicorp/terraform-provider-google/issues/20576 is fixed
+ ignore_changes = [psc_data]
+ }
}
resource "google_compute_region_network_endpoint_group" "serverless" {
diff --git a/modules/net-lb-app-ext-regional/versions.tofu b/modules/net-lb-app-ext-regional/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-app-ext-regional/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-app-ext/README.md b/modules/net-lb-app-ext/README.md
index b11c8d5409..83872dc348 100644
--- a/modules/net-lb-app-ext/README.md
+++ b/modules/net-lb-app-ext/README.md
@@ -1050,7 +1050,7 @@ After provisioning this change, and verifying that the new certificate is provis
| [project_id](variables.tf#L195) | Project id. | string
| ✓ | |
| [address](variables.tf#L17) | Optional IP address used for the forwarding rule. | string
| | null
|
| [backend_buckets_config](variables.tf#L23) | Backend buckets configuration. | map(object({…}))
| | {}
|
-| [backend_service_configs](variables-backend-service.tf#L19) | Backend service level configuration. | map(object({…})) }))
| | {}
|
+| [backend_service_configs](variables-backend-service.tf#L19) | Backend service level configuration. | map(object({…})) }))
| | {}
|
| [description](variables.tf#L56) | Optional description used for resources. | string
| | "Terraform managed."
|
| [group_configs](variables.tf#L62) | Optional unmanaged groups to create. Can be referenced in backends via key or outputs. | map(object({…}))
| | {}
|
| [health_check_configs](variables-health-check.tf#L19) | Optional auto-created health check configurations, use the output self-link to set it in the auto healing policy. Refer to examples for usage. | map(object({…}))
| | {…}
|
diff --git a/modules/net-lb-app-ext/main.tf b/modules/net-lb-app-ext/main.tf
index f2680d9886..f385dc8402 100644
--- a/modules/net-lb-app-ext/main.tf
+++ b/modules/net-lb-app-ext/main.tf
@@ -83,7 +83,7 @@ resource "google_compute_target_https_proxy" "default" {
certificate_map = var.https_proxy_config.certificate_map
certificate_manager_certificates = var.https_proxy_config.certificate_manager_certificates
quic_override = var.https_proxy_config.quic_override
- ssl_certificates = local.proxy_ssl_certificates
+ ssl_certificates = length(local.proxy_ssl_certificates) == 0 ? null : local.proxy_ssl_certificates
ssl_policy = var.https_proxy_config.ssl_policy
url_map = google_compute_url_map.default.id
server_tls_policy = var.https_proxy_config.mtls_policy
diff --git a/modules/net-lb-app-ext/negs.tf b/modules/net-lb-app-ext/negs.tf
index 0011968d52..290866c6fb 100644
--- a/modules/net-lb-app-ext/negs.tf
+++ b/modules/net-lb-app-ext/negs.tf
@@ -130,6 +130,10 @@ resource "google_compute_region_network_endpoint_group" "psc" {
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
+ lifecycle {
+ # ignore until https://github.com/hashicorp/terraform-provider-google/issues/20576 is fixed
+ ignore_changes = [psc_data]
+ }
}
resource "google_compute_region_network_endpoint_group" "serverless" {
diff --git a/modules/net-lb-app-ext/variables-backend-service.tf b/modules/net-lb-app-ext/variables-backend-service.tf
index 7a431e10a6..9b24b0c845 100644
--- a/modules/net-lb-app-ext/variables-backend-service.tf
+++ b/modules/net-lb-app-ext/variables-backend-service.tf
@@ -121,8 +121,8 @@ variable "backend_service_configs" {
}))
}))
security_settings = optional(object({
- client_tls_policy = string
- subject_alt_names = list(string)
+ client_tls_policy = optional(string)
+ subject_alt_names = optional(list(string))
aws_v4_authentication = optional(object({
access_key_id = optional(string)
access_key = optional(string)
diff --git a/modules/net-lb-app-ext/versions.tofu b/modules/net-lb-app-ext/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-app-ext/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-app-int-cross-region/main.tf b/modules/net-lb-app-int-cross-region/main.tf
index e3b3b50361..a46e018297 100644
--- a/modules/net-lb-app-int-cross-region/main.tf
+++ b/modules/net-lb-app-int-cross-region/main.tf
@@ -163,4 +163,8 @@ resource "google_compute_region_network_endpoint_group" "psc" {
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
+ lifecycle {
+ # ignore until https://github.com/hashicorp/terraform-provider-google/issues/20576 is fixed
+ ignore_changes = [psc_data]
+ }
}
diff --git a/modules/net-lb-app-int-cross-region/versions.tofu b/modules/net-lb-app-int-cross-region/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-app-int-cross-region/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-app-int/README.md b/modules/net-lb-app-int/README.md
index 0d268045dd..87eaeab54d 100644
--- a/modules/net-lb-app-int/README.md
+++ b/modules/net-lb-app-int/README.md
@@ -26,6 +26,7 @@ Due to the complexity of the underlying resources, changes to the configuration
- [Files](#files)
- [Variables](#variables)
- [Outputs](#outputs)
+- [Fixtures](#fixtures)
### Minimal Example
@@ -375,7 +376,7 @@ module "ilb-l7" {
source = "./fabric/modules/net-lb-app-int"
name = "ilb-test"
project_id = var.project_id
- region = "europe-west1"
+ region = var.region
backend_service_configs = {
default = {
backends = [{
@@ -388,8 +389,8 @@ module "ilb-l7" {
neg_configs = {
my-neg = {
psc = {
- region = "europe-west1"
- target_service = "europe-west1-cloudkms.googleapis.com"
+ region = var.region
+ target_service = "${var.region}-cloudkms.googleapis.com"
}
}
}
@@ -398,7 +399,7 @@ module "ilb-l7" {
subnetwork = var.subnet.self_link
}
}
-# tftest modules=1 resources=5
+# tftest modules=1 resources=5 e2e
```
#### Internet NEG creation
@@ -561,11 +562,11 @@ module "ilb-l7" {
source = "./fabric/modules/net-lb-app-int"
name = "ilb-test"
project_id = var.project_id
- region = "europe-west1"
+ region = var.region
backend_service_configs = {
default = {
backends = [{
- group = "projects/myprj/zones/europe-west1-a/instanceGroups/my-ig"
+ group = module.compute-vm-group-b.group.id
}]
}
}
@@ -575,14 +576,14 @@ module "ilb-l7" {
}
service_attachment = {
nat_subnets = [var.subnet_psc_1.self_link]
- automatic_connection = true
+ automatic_connection = false
consumer_accept_lists = {
# map of `project_id` => `connection_limit`
(var.project_id) = 10
}
}
}
-# tftest modules=1 resources=6
+# tftest modules=3 resources=10 fixtures=fixtures/compute-vm-group-bc.tf e2e
```
### Complex example
@@ -774,4 +775,8 @@ For deploying changes to load balancer configuration please refer to [net-lb-app
| [psc_neg_ids](outputs.tf#L68) | Autogenerated PSC network endpoint group ids. | |
| [regional_neg_ids](outputs.tf#L75) | Autogenerated regional network endpoint group ids. | |
| [service_attachment_id](outputs.tf#L82) | Id of the service attachment. | |
+
+## Fixtures
+
+- [compute-vm-group-bc.tf](../../tests/fixtures/compute-vm-group-bc.tf)
diff --git a/modules/net-lb-app-int/main.tf b/modules/net-lb-app-int/main.tf
index 3b63cfc418..6a3e10521f 100644
--- a/modules/net-lb-app-int/main.tf
+++ b/modules/net-lb-app-int/main.tf
@@ -108,16 +108,12 @@ resource "google_compute_region_target_http_proxy" "default" {
}
resource "google_compute_region_target_https_proxy" "default" {
- count = var.protocol == "HTTPS" ? 1 : 0
- project = var.project_id
- region = var.region
- name = var.name
- description = var.description
- ssl_certificates = (
- length(local.proxy_ssl_certificates) == 0
- ? null
- : local.proxy_ssl_certificates
- )
+ count = var.protocol == "HTTPS" ? 1 : 0
+ project = var.project_id
+ region = var.region
+ name = var.name
+ description = var.description
+ ssl_certificates = length(local.proxy_ssl_certificates) == 0 ? null : local.proxy_ssl_certificates
ssl_policy = var.https_proxy_config.ssl_policy
url_map = google_compute_region_url_map.default.id
certificate_manager_certificates = var.https_proxy_config.certificate_manager_certificates
@@ -219,6 +215,11 @@ resource "google_compute_region_network_endpoint_group" "psc" {
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
+ lifecycle {
+ # ignore until https://github.com/hashicorp/terraform-provider-google/issues/20576 is fixed
+ ignore_changes = [psc_data]
+ }
+
}
locals {
diff --git a/modules/net-lb-app-int/versions.tofu b/modules/net-lb-app-int/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-app-int/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-ext/versions.tofu b/modules/net-lb-ext/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-ext/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-int/versions.tofu b/modules/net-lb-int/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-int/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-lb-proxy-int/main.tf b/modules/net-lb-proxy-int/main.tf
index 1fdfd0f07b..096ae33ce3 100644
--- a/modules/net-lb-proxy-int/main.tf
+++ b/modules/net-lb-proxy-int/main.tf
@@ -121,6 +121,10 @@ resource "google_compute_region_network_endpoint_group" "psc" {
psc_target_service = each.value.psc.target_service
network = each.value.psc.network
subnetwork = each.value.psc.subnetwork
+ lifecycle {
+ # ignore until https://github.com/hashicorp/terraform-provider-google/issues/20576 is fixed
+ ignore_changes = [psc_data]
+ }
}
# Internet NEG
diff --git a/modules/net-lb-proxy-int/versions.tofu b/modules/net-lb-proxy-int/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-lb-proxy-int/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-swp/versions.tofu b/modules/net-swp/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-swp/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vlan-attachment/versions.tofu b/modules/net-vlan-attachment/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vlan-attachment/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpc-firewall/versions.tofu b/modules/net-vpc-firewall/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpc-firewall/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpc-peering/versions.tofu b/modules/net-vpc-peering/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpc-peering/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpc/psa.tf b/modules/net-vpc/psa.tf
index e32b0b56a9..9591938961 100644
--- a/modules/net-vpc/psa.tf
+++ b/modules/net-vpc/psa.tf
@@ -68,6 +68,7 @@ resource "google_service_networking_connection" "psa_connection" {
service = each.key
reserved_peering_ranges = formatlist("${each.value.key}%s", keys(each.value.ranges))
deletion_policy = each.value.deletion_policy
+ depends_on = [google_compute_global_address.psa_ranges]
}
resource "google_compute_network_peering_routes_config" "psa_routes" {
diff --git a/modules/net-vpc/versions.tofu b/modules/net-vpc/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpc/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpn-dynamic/versions.tofu b/modules/net-vpn-dynamic/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpn-dynamic/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpn-ha/versions.tofu b/modules/net-vpn-ha/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpn-ha/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/net-vpn-static/versions.tofu b/modules/net-vpn-static/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/net-vpn-static/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/organization/versions.tofu b/modules/organization/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/organization/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md
index 03d47043d0..7b705612c2 100644
--- a/modules/project-factory/README.md
+++ b/modules/project-factory/README.md
@@ -440,10 +440,10 @@ update_rules:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [factories_config](variables.tf#L100) | Path to folder with YAML resource description data files. | object({…})
| ✓ | |
-| [data_defaults](variables.tf#L17) | Optional default values used when corresponding project data from files are missing. | object({…})
| | {}
|
-| [data_merges](variables.tf#L54) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…})
| | {}
|
-| [data_overrides](variables.tf#L73) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…})
| | {}
|
+| [factories_config](variables.tf#L112) | Path to folder with YAML resource description data files. | object({…})
| ✓ | |
+| [data_defaults](variables.tf#L17) | Optional default values used when corresponding project data from files are missing. | object({…})
| | {}
|
+| [data_merges](variables.tf#L60) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…})
| | {}
|
+| [data_overrides](variables.tf#L79) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…})
| | {}
|
## Outputs
diff --git a/modules/project-factory/factory-projects.tf b/modules/project-factory/factory-projects.tf
index c29be097df..e33a5193a1 100644
--- a/modules/project-factory/factory-projects.tf
+++ b/modules/project-factory/factory-projects.tf
@@ -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.
@@ -58,6 +58,37 @@ locals {
try(v.contacts, null),
var.data_defaults.contacts
)
+ factories_config = {
+ custom_roles = try(
+ coalesce(
+ var.data_overrides.factories_config.custom_roles,
+ try(v.factories_config.custom_roles, null),
+ var.data_defaults.factories_config.custom_roles
+ ),
+ null
+ )
+ observability = try(
+ coalesce(
+ var.data_overrides.factories_config.observability,
+ try(v.factories_config.observability, null),
+ var.data_defaults.factories_config.observability
+ ),
+ null)
+ org_policies = try(
+ coalesce(
+ var.data_overrides.factories_config.org_policies,
+ try(v.factories_config.org_policies, null),
+ var.data_defaults.factories_config.org_policies
+ ),
+ null)
+ quotas = try(
+ coalesce(
+ var.data_overrides.factories_config.quotas,
+ try(v.factories_config.quotas, null),
+ var.data_defaults.factories_config.quotas
+ ),
+ null)
+ }
labels = coalesce(
try(v.labels, null),
var.data_defaults.labels
diff --git a/modules/project-factory/main.tf b/modules/project-factory/main.tf
index c806a75939..f350503f37 100644
--- a/modules/project-factory/main.tf
+++ b/modules/project-factory/main.tf
@@ -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.
@@ -41,6 +41,7 @@ module "projects" {
local.context.folder_ids, each.value.parent, each.value.parent
)
prefix = each.value.prefix
+ alerts = try(each.value.alerts, null)
auto_create_network = try(each.value.auto_create_network, false)
compute_metadata = try(each.value.compute_metadata, {})
# TODO: concat lists for each key
@@ -49,6 +50,15 @@ module "projects" {
)
default_service_account = try(each.value.default_service_account, "keep")
descriptive_name = try(each.value.descriptive_name, null)
+ factories_config = {
+ custom_roles = each.value.factories_config.custom_roles
+ observability = each.value.factories_config.observability
+ org_policies = each.value.factories_config.org_policies
+ quotas = each.value.factories_config.quotas
+ context = {
+ notification_channels = var.factories_config.context.notification_channels
+ }
+ }
iam = {
for k, v in lookup(each.value, "iam", {}) : k => [
for vv in v : try(
@@ -93,13 +103,16 @@ module "projects" {
each.value.labels, var.data_merges.labels
)
lien_reason = try(each.value.lien_reason, null)
+ log_scopes = try(each.value.log_scopes, null)
logging_data_access = try(each.value.logging_data_access, {})
logging_exclusions = try(each.value.logging_exclusions, {})
+ logging_metrics = try(each.value.logging_metrics, null)
logging_sinks = try(each.value.logging_sinks, {})
metric_scopes = distinct(concat(
each.value.metric_scopes, var.data_merges.metric_scopes
))
- org_policies = each.value.org_policies
+ notification_channels = try(each.value.notification_channels, null)
+ org_policies = each.value.org_policies
service_encryption_key_ids = merge(
each.value.service_encryption_key_ids,
var.data_merges.service_encryption_key_ids
diff --git a/modules/project-factory/variables.tf b/modules/project-factory/variables.tf
index bd364e1b47..bf21ae2772 100644
--- a/modules/project-factory/variables.tf
+++ b/modules/project-factory/variables.tf
@@ -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.
@@ -17,8 +17,14 @@
variable "data_defaults" {
description = "Optional default values used when corresponding project data from files are missing."
type = object({
- billing_account = optional(string)
- contacts = optional(map(list(string)), {})
+ billing_account = optional(string)
+ contacts = optional(map(list(string)), {})
+ factories_config = optional(object({
+ custom_roles = optional(string)
+ observability = optional(string)
+ org_policies = optional(string)
+ quotas = optional(string)
+ }), {})
labels = optional(map(string), {})
metric_scopes = optional(list(string), [])
parent = optional(string)
@@ -73,8 +79,14 @@ variable "data_merges" {
variable "data_overrides" {
description = "Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`."
type = object({
- billing_account = optional(string)
- contacts = optional(map(list(string)))
+ billing_account = optional(string)
+ contacts = optional(map(list(string)))
+ factories_config = optional(object({
+ custom_roles = optional(string)
+ observability = optional(string)
+ org_policies = optional(string)
+ quotas = optional(string)
+ }), {})
parent = optional(string)
prefix = optional(string)
service_encryption_key_ids = optional(map(list(string)))
@@ -100,8 +112,6 @@ variable "data_overrides" {
variable "factories_config" {
description = "Path to folder with YAML resource description data files."
type = object({
- folders_data_path = optional(string)
- projects_data_path = optional(string)
budgets = optional(object({
billing_account = string
budgets_data_path = string
@@ -110,11 +120,14 @@ variable "factories_config" {
}))
context = optional(object({
# TODO: add KMS keys
- folder_ids = optional(map(string), {})
- iam_principals = optional(map(string), {})
- tag_values = optional(map(string), {})
- vpc_host_projects = optional(map(string), {})
+ folder_ids = optional(map(string), {})
+ iam_principals = optional(map(string), {})
+ tag_values = optional(map(string), {})
+ vpc_host_projects = optional(map(string), {})
+ notification_channels = optional(map(string), {})
}), {})
+ folders_data_path = optional(string)
+ projects_data_path = optional(string)
})
nullable = false
}
diff --git a/modules/project/README.md b/modules/project/README.md
index 62bb6fea6d..2d8c9961ad 100644
--- a/modules/project/README.md
+++ b/modules/project/README.md
@@ -18,6 +18,7 @@ This module implements the creation and management of one GCP project including
- [Dry-Run Mode](#dry-run-mode)
- [Log Sinks](#log-sinks)
- [Data Access Logs](#data-access-logs)
+- [Log Scopes](#log-scopes)
- [Cloud KMS Encryption Keys](#cloud-kms-encryption-keys)
- [Tags](#tags)
- [Tag Bindings](#tag-bindings)
@@ -29,6 +30,8 @@ This module implements the creation and management of one GCP project including
- [VPC Service Controls](#vpc-service-controls)
- [Project Related Outputs](#project-related-outputs)
- [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it)
+- [Observability](#observability)
+- [Observability factory](#observability-factory)
- [Files](#files)
- [Variables](#variables)
- [Outputs](#outputs)
@@ -720,6 +723,46 @@ module "project" {
}
# tftest modules=1 resources=3 inventory=logging-data-access.yaml e2e
```
+## Log Scopes
+
+```hcl
+module "bucket" {
+ source = "./fabric/modules/logging-bucket"
+ parent_type = "project"
+ parent = "other-project"
+ id = "mybucket"
+ views = {
+ view1 = {
+ filter = "LOG_ID(\"stdout\")"
+ iam = {
+ "roles/logging.viewAccessor" = ["user:user@example.com"]
+ }
+ }
+ }
+}
+
+module "project" {
+ source = "./fabric/modules/project"
+ billing_account = var.billing_account_id
+ prefix = var.prefix
+ parent = var.folder_id
+ name = "logscope"
+ services = [
+ "logging.googleapis.com",
+ ]
+ log_scopes = {
+ scope = {
+ description = "My log scope"
+ resource_names = [
+ "project1",
+ "project2",
+ module.bucket.view_ids["_AllLogs"],
+ ]
+ }
+ }
+}
+# tftest modules=2 resources=6 inventory=log-scopes.yaml
+```
## Cloud KMS Encryption Keys
@@ -1360,16 +1403,164 @@ module "bucket" {
# tftest inventory=data.yaml e2e
```
+## Observability
+
+Alerting policies, log-based metrics, and notification channels are managed by the `alerts`, `logging_metrics`, and `notification_channels` variables, respectively.
+
+```hcl
+module "project" {
+ source = "./fabric/modules/project"
+ name = "project"
+ billing_account = var.billing_account_id
+ parent = var.folder_id
+ prefix = var.prefix
+ alerts = {
+ alert-1 = {
+ display_name = "alert-1"
+ combiner = "OR"
+ notification_channels = [
+ "my-channel",
+ "projects/other-project/notificationChannels/1234567890"
+ ]
+ conditions = [{
+ display_name = "test condition"
+ condition_threshold = {
+ filter = "metric.type=\"compute.googleapis.com/instance/disk/write_bytes_count\""
+ comparison = "COMPARISON_GT"
+ threshold_value = 100
+ duration = "60s"
+ aggregations = {
+ alignment_period = "60s"
+ per_series_aligner = "ALIGN_RATE"
+ }
+ }
+ }]
+ }
+ }
+ logging_metrics = {
+ metric-1 = {
+ name = "metric-1"
+ filter = "resource.type=\"gce_instance\""
+ description = "This is a metric"
+ metric_descriptor = {
+ metric_kind = "GAUGE"
+ value_type = "DOUBLE"
+ unit = "ms"
+ }
+ }
+ }
+ notification_channels = {
+ my-channel = {
+ display_name = "My Channel"
+ type = "email"
+ labels = {
+ email_address = "hello@example.com"
+ }
+ }
+ }
+}
+# tftest modules=1 resources=4
+```
+
+# Observability factory
+
+Observability variables are exposed through a factory enabled by setting `var.factories_config.observability`. YAML files configure observability resources using top-level keys: `alerts`, `logging_metrics`, and `notification_channels`, which correspond to the respective variables. All top-level keys are optional, and their structure mirrors their corresponding variable's structure.
+
+```hcl
+module "project" {
+ source = "./fabric/modules/project"
+ name = "project"
+ billing_account = var.billing_account_id
+ parent = var.folder_id
+ prefix = var.prefix
+ factories_config = {
+ observability = "data/observability"
+ context = {
+ notification_channels = {
+ common-channel = "projects/other-project/notificationChannels/1234567890"
+ }
+ }
+ }
+}
+# tftest modules=1 resources=5 files=observability
+```
+
+```yaml
+# tftest-file id=observability path=data/observability/observability.yaml schema=observability.schema.json
+logging_metrics:
+ factory-metric-1:
+ filter: "resource.type=gae_app AND severity>=ERROR"
+ metric_descriptor:
+ metric_kind: DELTA
+ value_type: INT64
+ disabled: true
+
+ factory-metric-2:
+ filter: resource.type=gae_app AND severity>=ERROR
+ metric_descriptor:
+ metric_kind: DELTA
+ value_type: DISTRIBUTION
+ unit: "1"
+ labels:
+ - key: mass
+ value_type: STRING
+ description: amount of matter
+ - key: sku
+ value_type: INT64
+ description: Identifying number for item
+ display_name: My metric
+ value_extractor: EXTRACT(jsonPayload.request)
+ label_extractors:
+ mass: EXTRACT(jsonPayload.request)
+ sku: EXTRACT(jsonPayload.id)
+ bucket_options:
+ linear_buckets:
+ num_finite_buckets: 3
+ width: 1
+ offset: 1
+
+notification_channels:
+ channel-1:
+ display_name: channel-1
+ type: email
+ labels:
+ email_address: hello2@example.com
+
+alerts:
+ alert-1:
+ display_name: My Alert Policy
+ combiner: OR
+ notification_channels:
+ - channel-1
+ - common-channel
+ conditions:
+ - display_name: test condition
+ condition_threshold:
+ filter: |
+ metric.type="compute.googleapis.com/instance/disk/write_bytes_count" AND resource.type="gce_instance"
+ duration: 60s
+ comparison: COMPARISON_GT
+ aggregations:
+ alignment_period: 60s
+ per_series_aligner: ALIGN_RATE
+ user_labels:
+ foo: bar
+```
+
+
## Files
| name | description | resources |
|---|---|---|
+| [alerts.tf](./alerts.tf) | None | google_monitoring_alert_policy
|
| [cmek.tf](./cmek.tf) | Service Agent IAM Bindings for CMEK | google_kms_crypto_key_iam_member
|
| [iam.tf](./iam.tf) | IAM bindings. | google_project_iam_binding
· google_project_iam_custom_role
· google_project_iam_member
|
-| [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member
· google_logging_project_exclusion
· google_logging_project_sink
· google_project_iam_audit_config
· google_project_iam_member
· google_pubsub_topic_iam_member
· google_storage_bucket_iam_member
|
+| [logging-metrics.tf](./logging-metrics.tf) | None | google_logging_metric
|
+| [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member
· google_logging_log_scope
· google_logging_project_exclusion
· google_logging_project_sink
· google_project_iam_audit_config
· google_project_iam_member
· google_pubsub_topic_iam_member
· google_storage_bucket_iam_member
|
| [main.tf](./main.tf) | Module-level locals and resources. | google_compute_project_metadata_item
· google_essential_contacts_contact
· google_monitoring_monitored_project
· google_project
· google_project_service
· google_resource_manager_lien
|
+| [notification-channels.tf](./notification-channels.tf) | None | google_monitoring_notification_channel
|
| [organization-policies.tf](./organization-policies.tf) | Project-level organization policies. | google_org_policy_policy
|
| [outputs.tf](./outputs.tf) | Module outputs. | |
| [quotas.tf](./quotas.tf) | None | google_cloud_quotas_quota_preference
|
@@ -1377,6 +1568,7 @@ module "bucket" {
| [shared-vpc.tf](./shared-vpc.tf) | Shared VPC project-level configuration. | google_compute_shared_vpc_host_project
· google_compute_shared_vpc_service_project
· google_compute_subnetwork_iam_member
· google_project_iam_member
|
| [tags.tf](./tags.tf) | None | google_tags_tag_binding
· google_tags_tag_key
· google_tags_tag_key_iam_binding
· google_tags_tag_key_iam_member
· google_tags_tag_value
· google_tags_tag_value_iam_binding
· google_tags_tag_value_iam_member
|
| [variables-iam.tf](./variables-iam.tf) | None | |
+| [variables-observability.tf](./variables-observability.tf) | None | |
| [variables-quotas.tf](./variables-quotas.tf) | None | |
| [variables-tags.tf](./variables-tags.tf) | None | |
| [variables.tf](./variables.tf) | Module variables. | |
@@ -1387,7 +1579,8 @@ module "bucket" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L165) | Project name and id suffix. | string
| ✓ | |
+| [name](variables.tf#L109) | Project name and id suffix. | string
| ✓ | |
+| [alerts](variables-observability.tf#L17) | Monitoring alerts. | map(object({…}))
| | {}
|
| [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | bool
| | false
|
| [billing_account](variables.tf#L23) | Billing account id. | string
| | null
|
| [compute_metadata](variables.tf#L29) | Optional compute metadata key/values. Only usable if compute API has been enabled. | map(string)
| | {}
|
@@ -1396,52 +1589,58 @@ module "bucket" {
| [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string
| | "keep"
|
| [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string
| | "DELETE"
|
| [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string
| | null
|
-| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…})
| | {}
|
+| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…})
| | {}
|
| [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…}))
| | {}
|
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
| [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string))
| | {}
|
-| [labels](variables.tf#L92) | Resource labels. | map(string)
| | {}
|
-| [lien_reason](variables.tf#L99) | If non-empty, creates a project lien with this description. | string
| | null
|
-| [logging_data_access](variables.tf#L105) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string)))
| | {}
|
-| [logging_exclusions](variables.tf#L120) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string)
| | {}
|
-| [logging_sinks](variables.tf#L127) | Logging sinks to create for this project. | map(object({…}))
| | {}
|
-| [metric_scopes](variables.tf#L158) | List of projects that will act as metric scopes for this project. | list(string)
| | []
|
+| [labels](variables.tf#L96) | Resource labels. | map(string)
| | {}
|
+| [lien_reason](variables.tf#L103) | If non-empty, creates a project lien with this description. | string
| | null
|
+| [log_scopes](variables-observability.tf#L117) | Log scopes under this project. | map(object({…}))
| | {}
|
+| [logging_data_access](variables-observability.tf#L127) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | map(map(list(string)))
| | {}
|
+| [logging_exclusions](variables-observability.tf#L142) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string)
| | {}
|
+| [logging_metrics](variables-observability.tf#L149) | Log-based metrics. | map(object({…}))
| | {}
|
+| [logging_sinks](variables-observability.tf#L189) | Logging sinks to create for this project. | map(object({…}))
| | {}
|
+| [metric_scopes](variables-observability.tf#L220) | List of projects that will act as metric scopes for this project. | list(string)
| | []
|
| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…}))
| | {}
|
-| [org_policies](variables.tf#L170) | Organization policies applied to this project keyed by policy name. | map(object({…}))
| | {}
|
-| [parent](variables.tf#L197) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string
| | null
|
-| [prefix](variables.tf#L207) | Optional prefix used to generate project id and name. | string
| | null
|
-| [project_create](variables.tf#L217) | Create project. When set to false, uses a data source to reference existing project. | bool
| | true
|
+| [notification_channels](variables-observability.tf#L227) | Monitoring notification channels. | map(object({…}))
| | {}
|
+| [org_policies](variables.tf#L114) | Organization policies applied to this project keyed by policy name. | map(object({…}))
| | {}
|
+| [parent](variables.tf#L141) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string
| | null
|
+| [prefix](variables.tf#L151) | Optional prefix used to generate project id and name. | string
| | null
|
+| [project_create](variables.tf#L161) | Create project. When set to false, uses a data source to reference existing project. | bool
| | true
|
| [quotas](variables-quotas.tf#L17) | Service quota configuration. | map(object({…}))
| | {}
|
-| [service_agents_config](variables.tf#L223) | Automatic service agent configuration options. | object({…})
| | {}
|
-| [service_config](variables.tf#L234) | Configure service API activation. | object({…})
| | {…}
|
-| [service_encryption_key_ids](variables.tf#L246) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string))
| | {}
|
-| [services](variables.tf#L253) | Service APIs to enable. | list(string)
| | []
|
-| [shared_vpc_host_config](variables.tf#L259) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…})
| | null
|
-| [shared_vpc_service_config](variables.tf#L268) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…})
| | {…}
|
-| [skip_delete](variables.tf#L296) | Deprecated. Use deletion_policy. | bool
| | null
|
+| [service_agents_config](variables.tf#L167) | Automatic service agent configuration options. | object({…})
| | {}
|
+| [service_config](variables.tf#L178) | Configure service API activation. | object({…})
| | {…}
|
+| [service_encryption_key_ids](variables.tf#L190) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string))
| | {}
|
+| [services](variables.tf#L197) | Service APIs to enable. | list(string)
| | []
|
+| [shared_vpc_host_config](variables.tf#L203) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…})
| | null
|
+| [shared_vpc_service_config](variables.tf#L212) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…})
| | {…}
|
+| [skip_delete](variables.tf#L240) | Deprecated. Use deletion_policy. | bool
| | null
|
| [tag_bindings](variables-tags.tf#L81) | Tag bindings for this project, in key => tag value id format. | map(string)
| | null
|
| [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…}))
| | {}
|
-| [vpc_sc](variables.tf#L308) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…})
| | null
|
+| [vpc_sc](variables.tf#L252) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…})
| | null
|
## Outputs
| name | description | sensitive |
|---|---|:---:|
-| [custom_role_id](outputs.tf#L17) | Map of custom role IDs created in the project. | |
-| [custom_roles](outputs.tf#L27) | Map of custom roles resources created in the project. | |
-| [default_service_accounts](outputs.tf#L33) | Emails of the default service accounts for this project. | |
-| [id](outputs.tf#L41) | Project id. | |
-| [name](outputs.tf#L59) | Project name. | |
-| [network_tag_keys](outputs.tf#L71) | Tag key resources. | |
-| [network_tag_values](outputs.tf#L80) | Tag value resources. | |
-| [number](outputs.tf#L88) | Project number. | |
-| [project_id](outputs.tf#L106) | Project id. | |
-| [quota_configs](outputs.tf#L124) | Quota configurations. | |
-| [quotas](outputs.tf#L135) | Quota resources. | |
-| [service_agents](outputs.tf#L140) | List of all (active) service agents for this project. | |
-| [services](outputs.tf#L149) | Service APIs to enabled in the project. | |
-| [sink_writer_identities](outputs.tf#L158) | Writer identities created for each sink. | |
-| [tag_keys](outputs.tf#L165) | Tag key resources. | |
-| [tag_values](outputs.tf#L174) | Tag value resources. | |
+| [alert_ids](outputs.tf#L17) | Monitoring alert IDs. | |
+| [custom_role_id](outputs.tf#L25) | Map of custom role IDs created in the project. | |
+| [custom_roles](outputs.tf#L35) | Map of custom roles resources created in the project. | |
+| [default_service_accounts](outputs.tf#L40) | Emails of the default service accounts for this project. | |
+| [id](outputs.tf#L48) | Project id. | |
+| [name](outputs.tf#L66) | Project name. | |
+| [network_tag_keys](outputs.tf#L78) | Tag key resources. | |
+| [network_tag_values](outputs.tf#L87) | Tag value resources. | |
+| [notification_channel_names](outputs.tf#L95) | Notification channel names. | |
+| [notification_channels](outputs.tf#L103) | Full notification channel objects. | |
+| [number](outputs.tf#L108) | Project number. | |
+| [project_id](outputs.tf#L126) | Project id. | |
+| [quota_configs](outputs.tf#L144) | Quota configurations. | |
+| [quotas](outputs.tf#L155) | Quota resources. | |
+| [service_agents](outputs.tf#L160) | List of all (active) service agents for this project. | |
+| [services](outputs.tf#L169) | Service APIs to enabled in the project. | |
+| [sink_writer_identities](outputs.tf#L178) | Writer identities created for each sink. | |
+| [tag_keys](outputs.tf#L185) | Tag key resources. | |
+| [tag_values](outputs.tf#L194) | Tag value resources. | |
diff --git a/modules/project/alerts.tf b/modules/project/alerts.tf
new file mode 100644
index 0000000000..625cb189e7
--- /dev/null
+++ b/modules/project/alerts.tf
@@ -0,0 +1,285 @@
+/**
+ * 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.
+ */
+
+locals {
+ _alerts_factory_data_raw = merge([
+ for k in local.observability_factory_data_raw :
+ lookup(k, "alerts", {})
+ ]...)
+ _alerts_factory_data = {
+ for k, v in local._alerts_factory_data_raw :
+ k => {
+ combiner = v.combiner
+ display_name = try(v.display_name, null)
+ enabled = try(v.enabled, null)
+ notification_channels = try(v.notification_channels, [])
+ severity = try(v.severity, null)
+ user_labels = try(v.user_labels, null)
+ alert_strategy = !can(v.alert_strategy) ? null : {
+ auto_close = try(v.alert_strategy.auto_close, null)
+ notification_prompts = try(v.alert_strategy.notification_prompts, null)
+ notification_rate_limit = !can(v.alert_strategy.notification_rate_limit) ? null : {
+ period = try(v.alert_strategy.notification_rate_limit.period, null)
+ }
+ notification_channel_strategy = !can(v.alert_strategy.notification_channel_strategy) ? null : {
+ notification_channel_names = try(v.alert_strategy.notification_channel_strategy.notification_channel_names, null)
+ renotify_interval = try(v.alert_strategy.notification_channel_strategy.renotify_interval, null)
+ }
+ }
+ conditions = !can(v.conditions) ? null : [
+ for c in v.conditions : {
+ display_name = c.display_name
+ condition_absent = !can(c.condition_absent) ? null : {
+ duration = c.condition_absent.duration
+ filter = try(c.condition_absent.filter, null)
+ aggregations = !can(c.condition_absent.aggregations) ? null : {
+ per_series_aligner = try(c.condition_absent.aggregations.per_series_aligner, null)
+ group_by_fields = try(c.condition_absent.aggregations.group_by_fields, null)
+ cross_series_reducer = try(c.condition_absent.aggregations.cross_series_reducer, null)
+ alignment_period = try(c.condition_absent.aggregations.alignment_period, null)
+ }
+ trigger = !can(c.condition_absent.trigger) ? null : {
+ count = try(c.condition_absent.trigger.count, null)
+ percent = try(c.condition_absent.trigger.percent, null)
+ }
+ }
+ condition_matched_log = !can(c.condition_matched_log) ? null : {
+ filter = c.condition_matched_log.filter
+ label_extractors = try(c.condition_matched_log.label_extractors, null)
+ }
+ condition_monitoring_query_language = !can(c.condition_monitoring_query_language) ? null : {
+ duration = c.condition_monitoring_query_language.duration
+ query = c.condition_monitoring_query_language.query
+ evaluation_missing_data = try(c.condition_monitoring_query_language.evaluation_missing_data, null)
+ trigger = !can(c.condition_monitoring_query_language.trigger) ? null : {
+ count = try(c.condition_monitoring_query_language.trigger.count, null)
+ percent = try(c.condition_monitoring_query_language.trigger.percent, null)
+ }
+ }
+ condition_prometheus_query_language = !can(c.condition_prometheus_query_language) ? null : {
+ query = c.condition_prometheus_query_language.query
+ alert_rule = try(c.condition_prometheus_query_language.alert_rule, null)
+ disable_metric_validation = try(c.condition_prometheus_query_language.disable_metric_validation, null)
+ duration = try(c.condition_prometheus_query_language.duration, null)
+ evaluation_interval = try(c.condition_prometheus_query_language.evaluation_interval, null)
+ labels = try(c.condition_prometheus_query_language.labels, null)
+ rule_group = try(c.condition_prometheus_query_language.rule_group, null)
+ }
+ condition_threshold = !can(c.condition_threshold) ? null : {
+ comparison = c.condition_threshold.comparison
+ duration = c.condition_threshold.duration
+ denominator_filter = try(c.condition_threshold.denominator_filter, null)
+
+
+ evaluation_missing_data = try(c.condition_threshold.evaluation_missing_data, null)
+ filter = try(c.condition_threshold.filter, null)
+ threshold_value = try(c.condition_threshold.threshold_value, null)
+ aggregations = !can(c.condition_threshold.aggregations) ? null : {
+ per_series_aligner = try(c.condition_threshold.aggregations.per_series_aligner, null)
+ group_by_fields = try(c.condition_threshold.aggregations.group_by_fields, null)
+ cross_series_reducer = try(c.condition_threshold.aggregations.cross_series_reducer, null)
+ alignment_period = try(c.condition_threshold.aggregations.alignment_period, null)
+ }
+ denominator_aggregations = !can(c.condition_threshold.denominator_aggregations) ? null : {
+ per_series_aligner = try(c.condition_threshold.denominator_aggregations.per_series_aligner, null)
+ group_by_fields = try(c.condition_threshold.denominator_aggregations.group_by_fields, null)
+ cross_series_reducer = try(c.condition_threshold.denominator_aggregations.cross_series_reducer, null)
+ alignment_period = try(c.condition_threshold.denominator_aggregations.alignment_period, null)
+ }
+ forecast_options = !can(c.condition_threshold.forecast_options) ? null : {
+ forecast_horizon = c.condition_threshold.forecast_options.forecast_horizon
+ }
+ trigger = !can(c.condition_threshold.trigger) ? null : {
+ count = try(c.condition_threshold.trigger.count, null)
+ percent = try(c.condition_threshold.trigger.percent, null)
+ }
+ }
+ }
+ ]
+ documentation = !can(v.documentation) ? null : {
+ content = try(v.documentation.content, null)
+ mime_type = try(v.documentation.mime_type, null)
+ subject = try(v.documentation.subject, null)
+ links = !can(v.documentation.links) ? null : [
+ for l in v.documentation.link : {
+ display_name = try(l.display_name, null)
+ url = try(l.url, null)
+ }]
+ }
+ }
+ }
+ alerts = merge(local._alerts_factory_data, var.alerts)
+}
+
+resource "google_monitoring_alert_policy" "alerts" {
+ for_each = local.alerts
+ project = local.project.project_id
+
+ combiner = each.value.combiner
+ display_name = each.value.display_name
+ enabled = each.value.enabled
+ notification_channels = [
+ for x in each.value.notification_channels :
+ try(
+ # first try to get a channel created by this module
+ google_monitoring_notification_channel.channels[x].name,
+ # otherwise check the context
+ var.factories_config.context.notification_channels[x],
+ # if nothing else, use the provided channel as is
+ x
+ )
+ ]
+ severity = each.value.severity
+ user_labels = each.value.user_labels
+
+ dynamic "alert_strategy" {
+ for_each = each.value.alert_strategy[*]
+ content {
+ auto_close = alert_strategy.value.auto_close
+ notification_prompts = alert_strategy.value.notification_prompts
+ dynamic "notification_channel_strategy" {
+ for_each = alert_strategy.value.notification_channel_strategy[*]
+ content {
+ notification_channel_names = notification_channel_strategy.value.notification_channel_names
+ renotify_interval = notification_channel_strategy.value.renotify_interval
+ }
+ }
+ dynamic "notification_rate_limit" {
+ for_each = alert_strategy.value.notification_rate_limit[*]
+ content {
+ period = notification_rate_limit.value.period
+ }
+ }
+ }
+ }
+ dynamic "conditions" {
+ for_each = each.value.conditions
+ content {
+ display_name = conditions.value.display_name
+ dynamic "condition_absent" {
+ for_each = conditions.value.condition_absent[*]
+ content {
+ duration = condition_absent.value.duration
+ filter = condition_absent.value.filter
+ dynamic "aggregations" {
+ for_each = condition_absent.value.aggregations[*]
+ content {
+ alignment_period = aggregations.value.alignment_period
+ cross_series_reducer = aggregations.value.cross_series_reducer
+ group_by_fields = aggregations.value.group_by_fields
+ per_series_aligner = aggregations.value.per_series_aligner
+ }
+ }
+ dynamic "trigger" {
+ for_each = condition_absent.value.trigger[*]
+ content {
+ count = trigger.value.count
+ percent = trigger.value.percent
+ }
+ }
+ }
+ }
+ dynamic "condition_matched_log" {
+ for_each = conditions.value.condition_matched_log[*]
+ content {
+ filter = condition_matched_log.value.filter
+ label_extractors = condition_matched_log.value.label_extractors
+ }
+ }
+ dynamic "condition_monitoring_query_language" {
+ for_each = conditions.value.condition_monitoring_query_language[*]
+ content {
+ duration = condition_monitoring_query_language.value.duration
+ query = condition_monitoring_query_language.value.query
+ evaluation_missing_data = condition_monitoring_query_language.value.evaluation_missing_data
+ trigger {
+ count = condition_monitoring_query_language.value.trigger.count
+ percent = condition_monitoring_query_language.value.trigger.percent
+ }
+ }
+ }
+
+ dynamic "condition_prometheus_query_language" {
+ for_each = conditions.value.condition_prometheus_query_language[*]
+ content {
+ query = condition_prometheus_query_language.value.query
+ disable_metric_validation = condition_prometheus_query_language.value.disable_metric_validation
+ duration = condition_prometheus_query_language.value.duration
+ evaluation_interval = condition_prometheus_query_language.value.evaluation_interval
+ labels = condition_prometheus_query_language.value.labels
+ rule_group = condition_prometheus_query_language.value.rule_group
+ alert_rule = condition_prometheus_query_language.value.alert_rule
+ }
+ }
+ dynamic "condition_threshold" {
+ for_each = conditions.value.condition_threshold[*]
+ content {
+ comparison = condition_threshold.value.comparison
+ duration = condition_threshold.value.duration
+ denominator_filter = condition_threshold.value.denominator_filter
+ evaluation_missing_data = condition_threshold.value.evaluation_missing_data
+ filter = condition_threshold.value.filter
+ threshold_value = condition_threshold.value.threshold_value
+ dynamic "aggregations" {
+ for_each = condition_threshold.value.aggregations[*]
+ content {
+ alignment_period = aggregations.value.alignment_period
+ cross_series_reducer = aggregations.value.cross_series_reducer
+ group_by_fields = aggregations.value.group_by_fields
+ per_series_aligner = aggregations.value.per_series_aligner
+ }
+ }
+ dynamic "denominator_aggregations" {
+ for_each = condition_threshold.value.denominator_aggregations[*]
+ content {
+ alignment_period = denominator_aggregations.value.alignment_period
+ group_by_fields = denominator_aggregations.value.group_by_fields
+ per_series_aligner = denominator_aggregations.value.per_series_aligner
+ }
+ }
+ dynamic "forecast_options" {
+ for_each = condition_threshold.value.forecast_options[*]
+ content {
+ forecast_horizon = forecast_options.value.forecast_horizon
+ }
+ }
+ dynamic "trigger" {
+ for_each = condition_threshold.value.trigger[*]
+ content {
+ count = trigger.value.count
+ percent = trigger.value.percent
+ }
+ }
+ }
+ }
+ }
+ }
+ dynamic "documentation" {
+ for_each = each.value.documentation[*]
+ content {
+ content = documentation.value.content
+ mime_type = documentation.value.mime_type
+ subject = documentation.value.subject
+ dynamic "links" {
+ for_each = documentation.value.links[*]
+ content {
+ display_name = links.value.display_name
+ url = links.value.url
+ }
+ }
+ }
+ }
+}
diff --git a/modules/project/logging-metrics.tf b/modules/project/logging-metrics.tf
new file mode 100644
index 0000000000..f465586908
--- /dev/null
+++ b/modules/project/logging-metrics.tf
@@ -0,0 +1,120 @@
+/**
+ * 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.
+ */
+
+locals {
+ _logging_metrics_factory_data_raw = merge([
+ for k in local.observability_factory_data_raw :
+ lookup(k, "logging_metrics", {})
+ ]...)
+ _logging_metrics_factory_data = {
+ for k, v in local._logging_metrics_factory_data_raw :
+ k => {
+ filter = v.filter
+ bucket_name = try(v.bucket_name, null)
+ description = try(v.description, null)
+ disabled = try(v.disabled, null)
+ label_extractors = try(v.label_extractors, null)
+ value_extractor = try(v.value_extractor, null)
+ bucket_options = !can(v.bucket_options) ? null : {
+ explicit_buckets = !can(v.bucket_options.explicit_buckets) ? null : {
+ bounds = v.bucket_options.explicit_buckets.bounds
+ }
+ exponential_buckets = !can(v.bucket_options.exponential_buckets) ? null : {
+ num_finite_buckets = v.bucket_options.exponential_buckets.num_finite_buckets
+ growth_factor = v.bucket_options.exponential_buckets.growth_factor
+ scale = v.bucket_options.exponential_buckets.scale
+ }
+ linear_buckets = !can(v.bucket_options.linear_buckets) ? null : {
+ num_finite_buckets = v.bucket_options.linear_buckets.num_finite_buckets
+ width = v.bucket_options.linear_buckets.width
+ offset = v.bucket_options.linear_buckets.offset
+ }
+ }
+ metric_descriptor = !can(v.metric_descriptor) ? null : {
+ metric_kind = v.metric_descriptor.metric_kind
+ value_type = v.metric_descriptor.value_type
+ display_name = try(v.metric_descriptor.display_name, null)
+ unit = try(v.metric_descriptor.unit, null)
+ labels = !can(v.metric_descriptor.labels) ? [] : [
+ for vv in v.metric_descriptor.labels :
+ {
+ key = vv.key
+ description = try(vv.description, null)
+ value_type = try(vv.value_type, null)
+ }
+ ]
+ }
+ }
+ }
+ metrics = merge(local._logging_metrics_factory_data, var.logging_metrics)
+}
+
+resource "google_logging_metric" "metrics" {
+ for_each = local.metrics
+ project = local.project.project_id
+ name = each.key
+ filter = each.value.filter
+ description = each.value.description
+ disabled = each.value.disabled
+ bucket_name = each.value.bucket_name
+ value_extractor = each.value.value_extractor
+ label_extractors = each.value.label_extractors
+
+ dynamic "bucket_options" {
+ for_each = each.value.bucket_options[*]
+ content {
+ dynamic "explicit_buckets" {
+ for_each = bucket_options.value.explicit_buckets[*]
+ content {
+ bounds = explicit_buckets.value.bounds
+ }
+ }
+ dynamic "exponential_buckets" {
+ for_each = bucket_options.value.exponential_buckets[*]
+ content {
+ num_finite_buckets = exponential_buckets.value.num_finite_buckets
+ growth_factor = exponential_buckets.value.growth_factor
+ scale = exponential_buckets.value.scale
+ }
+ }
+ dynamic "linear_buckets" {
+ for_each = bucket_options.value.linear_buckets[*]
+ content {
+ num_finite_buckets = linear_buckets.value.num_finite_buckets
+ width = linear_buckets.value.width
+ offset = linear_buckets.value.offset
+ }
+ }
+ }
+ }
+ dynamic "metric_descriptor" {
+ for_each = each.value.metric_descriptor[*]
+ content {
+ metric_kind = metric_descriptor.value.metric_kind
+ value_type = metric_descriptor.value.value_type
+ display_name = metric_descriptor.value.display_name
+ unit = metric_descriptor.value.unit
+ dynamic "labels" {
+ for_each = metric_descriptor.value.labels
+ content {
+ key = labels.value.key
+ description = labels.value.description
+ value_type = labels.value.value_type
+ }
+ }
+ }
+ }
+}
diff --git a/modules/project/logging.tf b/modules/project/logging.tf
index b4f808891a..fba9634fdd 100644
--- a/modules/project/logging.tf
+++ b/modules/project/logging.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,17 @@ locals {
name => sink if sink.iam && sink.type == type
}
}
+
+ log_scopes = {
+ for k, v in var.log_scopes :
+ k => merge(v, {
+ # process all resource_names to allow bare project ids
+ resource_names = [
+ for r in v.resource_names :
+ startswith(r, "projects/") ? r : "projects/${r}"
+ ]
+ })
+ }
}
resource "google_project_iam_audit_config" "default" {
@@ -132,3 +143,12 @@ resource "google_logging_project_exclusion" "logging-exclusion" {
description = "${each.key} (Terraform-managed)."
filter = each.value
}
+
+resource "google_logging_log_scope" "log-scopes" {
+ for_each = local.log_scopes
+ parent = "projects/${local.project.project_id}"
+ location = "global"
+ name = each.key
+ resource_names = each.value.resource_names
+ description = each.value.description
+}
diff --git a/modules/project/main.tf b/modules/project/main.tf
index a90361d1ef..25d29fb0d6 100644
--- a/modules/project/main.tf
+++ b/modules/project/main.tf
@@ -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.
@@ -18,6 +18,10 @@ locals {
descriptive_name = (
var.descriptive_name != null ? var.descriptive_name : "${local.prefix}${var.name}"
)
+ observability_factory_data_raw = [
+ for f in try(fileset(var.factories_config.observability, "*.yaml"), []) :
+ yamldecode(file("${var.factories_config.observability}/${f}"))
+ ]
parent_type = var.parent == null ? null : split("/", var.parent)[0]
parent_id = var.parent == null ? null : split("/", var.parent)[1]
prefix = var.prefix == null ? "" : "${var.prefix}-"
diff --git a/modules/project/notification-channels.tf b/modules/project/notification-channels.tf
new file mode 100644
index 0000000000..45d1678c63
--- /dev/null
+++ b/modules/project/notification-channels.tf
@@ -0,0 +1,60 @@
+/**
+ * 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.
+ */
+
+locals {
+ _channels_factory_data_raw = merge([
+ for k in local.observability_factory_data_raw :
+ lookup(k, "notification_channels", {})
+ ]...)
+ _channels_factory_data = {
+ for k, v in local._channels_factory_data_raw :
+ k => {
+ type = v.type
+ description = try(v.description, null)
+ display_name = try(v.display_name, null)
+ enabled = try(v.enabled, null)
+ labels = try(v.labels, null)
+ user_labels = try(v.user_labels, null)
+ sensitive_labels = !can(v.sensitive_labels) ? null : {
+ auth_token = try(v.sensitive_labels.auth_token, null)
+ password = try(v.sensitive_labels.password, null)
+ service_key = try(v.sensitive_labels.service_key, null)
+ }
+ }
+ }
+ channels = merge(local._channels_factory_data, var.notification_channels)
+}
+
+resource "google_monitoring_notification_channel" "channels" {
+ for_each = local.channels
+ project = local.project.project_id
+ type = each.value.type
+ description = each.value.description
+ display_name = each.value.display_name
+ enabled = each.value.enabled
+ labels = each.value.labels
+ user_labels = each.value.user_labels
+ dynamic "sensitive_labels" {
+ for_each = each.value.sensitive_labels[*]
+ content {
+ auth_token = sensitive_labels.value.auth_token
+ password = sensitive_labels.value.password
+ service_key = sensitive_labels.value.service_key
+ }
+ }
+}
+
+
diff --git a/modules/project/outputs.tf b/modules/project/outputs.tf
index 8a296ede51..60134a4468 100644
--- a/modules/project/outputs.tf
+++ b/modules/project/outputs.tf
@@ -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.
@@ -14,6 +14,14 @@
* limitations under the License.
*/
+output "alert_ids" {
+ description = "Monitoring alert IDs."
+ value = {
+ for k, v in google_monitoring_alert_policy.alerts :
+ k => v.id
+ }
+}
+
output "custom_role_id" {
description = "Map of custom role IDs created in the project."
value = {
@@ -29,7 +37,6 @@ output "custom_roles" {
value = google_project_iam_custom_role.roles
}
-
output "default_service_accounts" {
description = "Emails of the default service accounts for this project."
value = {
@@ -85,6 +92,19 @@ output "network_tag_values" {
}
}
+output "notification_channel_names" {
+ description = "Notification channel names."
+ value = {
+ for k, v in google_monitoring_notification_channel.channels :
+ k => v.name
+ }
+}
+
+output "notification_channels" {
+ description = "Full notification channel objects."
+ value = google_monitoring_notification_channel.channels
+}
+
output "number" {
description = "Project number."
value = local.project.number
diff --git a/modules/project/schemas/observability.schema.json b/modules/project/schemas/observability.schema.json
new file mode 100644
index 0000000000..cf3eb2f0a7
--- /dev/null
+++ b/modules/project/schemas/observability.schema.json
@@ -0,0 +1,514 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Observability Schema",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "alerts": {
+ "$ref": "#/$defs/alerts"
+ },
+ "logging_metrics": {
+ "$ref": "#/$defs/logging_metrics"
+ },
+ "notification_channels": {
+ "$ref": "#/$defs/notification_channels"
+ }
+ },
+ "$defs": {
+ "alerts": {
+ "title": "Alerts",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z0-9-]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "combiner": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "notification_channels": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "severity": {
+ "type": "string"
+ },
+ "user_labels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "alert_strategy": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "auto_close": {
+ "type": "string"
+ },
+ "notification_prompts": {
+ "type": "string"
+ },
+ "notification_rate_limit": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "period": {
+ "type": "string"
+ }
+ }
+ },
+ "notification_channel_strategy": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "notification_channel_names": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "renotify_interval": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "conditions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/$defs/condition"
+ }
+ },
+ "documentation": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "content": {
+ "type": "string"
+ },
+ "mime_type": {
+ "type": "string"
+ },
+ "subject": {
+ "type": "string"
+ },
+ "links": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "display_name": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "required": [
+ "combiner"
+ ]
+ }
+ }
+ },
+ "logging_metrics": {
+ "title": "Logging Metrics",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z0-9-]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "filter": {
+ "type": "string"
+ },
+ "bucket_name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "disabled": {
+ "type": "boolean"
+ },
+ "label_extractors": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "value_extractor": {
+ "type": "string"
+ },
+ "bucket_options": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "explicit_buckets": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bounds": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ "exponential_buckets": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "num_finite_buckets": {
+ "type": "number"
+ },
+ "growth_factor": {
+ "type": "number"
+ },
+ "scale": {
+ "type": "number"
+ }
+ }
+ },
+ "linear_buckets": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "num_finite_buckets": {
+ "type": "number"
+ },
+ "width": {
+ "type": "number"
+ },
+ "offset": {
+ "type": "number"
+ }
+ }
+ }
+ }
+ },
+ "metric_descriptor": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "metric_kind": {
+ "type": "string"
+ },
+ "value_type": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "unit": {
+ "type": "string"
+ },
+ "labels": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "key": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "value_type": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "key"
+ ]
+ }
+ }
+ },
+ "required": [
+ "metric_kind",
+ "value_type"
+ ]
+ }
+ },
+ "required": [
+ "filter"
+ ]
+ }
+ }
+ },
+ "notification_channels": {
+ "title": "Notification Channels",
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-zA-Z0-9-]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "display_name": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "labels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "user_labels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "sensitive_labels": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "auth_token": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "service_key": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ }
+ },
+ "condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "display_name": {
+ "type": "string"
+ },
+ "condition_absent": {
+ "$ref": "#/$defs/absent_condition"
+ },
+ "condition_matched_log": {
+ "$ref": "#/$defs/matched_log_condition"
+ },
+ "condition_monitoring_query_language": {
+ "$ref": "#/$defs/monitoring_query_condition"
+ },
+ "condition_prometheus_query_language": {
+ "$ref": "#/$defs/prometheus_query_condition"
+ },
+ "condition_threshold": {
+ "$ref": "#/$defs/threshold_condition"
+ }
+ },
+ "required": [
+ "display_name"
+ ]
+ },
+ "absent_condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "duration": {
+ "type": "string"
+ },
+ "filter": {
+ "type": "string"
+ },
+ "aggregations": {
+ "$ref": "#/$defs/aggregations"
+ },
+ "trigger": {
+ "$ref": "#/$defs/trigger"
+ }
+ },
+ "required": [
+ "duration"
+ ]
+ },
+ "matched_log_condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "filter": {
+ "type": "string"
+ },
+ "label_extractors": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "filter"
+ ]
+ },
+ "monitoring_query_condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "duration": {
+ "type": "string"
+ },
+ "query": {
+ "type": "string"
+ },
+ "evaluation_missing_data": {
+ "type": "string"
+ },
+ "trigger": {
+ "$ref": "#/$defs/trigger"
+ }
+ },
+ "required": [
+ "duration",
+ "query"
+ ]
+ },
+ "prometheus_query_condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "query": {
+ "type": "string"
+ },
+ "alert_rule": {
+ "type": "string"
+ },
+ "disable_metric_validation": {
+ "type": "boolean"
+ },
+ "duration": {
+ "type": "string"
+ },
+ "evaluation_interval": {
+ "type": "string"
+ },
+ "labels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "rule_group": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "query"
+ ]
+ },
+ "threshold_condition": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "comparison": {
+ "type": "string"
+ },
+ "duration": {
+ "type": "string"
+ },
+ "denominator_filter": {
+ "type": "string"
+ },
+ "evaluation_missing_data": {
+ "type": "string"
+ },
+ "filter": {
+ "type": "string"
+ },
+ "threshold_value": {
+ "type": "number"
+ },
+ "aggregations": {
+ "$ref": "#/$defs/aggregations"
+ },
+ "denominator_aggregations": {
+ "$ref": "#/$defs/aggregations"
+ },
+ "forecast_options": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "forecast_horizon": {
+ "type": "string"
+ }
+ }
+ },
+ "trigger": {
+ "$ref": "#/$defs/trigger"
+ }
+ },
+ "required": [
+ "comparison",
+ "duration"
+ ]
+ },
+ "aggregations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "per_series_aligner": {
+ "type": "string"
+ },
+ "group_by_fields": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "cross_series_reducer": {
+ "type": "string"
+ },
+ "alignment_period": {
+ "type": "string"
+ }
+ }
+ },
+ "trigger": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "count": {
+ "type": "number"
+ },
+ "percent": {
+ "type": "number"
+ }
+ }
+ }
+ }
+}
diff --git a/modules/project/service-agents.yaml b/modules/project/service-agents.yaml
index 8590aafb93..e7815218cf 100644
--- a/modules/project/service-agents.yaml
+++ b/modules/project/service-agents.yaml
@@ -787,6 +787,13 @@
role: null
is_primary: false
aliases: []
+- name: gcp-ri-contactcenterinsights
+ display_name: Contact Center Insights Resource Identity (prod)
+ api: contactcenterinsights.googleapis.com
+ identity: service-%s@gcp-ri-contactcenterinsights.iam.gserviceaccount.com
+ role: null
+ is_primary: false
+ aliases: []
- name: container-analysis
display_name: Container Analysis Service Agent
api: containeranalysis.googleapis.com
@@ -969,6 +976,13 @@
role: roles/firebaseapphosting.serviceAgent
is_primary: true
aliases: []
+- name: crashlytics
+ display_name: Firebase Crashlytics Service Agent
+ api: firebasecrashlytics.googleapis.com
+ identity: service-%s@gcp-sa-crashlytics.iam.gserviceaccount.com
+ role: roles/firebasecrashlytics.serviceAgent
+ is_primary: true
+ aliases: []
- name: firebasedataconnect
display_name: Firebase Data Connect Service Account
api: firebasedataconnect.googleapis.com
@@ -1173,13 +1187,6 @@
role: null
is_primary: false
aliases: []
-- name: chronicle-spanner
- display_name: Internal Chronicle Spanner Service Account
- api: chronicle.googleapis.com
- identity: service-%s@gcp-sa-chronicle-spanner.iam.gserviceaccount.com
- role: null
- is_primary: false
- aliases: []
- name: fs-spanner
display_name: Internal Cloud Firestore Spanner Service Agent
api: firestore.googleapis.com
@@ -1351,6 +1358,13 @@
role: null
is_primary: true
aliases: []
+- name: progrollout
+ display_name: Progressive Rollout Service Agent
+ api: progressiverollout.googleapis.com
+ identity: service-%s@gcp-sa-progrollout.iam.gserviceaccount.com
+ role: roles/progressiverollout.serviceAgent
+ is_primary: true
+ aliases: []
- name: pubsublite
display_name: Pub/Sub Lite Service Account
api: pubsublite.googleapis.com
@@ -1572,7 +1586,7 @@
display_name: Vertex AI Online Prediction Service Agent
api: aiplatform.googleapis.com
identity: service-%s@gcp-sa-vertex-op.iam.gserviceaccount.com
- role: null
+ role: roles/aiplatform.onlinePredictionServiceAgent
is_primary: false
aliases: []
- name: vertex-tune
diff --git a/modules/project/variables-observability.tf b/modules/project/variables-observability.tf
new file mode 100644
index 0000000000..56020d70ac
--- /dev/null
+++ b/modules/project/variables-observability.tf
@@ -0,0 +1,244 @@
+/**
+ * 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.
+ */
+
+variable "alerts" {
+ description = "Monitoring alerts."
+ type = map(object({
+ combiner = string
+ display_name = optional(string)
+ enabled = optional(bool)
+ notification_channels = optional(list(string), [])
+ severity = optional(string)
+ user_labels = optional(map(string))
+ alert_strategy = optional(object({
+ auto_close = optional(string)
+ notification_prompts = optional(string)
+ notification_rate_limit = optional(object({
+ period = optional(string)
+ }))
+ notification_channel_strategy = optional(object({
+ notification_channel_names = optional(list(string))
+ renotify_interval = optional(string)
+ }))
+ }))
+ conditions = optional(list(object({
+ display_name = string
+ condition_absent = optional(object({
+ duration = string
+ filter = optional(string)
+ aggregations = optional(object({
+ per_series_aligner = optional(string)
+ group_by_fields = optional(list(string))
+ cross_series_reducer = optional(string)
+ alignment_period = optional(string)
+ }))
+ trigger = optional(object({
+ count = optional(number)
+ percent = optional(number)
+ }))
+ }))
+ condition_matched_log = optional(object({
+ filter = string
+ label_extractors = optional(map(string))
+ }))
+ condition_monitoring_query_language = optional(object({
+ duration = string
+ query = string
+ evaluation_missing_data = optional(string)
+ trigger = optional(object({
+ count = optional(number)
+ percent = optional(number)
+ }))
+ }))
+ condition_prometheus_query_language = optional(object({
+ query = string
+ alert_rule = optional(string)
+ disable_metric_validation = optional(bool)
+ duration = optional(string)
+ evaluation_interval = optional(string)
+ labels = optional(map(string))
+ rule_group = optional(string)
+ }))
+ condition_threshold = optional(object({
+ comparison = string
+ duration = string
+ denominator_filter = optional(string)
+ evaluation_missing_data = optional(string)
+ filter = optional(string)
+ threshold_value = optional(number)
+ aggregations = optional(object({
+ per_series_aligner = optional(string)
+ group_by_fields = optional(list(string))
+ cross_series_reducer = optional(string)
+ alignment_period = optional(string)
+ }))
+ denominator_aggregations = optional(object({
+ per_series_aligner = optional(string)
+ group_by_fields = optional(list(string))
+ cross_series_reducer = optional(string)
+ alignment_period = optional(string)
+ }))
+ forecast_options = optional(object({
+ forecast_horizon = string
+ }))
+ trigger = optional(object({
+ count = optional(number)
+ percent = optional(number)
+ }))
+ }))
+ })), [])
+ documentation = optional(object({
+ content = optional(string)
+ mime_type = optional(string)
+ subject = optional(string)
+ links = optional(list(object({
+ display_name = optional(string)
+ url = optional(string)
+ })))
+ }))
+ }))
+ nullable = false
+ default = {}
+}
+
+variable "log_scopes" {
+ description = "Log scopes under this project."
+ type = map(object({
+ description = optional(string)
+ resource_names = list(string)
+ }))
+ nullable = false
+ default = {}
+}
+
+variable "logging_data_access" {
+ description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
+ type = map(map(list(string)))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue(flatten([
+ for k, v in var.logging_data_access : [
+ for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
+ ]
+ ]))
+ error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
+ }
+}
+
+variable "logging_exclusions" {
+ description = "Logging exclusions for this project in the form {NAME -> FILTER}."
+ type = map(string)
+ default = {}
+ nullable = false
+}
+
+variable "logging_metrics" {
+ description = "Log-based metrics."
+ type = map(object({
+ filter = string
+ bucket_name = optional(string)
+ description = optional(string)
+ disabled = optional(bool)
+ label_extractors = optional(map(string))
+ value_extractor = optional(string)
+ bucket_options = optional(object({
+ explicit_buckets = optional(object({
+ bounds = list(number)
+ }))
+ exponential_buckets = optional(object({
+ num_finite_buckets = number
+ growth_factor = number
+ scale = number
+ }))
+ linear_buckets = optional(object({
+ num_finite_buckets = number
+ width = number
+ offset = number
+ }))
+ }))
+ metric_descriptor = optional(object({
+ metric_kind = string
+ value_type = string
+ display_name = optional(string)
+ unit = optional(string)
+ labels = optional(list(object({
+ key = string
+ description = optional(string)
+ value_type = optional(string)
+ })), [])
+ }))
+ }))
+ nullable = false
+ default = {}
+}
+
+variable "logging_sinks" {
+ description = "Logging sinks to create for this project."
+ type = map(object({
+ bq_partitioned_table = optional(bool, false)
+ description = optional(string)
+ destination = string
+ disabled = optional(bool, false)
+ exclusions = optional(map(string), {})
+ filter = optional(string)
+ iam = optional(bool, true)
+ type = string
+ unique_writer = optional(bool, true)
+ }))
+ default = {}
+ nullable = false
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
+ ])
+ error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
+ }
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ v.bq_partitioned_table != true || v.type == "bigquery"
+ ])
+ error_message = "Can only set bq_partitioned_table when type is `bigquery`."
+ }
+}
+
+variable "metric_scopes" {
+ description = "List of projects that will act as metric scopes for this project."
+ type = list(string)
+ default = []
+ nullable = false
+}
+
+variable "notification_channels" {
+ description = "Monitoring notification channels."
+ type = map(object({
+ type = string
+ description = optional(string)
+ display_name = optional(string)
+ enabled = optional(bool)
+ labels = optional(map(string))
+ user_labels = optional(map(string))
+ sensitive_labels = optional(object({
+ auth_token = optional(string)
+ password = optional(string)
+ service_key = optional(string)
+ }))
+ }))
+ nullable = false
+ default = {}
+}
diff --git a/modules/project/variables.tf b/modules/project/variables.tf
index 88f59763a0..31ee76ff99 100644
--- a/modules/project/variables.tf
+++ b/modules/project/variables.tf
@@ -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.
@@ -81,9 +81,13 @@ variable "descriptive_name" {
variable "factories_config" {
description = "Paths to data files and folders that enable factory functionality."
type = object({
- custom_roles = optional(string)
- org_policies = optional(string)
- quotas = optional(string)
+ custom_roles = optional(string)
+ observability = optional(string)
+ org_policies = optional(string)
+ quotas = optional(string)
+ context = optional(object({
+ notification_channels = optional(map(string), {})
+ }), {})
})
nullable = false
default = {}
@@ -102,66 +106,6 @@ variable "lien_reason" {
default = null
}
-variable "logging_data_access" {
- description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
- type = map(map(list(string)))
- nullable = false
- default = {}
- validation {
- condition = alltrue(flatten([
- for k, v in var.logging_data_access : [
- for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
- ]
- ]))
- error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
- }
-}
-
-variable "logging_exclusions" {
- description = "Logging exclusions for this project in the form {NAME -> FILTER}."
- type = map(string)
- default = {}
- nullable = false
-}
-
-variable "logging_sinks" {
- description = "Logging sinks to create for this project."
- type = map(object({
- bq_partitioned_table = optional(bool, false)
- description = optional(string)
- destination = string
- disabled = optional(bool, false)
- exclusions = optional(map(string), {})
- filter = optional(string)
- iam = optional(bool, true)
- type = string
- unique_writer = optional(bool, true)
- }))
- default = {}
- nullable = false
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
- ])
- error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
- }
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- v.bq_partitioned_table != true || v.type == "bigquery"
- ])
- error_message = "Can only set bq_partitioned_table when type is `bigquery`."
- }
-}
-
-variable "metric_scopes" {
- description = "List of projects that will act as metric scopes for this project."
- type = list(string)
- default = []
- nullable = false
-}
-
variable "name" {
description = "Project name and id suffix."
type = string
diff --git a/modules/project/versions.tofu b/modules/project/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/project/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/projects-data-source/versions.tofu b/modules/projects-data-source/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/projects-data-source/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/pubsub/versions.tofu b/modules/pubsub/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/pubsub/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/secret-manager/versions.tofu b/modules/secret-manager/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/secret-manager/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/secure-source-manager-instance/versions.tofu b/modules/secure-source-manager-instance/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/secure-source-manager-instance/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/service-directory/versions.tofu b/modules/service-directory/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/service-directory/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/source-repository/versions.tofu b/modules/source-repository/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/source-repository/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/spanner-instance/versions.tofu b/modules/spanner-instance/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/spanner-instance/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/vpc-sc/versions.tofu b/modules/vpc-sc/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/vpc-sc/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/modules/workstation-cluster/versions.tofu b/modules/workstation-cluster/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/modules/workstation-cluster/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/tests/examples/test_plan.py b/tests/examples/test_plan.py
index 46cde59799..7215486e83 100644
--- a/tests/examples/test_plan.py
+++ b/tests/examples/test_plan.py
@@ -13,7 +13,7 @@
# limitations under the License.
import json
-import re
+import os
import shutil
import subprocess
import tempfile
@@ -101,8 +101,9 @@ def _test_terraform_example(plan_validator, example):
# TODO(jccb): this should probably be done in check_documentation
# but we already have all the data here.
+ binary = os.environ.get('TERRAFORM', 'terraform')
result = subprocess.run(
- 'terraform fmt -check -diff -no-color main.tf'.split(), cwd=tmp_path,
+ f'{binary} fmt -check -diff -no-color main.tf'.split(), cwd=tmp_path,
stdout=subprocess.PIPE, encoding='utf-8')
assert result.returncode == 0, f'terraform code not formatted correctly\n{result.stdout}'
diff --git a/tests/examples_e2e/setup_module/jit.tf.json b/tests/examples_e2e/setup_module/jit.tf.json
new file mode 100644
index 0000000000..d2a9c8cedd
--- /dev/null
+++ b/tests/examples_e2e/setup_module/jit.tf.json
@@ -0,0 +1,28 @@
+{
+ "locals": {
+ "jit_services": {
+ "alloydb.googleapis.com": "roles/alloydb.serviceAgent",
+ "apigee.googleapis.com": "roles/apigee.serviceAgent",
+ "artifactregistry.googleapis.com": "roles/artifactregistry.serviceAgent",
+ "assuredworkloads.googleapis.com": "roles/assuredworkloads.serviceAgent",
+ "dns.googleapis.com": "roles/dns.serviceAgent",
+ "dataplex.googleapis.com": "roles/dataplex.serviceAgent",
+ "pubsub.googleapis.com": "roles/pubsub.serviceAgent",
+ "sqladmin.googleapis.com": "roles/cloudsql.serviceAgent",
+ "dataform.googleapis.com": "roles/dataform.serviceAgent",
+ "eventarc.googleapis.com": "roles/eventarc.serviceAgent",
+ "cloudkms.googleapis.com": null,
+ "dataproc.googleapis.com": "roles/dataproc.serviceAgent",
+ "cloudfunctions.googleapis.com": "roles/cloudfunctions.serviceAgent",
+ "run.googleapis.com": "roles/run.serviceAgent",
+ "iap.googleapis.com": null,
+ "container.googleapis.com": "roles/container.serviceAgent",
+ "looker.googleapis.com": "roles/looker.serviceAgent",
+ "monitoring.googleapis.com": "roles/monitoring.notificationServiceAgent",
+ "networkconnectivity.googleapis.com": "roles/networkconnectivity.serviceAgent",
+ "secretmanager.googleapis.com": null,
+ "vpcaccess.googleapis.com": "roles/vpcaccess.serviceAgent",
+ "servicenetworking.googleapis.com": "roles/servicenetworking.serviceAgent"
+ }
+ }
+}
diff --git a/tests/examples_e2e/setup_module/main.tf b/tests/examples_e2e/setup_module/main.tf
index 82b59b8402..47db8dfb34 100644
--- a/tests/examples_e2e/setup_module/main.tf
+++ b/tests/examples_e2e/setup_module/main.tf
@@ -14,15 +14,13 @@
locals {
prefix = "${var.prefix}-${var.timestamp}${var.suffix}"
- jit_services = [
- "alloydb.googleapis.com", # no permissions granted by default
- "artifactregistry.googleapis.com", # roles/artifactregistry.serviceAgent
- "pubsub.googleapis.com", # roles/pubsub.serviceAgent
- "storage.googleapis.com", # no permissions granted by default
- "sqladmin.googleapis.com", # roles/cloudsql.serviceAgent
- ]
services = [
- # trimmed down list of services, to be extended as needed
+ # trimmed down list of services, to be extended as needed. If you
+ # update this list, make sure to update E2E_SERVICES in
+ # tools/built_service_agents.py and run:
+ #
+ # python tools/build_service_agents.py --e2e > tests/examples_e2e/setup_module/jit.tf.json
+ #
"alloydb.googleapis.com",
"analyticshub.googleapis.com",
"apigee.googleapis.com",
@@ -212,6 +210,7 @@ resource "google_service_networking_connection" "psa_connection" {
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.psa_ranges.name]
deletion_policy = "ABANDON"
+ depends_on = [google_project_iam_binding.agents]
}
### END OF PSA
@@ -223,33 +222,24 @@ resource "google_service_account" "service_account" {
}
resource "google_project_service_identity" "jit_si" {
- for_each = toset(local.jit_services)
+ for_each = local.jit_services
provider = google-beta
project = google_project.project.project_id
- service = each.value
+ service = each.key
depends_on = [google_project_service.project_service]
}
-resource "google_project_iam_binding" "cloudsql_agent" {
- members = ["serviceAccount:service-${google_project.project.number}@gcp-sa-cloud-sql.iam.gserviceaccount.com"]
- project = google_project.project.project_id
- role = "roles/cloudsql.serviceAgent"
- depends_on = [google_project_service_identity.jit_si]
-}
-
-resource "google_project_iam_binding" "artifactregistry_agent" {
- members = ["serviceAccount:service-${google_project.project.number}@gcp-sa-artifactregistry.iam.gserviceaccount.com"]
- project = google_project.project.project_id
- role = "roles/artifactregistry.serviceAgent"
- depends_on = [google_project_service_identity.jit_si]
+resource "google_project_iam_binding" "agents" {
+ for_each = {
+ for k, v in local.jit_services : k => v if v != null
+ }
+ members = [
+ google_project_service_identity.jit_si[each.key].member
+ ]
+ project = google_project.project.project_id
+ role = each.value
}
-resource "google_project_iam_binding" "pubsub_agent" {
- members = ["serviceAccount:service-${google_project.project.number}@gcp-sa-pubsub.iam.gserviceaccount.com"]
- project = google_project.project.project_id
- role = "roles/pubsub.serviceAgent"
- depends_on = [google_project_service_identity.jit_si]
-}
resource "local_file" "terraform_tfvars" {
filename = "e2e_tests.tfvars"
diff --git a/tests/examples_e2e/setup_module/versions.tofu b/tests/examples_e2e/setup_module/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/tests/examples_e2e/setup_module/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}
diff --git a/tests/fast/stages/s1_resman/simple.yaml b/tests/fast/stages/s1_resman/simple.yaml
index 0a4b782fad..0f7d2058d3 100644
--- a/tests/fast/stages/s1_resman/simple.yaml
+++ b/tests/fast/stages/s1_resman/simple.yaml
@@ -1802,7 +1802,6 @@ outputs:
repository:
branch: main
name: test/00-networking
- parent_id: null
type: github
security:
provider: projects/1234567890/locations/global/workloadIdentityPools/ldj-bootstrap/providers/ldj-bootstrap-gitlab-ludomagno
diff --git a/tests/modules/logging_bucket/examples/views.yaml b/tests/modules/logging_bucket/examples/views.yaml
new file mode 100644
index 0000000000..c870d5e5d3
--- /dev/null
+++ b/tests/modules/logging_bucket/examples/views.yaml
@@ -0,0 +1,42 @@
+# Copyright 2024 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.bucket.google_logging_log_view.views["myview"]:
+ description: null
+ filter: LOG_ID("stdout")
+ location: global
+ name: myview
+ timeouts: null
+ module.bucket.google_logging_log_view_iam_binding.authoritative["myview.roles/logging.viewAccessor"]:
+ condition: []
+ location: global
+ members:
+ - user:user@example.com
+ name: myview
+ role: roles/logging.viewAccessor
+ module.bucket.google_logging_project_bucket_config.bucket[0]:
+ bucket_id: mybucket
+ cmek_settings: []
+ enable_analytics: false
+ index_configs: []
+ location: global
+ locked: null
+ project: project-id
+ retention_days: 30
+
+counts:
+ google_logging_log_view: 1
+ google_logging_log_view_iam_binding: 1
+ google_logging_project_bucket_config: 1
diff --git a/tests/modules/project/examples/log-scopes.yaml b/tests/modules/project/examples/log-scopes.yaml
new file mode 100644
index 0000000000..d4cacb3aba
--- /dev/null
+++ b/tests/modules/project/examples/log-scopes.yaml
@@ -0,0 +1,68 @@
+# Copyright 2024 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.bucket.google_logging_log_view.views["view1"]:
+ description: null
+ filter: LOG_ID("stdout")
+ location: global
+ name: view1
+ module.bucket.google_logging_log_view_iam_binding.authoritative["view1.roles/logging.viewAccessor"]:
+ condition: []
+ location: global
+ members:
+ - user:user@example.com
+ name: view1
+ role: roles/logging.viewAccessor
+ module.bucket.google_logging_project_bucket_config.bucket[0]:
+ bucket_id: mybucket
+ cmek_settings: []
+ enable_analytics: false
+ index_configs: []
+ location: global
+ locked: null
+ project: other-project
+ retention_days: 30
+ module.project.google_logging_log_scope.log-scopes["scope"]:
+ description: My log scope
+ location: global
+ name: scope
+ parent: projects/test-logscope
+ module.project.google_project.project[0]:
+ auto_create_network: false
+ billing_account: 123456-123456-123456
+ deletion_policy: DELETE
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ folder_id: '1122334455'
+ labels: null
+ name: test-logscope
+ org_id: null
+ project_id: test-logscope
+ tags: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ module.project.google_project_service.project_services["logging.googleapis.com"]:
+ disable_dependent_services: false
+ disable_on_destroy: false
+ project: test-logscope
+ service: logging.googleapis.com
+
+counts:
+ google_logging_log_scope: 1
+ google_logging_log_view: 1
+ google_logging_log_view_iam_binding: 1
+ google_logging_project_bucket_config: 1
+ google_project: 1
+ google_project_service: 1
diff --git a/tools/build_service_agents.py b/tools/build_service_agents.py
index c8dc0690da..65e22d28b2 100755
--- a/tools/build_service_agents.py
+++ b/tools/build_service_agents.py
@@ -17,6 +17,8 @@
from dataclasses import asdict, dataclass
from itertools import chain
+import click
+import json
import requests
import yaml
from bs4 import BeautifulSoup
@@ -41,6 +43,42 @@
'serverless-robot-prod': ['cloudrun', 'run'],
}
+E2E_SERVICES = [
+ "alloydb.googleapis.com",
+ "analyticshub.googleapis.com",
+ "apigee.googleapis.com",
+ "artifactregistry.googleapis.com",
+ "assuredworkloads.googleapis.com",
+ "bigquery.googleapis.com",
+ "cloudbuild.googleapis.com",
+ "cloudfunctions.googleapis.com",
+ "cloudkms.googleapis.com",
+ "cloudresourcemanager.googleapis.com",
+ "compute.googleapis.com",
+ "container.googleapis.com",
+ "dataform.googleapis.com",
+ "dataplex.googleapis.com",
+ "dataproc.googleapis.com",
+ "dns.googleapis.com",
+ "eventarc.googleapis.com",
+ "iam.googleapis.com",
+ "iap.googleapis.com",
+ "logging.googleapis.com",
+ "looker.googleapis.com",
+ "monitoring.googleapis.com",
+ "networkconnectivity.googleapis.com",
+ "pubsub.googleapis.com",
+ "run.googleapis.com",
+ "secretmanager.googleapis.com",
+ "servicenetworking.googleapis.com",
+ "serviceusage.googleapis.com",
+ "sqladmin.googleapis.com",
+ "stackdriver.googleapis.com",
+ "storage-component.googleapis.com",
+ "storage.googleapis.com",
+ "vpcaccess.googleapis.com",
+]
+
PRIMARY_OVERRIDE = {
'storage-transfer-service': True,
}
@@ -57,7 +95,9 @@ class Agent:
aliases: list[str]
-def main():
+@click.command()
+@click.option('--e2e', is_flag=True, default=False)
+def main(e2e=False):
page = requests.get(SERVICE_AGENTS_URL).content
soup = BeautifulSoup(page, 'html.parser')
agents = []
@@ -115,11 +155,19 @@ def main():
aliases = set(chain.from_iterable(agent.aliases for agent in agents))
assert aliases.isdisjoint(names)
- # take the header from the first lines of this file
- header = open(__file__).readlines()[2:15]
- print("".join(header))
- # and print all the agents
- print(yaml.safe_dump([asdict(a) for a in agents], sort_keys=False))
+ if not e2e:
+ # take the header from the first lines of this file
+ header = open(__file__).readlines()[2:15]
+ print("".join(header))
+ # and print all the agents
+ print(yaml.safe_dump([asdict(a) for a in agents], sort_keys=False))
+ else:
+ jit_services = {}
+ result = {"locals": {"jit_services": jit_services}}
+ for a in agents:
+ if a.is_primary and a.api in E2E_SERVICES:
+ jit_services[a.api] = a.role
+ print(json.dumps(result, indent=2))
if __name__ == '__main__':
diff --git a/tools/lockfile/main.tf b/tools/lockfile/main.tf
index 9c8a3e7047..6670ff63ce 100644
--- a/tools/lockfile/main.tf
+++ b/tools/lockfile/main.tf
@@ -23,3 +23,4 @@ resource "random_pet" "default" {}
resource "time_static" "default" {}
resource "tls_private_key" "default" {}
resource "vsphere_role" "default" {}
+resource "kubernetes_secret" "default" {}
diff --git a/tools/lockfile/versions.tofu b/tools/lockfile/versions.tofu
new file mode 100644
index 0000000000..b21145b3bf
--- /dev/null
+++ b/tools/lockfile/versions.tofu
@@ -0,0 +1,29 @@
+# Copyright 2024 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
+#
+# https://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.
+
+# Fabric release: v36.0.1
+
+terraform {
+ required_version = ">= 1.8.0"
+ required_providers {
+ google = {
+ source = "hashicorp/google"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ google-beta = {
+ source = "hashicorp/google-beta"
+ version = ">= 6.13.0, < 7.0.0" # tftest
+ }
+ }
+}