diff --git a/CHANGELOG.md b/CHANGELOG.md
index 75dcecb1..1bfafeac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,48 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
-
+
+
+### BLUEPRINTS
+
+- [[#1748](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1748)] Bump golang.org/x/net from 0.7.0 to 0.17.0 in /blueprints/cloud-operations/unmanaged-instances-healthcheck/function/restarter ([dependabot[bot]](https://github.com/dependabot[bot]))
+- [[#1747](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1747)] Bump golang.org/x/net from 0.7.0 to 0.17.0 in /blueprints/cloud-operations/unmanaged-instances-healthcheck/function/healthchecker ([dependabot[bot]](https://github.com/dependabot[bot]))
+- [[#1735](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1735)] Make deletion protection consistent across all modules ([juliocc](https://github.com/juliocc))
+
+### DOCUMENTATION
+
+- [[#1743](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1743)] Billing account module ([ludoo](https://github.com/ludoo))
+
+### FAST
+
+- [[#1760](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1760)] Add support for psa peered domains to fast stages ([ludoo](https://github.com/ludoo))
+- [[#1759](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1759)] Minor edits to FAST network stage READMEs ([ludoo](https://github.com/ludoo))
+- [[#1743](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1743)] Billing account module ([ludoo](https://github.com/ludoo))
+- [[#1735](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1735)] Make deletion protection consistent across all modules ([juliocc](https://github.com/juliocc))
+- [[#1734](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1734)] Update to lint.sh and wording to some tf ([bluPhy](https://github.com/bluPhy))
+- [[#1733](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1733)] Fix typo in FAST stage 2 README ([bluPhy](https://github.com/bluPhy))
+
+### MODULES
+
+- [[#1762](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1762)] Make subnets depend on proxy only subnets ([juliocc](https://github.com/juliocc))
+- [[#1757](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1757)] Add autoclass to GCS ([jeroenmonteban](https://github.com/jeroenmonteban))
+- [[#1756](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1756)] Exposed stack_type variable in compute_vm module ([luigi-bitonti](https://github.com/luigi-bitonti))
+- [[#1743](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1743)] Billing account module ([ludoo](https://github.com/ludoo))
+- [[#1752](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1752)] Add outputs to BigQuery dataset module ([devuonocar](https://github.com/devuonocar))
+- [[#1754](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1754)] Fix typo in GKE nodepool taints ([ludoo](https://github.com/ludoo))
+- [[#1746](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1746)] Module autopilot bug fixes ([luigi-bitonti](https://github.com/luigi-bitonti))
+- [[#1745](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1745)] Add missing fields to Cloud Storage bucket ([devuonocar](https://github.com/devuonocar))
+- [[#1744](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1744)] Append "s" to pubsub backoff times ([juliocc](https://github.com/juliocc))
+- [[#1741](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1741)] Add PSA peered domains support to `net-vpc` ([juliocc](https://github.com/juliocc))
+- [[#1737](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1737)] Enforce mandatory types in all variables ([juliocc](https://github.com/juliocc))
+- [[#1732](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1732)] Added FQDN Network Policy feature on GKE Cluster ([luigi-bitonti](https://github.com/luigi-bitonti))
+- [[#1735](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1735)] Make deletion protection consistent across all modules ([juliocc](https://github.com/juliocc))
+- [[#1726](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1726)] Add materialized views for bigquery ([devuonocar](https://github.com/devuonocar))
+
+### TOOLS
+
+- [[#1737](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1737)] Enforce mandatory types in all variables ([juliocc](https://github.com/juliocc))
+- [[#1734](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1734)] Update to lint.sh and wording to some tf ([bluPhy](https://github.com/bluPhy))
## [27.0.0] - 2023-10-04
diff --git a/README.md b/README.md
index 84dbdca2..08907864 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ The current list of modules supports most of the core foundational and networkin
Currently available modules:
-- **foundational** - [billing budget](./modules/billing-budget), [Cloud Identity group](./modules/cloud-identity-group/), [folder](./modules/folder), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [organization](./modules/organization), [project](./modules/project), [projects-data-source](./modules/projects-data-source)
+- **foundational** - [billing account](./modules/billing-account), [Cloud Identity group](./modules/cloud-identity-group/), [folder](./modules/folder), [service accounts](./modules/iam-service-account), [logging bucket](./modules/logging-bucket), [organization](./modules/organization), [project](./modules/project), [projects-data-source](./modules/projects-data-source)
- **networking** - [DNS](./modules/dns), [DNS Response Policy](./modules/dns-response-policy/), [Cloud Endpoints](./modules/endpoints), [address reservation](./modules/net-address), [NAT](./modules/net-cloudnat), [VLAN Attachment](./modules/net-vlan-attachment/), [External Application LB](./modules/net-lb-app-ext/), [External Passthrough Network LB](./modules/net-lb-ext), [Firewall policy](./modules/net-firewall-policy), [Internal Application LB](./modules/net-lb-app-int), [Internal Passthrough Network LB](./modules/net-lb-int), [Internal Proxy Network LB](./modules/net-lb-proxy-int), [IPSec over Interconnect](./modules/net-ipsec-over-interconnect), [VPC](./modules/net-vpc), [VPC firewall](./modules/net-vpc-firewall), [VPC peering](./modules/net-vpc-peering), [VPN dynamic](./modules/net-vpn-dynamic), [HA VPN](./modules/net-vpn-ha), [VPN static](./modules/net-vpn-static), [Service Directory](./modules/service-directory), [Secure Web Proxy](./modules/net-swp)
- **compute** - [VM/VM group](./modules/compute-vm), [MIG](./modules/compute-mig), [COS container](./modules/cloud-config-container/cos-generic-metadata/) (coredns, mysql, onprem, squid), [GKE cluster](./modules/gke-cluster-standard), [GKE hub](./modules/gke-hub), [GKE nodepool](./modules/gke-nodepool), [GCVE private cloud](./modules/gcve-private-cloud)
- **data** - [BigQuery dataset](./modules/bigquery-dataset), [Bigtable instance](./modules/bigtable-instance), [Dataplex](./modules/dataplex), [Dataplex DataScan](./modules/dataplex-datascan/), [Cloud SQL instance](./modules/cloudsql-instance), [Data Catalog Policy Tag](./modules/data-catalog-policy-tag), [Datafusion](./modules/datafusion), [Dataproc](./modules/dataproc), [GCS](./modules/gcs), [Pub/Sub](./modules/pubsub)
diff --git a/fast/stages/0-bootstrap/billing.tf b/fast/stages/0-bootstrap/billing.tf
index 203ecbe8..82185461 100644
--- a/fast/stages/0-bootstrap/billing.tf
+++ b/fast/stages/0-bootstrap/billing.tf
@@ -74,12 +74,3 @@ resource "google_billing_account_iam_member" "billing_ext_admin" {
role = "roles/billing.admin"
member = each.key
}
-
-resource "google_billing_account_iam_member" "billing_ext_cost_manager" {
- for_each = toset(
- local.billing_mode == "resource" ? local.billing_ext_admins : []
- )
- billing_account_id = var.billing_account.id
- role = "roles/billing.costsManager"
- member = each.key
-}
diff --git a/fast/stages/0-bootstrap/organization-iam.tf b/fast/stages/0-bootstrap/organization-iam.tf
index 9cc99665..26285ac1 100644
--- a/fast/stages/0-bootstrap/organization-iam.tf
+++ b/fast/stages/0-bootstrap/organization-iam.tf
@@ -34,8 +34,7 @@ locals {
authoritative = []
additive = (
local.billing_mode != "org" ? [] : [
- "roles/billing.admin",
- "roles/billing.costsManager"
+ "roles/billing.admin"
]
)
}
@@ -66,8 +65,7 @@ locals {
"roles/orgpolicy.policyAdmin"
],
local.billing_mode != "org" ? [] : [
- "roles/billing.admin",
- "roles/billing.costsManager"
+ "roles/billing.admin"
]
)
}
@@ -111,8 +109,7 @@ locals {
"roles/orgpolicy.policyAdmin"
],
local.billing_mode != "org" ? [] : [
- "roles/billing.admin",
- "roles/billing.costsManager"
+ "roles/billing.admin"
]
)
}
@@ -129,8 +126,7 @@ locals {
"roles/orgpolicy.policyAdmin"
],
local.billing_mode != "org" ? [] : [
- "roles/billing.admin",
- "roles/billing.costsManager"
+ "roles/billing.admin"
]
)
}
@@ -148,8 +144,7 @@ locals {
# TODO: align additive roles with the README
additive = (
local.billing_mode != "org" ? [] : [
- "roles/billing.admin",
- "roles/billing.costsManager"
+ "roles/billing.admin"
]
)
}
diff --git a/fast/stages/2-networking-a-peering/README.md b/fast/stages/2-networking-a-peering/README.md
index 03883b16..05478d79 100644
--- a/fast/stages/2-networking-a-peering/README.md
+++ b/fast/stages/2-networking-a-peering/README.md
@@ -147,15 +147,12 @@ This configuration is battle-tested, and flexible enough to lend itself to simpl
### VPCs
VPCs are defined in separate files, one for `landing` and one for each of `prod` and `dev`.
-Each file contains the same resources, described in the following paragraphs.
-The **project** ([`project`](../../../modules/project)) contains the VPC, and enables the required APIs and sets itself as a "[host project](https://cloud.google.com/vpc/docs/shared-vpc)".
+These files contain different resources:
-The **VPC** ([`net-vpc`](../../../modules/net-vpc)) manages the DNS inbound policy (for Landing), explicit routes for `{private,restricted}.googleapis.com`, and its **subnets**. Subnets are created leveraging a "resource factory" paradigm, where the configuration is separated from the module that implements it, and stored in a well-structured file. To add a new subnet, simply create a new file in the `data_folder` directory defined in the module, following the examples found in the [Fabric `net-vpc` documentation](../../../modules/net-vpc#subnet-factory). Sample subnets are shipped in [data/subnets](./data/subnets), and can be easily customised to fit your needs.
-
-Subnets for [L7 ILBs](https://cloud.google.com/load-balancing/docs/l7-internal/proxy-only-subnets) are handled differently, and defined in variable `l7ilb_subnets`, while ranges for [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by variable `psa_ranges` - such variables are consumed by spoke VPCs.
-
-**Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
+- **project** ([`projects`](../../../modules/project)): the "[host projects](https://cloud.google.com/vpc/docs/shared-vpc)" containing the VPCs and enabling the required APIs.
+- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manages the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy for the trusted landing VPC. Non-infrastructural subnets are created leveraging resource factories. Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs. [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by the variable `psa_ranges` if managed services are needed.
+- **Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
### VPNs
@@ -282,17 +279,12 @@ terraform apply
#### Private Google Access
-[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment.
+[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment:
-For PGA to work:
+- DNS response policies in the landing project implement rules for all supported domains reachable via PGA
+- routes for the private and restricted ranges are defined in all VPCs
-- Private Google Access should be enabled on the subnet. \
-Subnets created by the `net-vpc` module are PGA-enabled by default.
-
-- 199.36.153.4/30 (`restricted.googleapis.com`) and 199.36.153.8/30 (`private.googleapis.com`) should be routed from on-prem to VPC, and from there to the `default-internet-gateway`. \
-Per variable `vpn_onprem_configs` such ranges are advertised to onprem - furthermore every VPC (e.g. see `landing-vpc` in [`landing.tf`](./landing.tf)) has explicit routes set in case the `0.0.0.0/0` route is changed.
-
-- A private DNS zone for `googleapis.com` should be created and configured per [this article](https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid#config-domain), as implemented in module `googleapis-private-zone` in [`dns-landing.tf`](./dns-landing.tf)
+To enable PGA access from on premises advertise the private/restricted ranges via the `landing-to-onprem-primary-vpn` variable, using router or tunnel custom advertisements.
## Customizations
@@ -406,10 +398,10 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | object({…})
| | {…}
| |
| [outputs_location](variables.tf#L121) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
| [peering_configs](variables-peerings.tf#L19) | Peering configurations. | object({…})
| | {}
| |
-| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…})
| | null
| |
-| [regions](variables.tf#L155) | Region definitions. | object({…})
| | {…}
| |
-| [service_accounts](variables.tf#L167) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
-| [vpn_onprem_primary_config](variables.tf#L181) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
+| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…})
| | null
| |
+| [regions](variables.tf#L157) | Region definitions. | object({…})
| | {…}
| |
+| [service_accounts](variables.tf#L169) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
+| [vpn_onprem_primary_config](variables.tf#L183) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
## Outputs
diff --git a/fast/stages/2-networking-a-peering/variables.tf b/fast/stages/2-networking-a-peering/variables.tf
index d0190dfa..42d068d7 100644
--- a/fast/stages/2-networking-a-peering/variables.tf
+++ b/fast/stages/2-networking-a-peering/variables.tf
@@ -139,14 +139,16 @@ variable "psa_ranges" {
description = "IP ranges used for Private Service Access (CloudSQL, etc.)."
type = object({
dev = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
prod = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
})
default = null
diff --git a/fast/stages/2-networking-b-vpn/README.md b/fast/stages/2-networking-b-vpn/README.md
index c06c75de..4de2666e 100644
--- a/fast/stages/2-networking-b-vpn/README.md
+++ b/fast/stages/2-networking-b-vpn/README.md
@@ -153,15 +153,11 @@ This configuration is battle-tested, and flexible enough to lend itself to simpl
### VPCs
VPCs are defined in separate files, one for `landing` and one for each of `prod` and `dev`.
-Each file contains the same resources, described in the following paragraphs.
+These files contain different resources:
-The **project** ([`project`](../../../modules/project)) contains the VPC, and enables the required APIs and sets itself as a "[host project](https://cloud.google.com/vpc/docs/shared-vpc)".
-
-The **VPC** ([`net-vpc`](../../../modules/net-vpc)) manages the DNS inbound policy (for Landing), explicit routes for `{private,restricted}.googleapis.com`, and its **subnets**. Subnets are created leveraging a "resource factory" paradigm, where the configuration is separated from the module that implements it, and stored in a well-structured file. To add a new subnet, simply create a new file in the `data_folder` directory defined in the module, following the examples found in the [Fabric `net-vpc` documentation](../../../modules/net-vpc#subnet-factory). Sample subnets are shipped in [data/subnets](./data/subnets), and can be easily customised to fit your needs.
-
-Subnets for [L7 ILBs](https://cloud.google.com/load-balancing/docs/l7-internal/proxy-only-subnets) are handled differently, and defined in variable `l7ilb_subnets`, while ranges for [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by variable `psa_ranges` - such variables are consumed by spoke VPCs.
-
-**Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
+- **project** ([`projects`](../../../modules/project)): the "[host projects](https://cloud.google.com/vpc/docs/shared-vpc)" containing the VPCs and enabling the required APIs.
+- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manages the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy for the trusted landing VPC. Non-infrastructural subnets are created leveraging resource factories. Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs. [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by the variable `psa_ranges` if managed services are needed.
+- **Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
### VPNs
@@ -296,17 +292,12 @@ terraform apply
#### Private Google Access
-[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment.
+[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment:
-For PGA to work:
+- DNS response policies in the landing project implement rules for all supported domains reachable via PGA
+- routes for the private and restricted ranges are defined in all VPCs
-- Private Google Access should be enabled on the subnet. \
-Subnets created by the `net-vpc` module are PGA-enabled by default.
-
-- 199.36.153.4/30 (`restricted.googleapis.com`) and 199.36.153.8/30 (`private.googleapis.com`) should be routed from on-prem to VPC, and from there to the `default-internet-gateway`. \
-Per variable `vpn_onprem_configs` such ranges are advertised to onprem - furthermore every VPC (e.g. see `landing-vpc` in [`landing.tf`](./landing.tf)) has explicit routes set in case the `0.0.0.0/0` route is changed.
-
-- A private DNS zone for `googleapis.com` should be created and configured per [this article](https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid#config-domain), as implemented in module `googleapis-private-zone` in [`dns-landing.tf`](./dns-landing.tf)
+To enable PGA access from on premises advertise the private/restricted ranges via the `landing-to-onprem-primary-vpn` variable, using router or tunnel custom advertisements.
## Customizations
@@ -430,11 +421,11 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [dns](variables.tf#L72) | Onprem DNS resolvers. | map(list(string))
| | {…}
| |
| [factories_config](variables.tf#L80) | Configuration for network resource factories. | object({…})
| | {…}
| |
| [outputs_location](variables.tf#L121) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
-| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…})
| | null
| |
-| [regions](variables.tf#L155) | Region definitions. | object({…})
| | {…}
| |
-| [service_accounts](variables.tf#L167) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
+| [psa_ranges](variables.tf#L138) | IP ranges used for Private Service Access (CloudSQL, etc.). | object({…})
| | null
| |
+| [regions](variables.tf#L157) | Region definitions. | object({…})
| | {…}
| |
+| [service_accounts](variables.tf#L169) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
| [vpn_configs](variables-vpn.tf#L17) | Hub to spokes VPN configurations. | object({…})
| | {…}
| |
-| [vpn_onprem_primary_config](variables.tf#L181) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
+| [vpn_onprem_primary_config](variables.tf#L183) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
## Outputs
diff --git a/fast/stages/2-networking-b-vpn/variables.tf b/fast/stages/2-networking-b-vpn/variables.tf
index d0190dfa..42d068d7 100644
--- a/fast/stages/2-networking-b-vpn/variables.tf
+++ b/fast/stages/2-networking-b-vpn/variables.tf
@@ -139,14 +139,16 @@ variable "psa_ranges" {
description = "IP ranges used for Private Service Access (CloudSQL, etc.)."
type = object({
dev = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
prod = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
})
default = null
diff --git a/fast/stages/2-networking-c-nva/README.md b/fast/stages/2-networking-c-nva/README.md
index 9da69cfa..d61baf57 100644
--- a/fast/stages/2-networking-c-nva/README.md
+++ b/fast/stages/2-networking-c-nva/README.md
@@ -125,19 +125,7 @@ This stage uses a dedicated /11 block (10.64.0.0/11), which should be sized to t
The /11 block is evenly split in eight, smaller /16 blocks, assigned to different areas of the GCP network: *landing untrusted europe-west1*, *landing untrusted europe-west4*, *landing trusted europe-west1*, *landing untrusted europe-west4*, *development europe-west1*, *development europe-west4*, *production europe-west1*, *production europe-west4*.
-The first /24 range in every area is allocated for a default subnet, which can be removed or modified as needed.
-
-Spoke VPCs also define and reserve three "special" CIDR ranges, derived from their respective /16, dedicated to
-
-- [PSA (Private Service Access)](https://cloud.google.com/vpc/docs/private-services-access):
-
- - The second-last /24 range is used for PSA (CloudSQL, Postrgres)
-
- - The third-last /24 range is used for PSA (CloudSQL, MySQL)
-
-- [Internal Application Load Balancers (L7 LBs)](https://cloud.google.com/load-balancing/docs/l7-internal):
-
- - The last /24 range
+The first /24 range in every area is allocated for a default subnet, which can be removed or modified as needed. The last three /24 ranges can be used for [PSA (Private Service Access)](https://cloud.google.com/vpc/docs/private-services-access)via the `psa_ranges` variable, or for [Internal Application Load Balancers (L7 LBs)](https://cloud.google.com/load-balancing/docs/l7-internal) subnets via the factory.
This is a summary of the subnets allocated by default in this setup:
@@ -148,23 +136,23 @@ This is a summary of the subnets allocated by default in this setup:
| landing-untrusted-default-ew1 | Untrusted landing subnet - europe-west1 | 10.128.0.0/24 |
| landing-untrusted-default-ew4 | Untrusted landing subnet - europe-west4 | 10.128.32.0/24 |
| dev-default-ew1 | Dev spoke subnet - europe-west1 | 10.68.0.0/24 |
-| dev-default-ew1 (PSA MySQL) | PSA subnet for MySQL in dev spoke - europe-west1 | 10.68.253.0/24 |
-| dev-default-ew1 (PSA SQL Server) | PSA subnet for Postgres in dev spoke - europe-west1 | 10.68.254.0/24 |
-| dev-default-ew1 (L7 ILB) | L7 ILB subnet for dev spoke - europe-west1 | 10.68.255.0/24 |
+| dev-default-ew1 | Free (PSA) - europe-west1 | 10.68.253.0/24 |
+| dev-default-ew1 | Free (PSA) - europe-west1 | 10.68.254.0/24 |
+| dev-default-ew1 | Free (L7 ILB) - europe-west1 | 10.68.255.0/24 |
| dev-default-ew4 | Dev spoke subnet - europe-west4 | 10.84.0.0/24 |
-| dev-default-ew4 (PSA MySQL) | PSA subnet for MySQL in dev spoke - europe-west4 | 10.84.253.0/24 |
-| dev-default-ew4 (PSA SQL Server) | PSA subnet for Postgres in dev spoke - europe-west4 | 10.84.254.0/24 |
-| dev-default-ew4 (L7 ILB) | L7 ILB subnet for dev spoke - europe-west4 | 10.84.255.0/24 |
+| dev-default-ew4 | Free (PSA) - europe-west4 | 10.84.253.0/24 |
+| dev-default-ew4 | Free (PSA) - europe-west4 | 10.84.254.0/24 |
+| dev-default-ew4 | Free (L7 ILB) - europe-west4 | 10.84.255.0/24 |
| prod-default-ew1 | Prod spoke subnet - europe-west1 | 10.72.0.0/24 |
-| prod-default-ew1 (PSA MySQL) | PSA subnet for MySQL in prod spoke - europe-west1 | 10.72.253.0/24 |
-| prod-default-ew1 (PSA SQL Server) | PSA subnet for Postgres in prod spoke - europe-west1 | 10.72.254.0/24 |
-| prod-default-ew1 (L7 ILB) | L7 ILB subnet for prod spoke - europe-west1 | 10.72.255.0/24 |
+| prod-default-ew1 | Free (PSA) - europe-west1 | 10.72.253.0/24 |
+| prod-default-ew1 | Free (PSA) - europe-west1 | 10.72.254.0/24 |
+| prod-default-ew1 | Free (L7 ILB) - europe-west1 | 10.72.255.0/24 |
| prod-default-ew4 | Prod spoke subnet - europe-west4 | 10.88.0.0/24 |
-| prod-default-ew4 (PSA MySQL) | PSA subnet for MySQL in prod spoke - europe-west4 | 10.88.253.0/24 |
-| prod-default-ew4 (PSA SQL Server) | PSA subnet for Postgres in prod spoke - europe-west4 | 10.88.254.0/24 |
-| prod-default-ew4 (L7 ILB) | L7 ILB subnet for prod spoke - europe-west4 | 10.88.255.0/24 |
+| prod-default-ew4 | Free (PSA) - europe-west4 | 10.88.253.0/24 |
+| prod-default-ew4 | Free (PSA) - europe-west4 | 10.88.254.0/24 |
+| prod-default-ew4 | Free (L7 ILB) - europe-west4 | 10.88.255.0/24 |
-These subnets can advertised to on-premises as an aggregate /11 range (10.64.0.0/11). Refer to the `var.vpn_onprem_primary_config.router_config` and `var.vpn_onprem_secondary_config.router_config` variables to configure it.
+These subnets can be advertised to on-premises as an aggregate /11 range (10.64.0.0/11). Refer to the `var.vpn_onprem_primary_config.router_config` and `var.vpn_onprem_secondary_config.router_config` variables to configure it.
Routes in GCP are either automatically created (for example, when a subnet is added to a VPC), manually created via static routes, dynamically exchanged through VPC peerings, or dynamically programmed by [Cloud Routers](https://cloud.google.com/network-connectivity/docs/router#docs) when a BGP session is established. BGP sessions can be configured to advertise VPC ranges, and/or custom ranges via custom advertisements.
@@ -231,10 +219,7 @@ VPCs are defined in separate files, one for `landing` (trusted and untrusted), o
These files contain different resources:
- **project** ([`projects`](../../../modules/project)): the "[host projects](https://cloud.google.com/vpc/docs/shared-vpc)" containing the VPCs and enabling the required APIs.
-- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manage the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy (for the trusted landing VPC). Subnets are created leveraging "resource factories": the configuration is separated from the module that implements it, and stored in a well-structured file. To add a new subnet, simply create a new file in the `data_folder` directory defined in the module, following the examples found in the [Fabric `net-vpc` documentation](../../../modules/net-vpc#subnet-factory). Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs.
-
-Subnets for [L7 ILBs](https://cloud.google.com/load-balancing/docs/l7-internal/proxy-only-subnets) are handled differently, and defined in variable `l7ilb_subnets`, while ranges for [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by variable `psa_ranges` - such variables are consumed by spoke VPCs.
-
+- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manages the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy for the trusted landing VPC. Non-infrastructural subnets are created leveraging resource factories. Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs. [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by the variable `psa_ranges` if managed services are needed.
- **Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) (in the untrusted landing VPC only): it manages the networking infrastructure required to enable the Internet egress.
### VPNs
@@ -364,17 +349,12 @@ terraform apply
#### Private Google Access
-[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment.
+[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment:
-For PGA to work:
+- DNS response policies in the landing project implement rules for all supported domains reachable via PGA
+- routes for the private and restricted ranges are defined in all VPCs except untrusted
-- Private Google Access should be enabled on the subnet. \
-Subnets created by the `net-vpc` module are PGA-enabled by default.
-
-- 199.36.153.4/30 (`restricted.googleapis.com`) and 199.36.153.8/30 (`private.googleapis.com`) should be routed from on-prem to VPC, and from there to the `default-internet-gateway`. \
-Per variable `vpn_onprem_configs` such ranges are advertised to onprem - furthermore every VPC (e.g. see `landing-vpc` in [`landing.tf`](./landing.tf)) has explicit routes set in case the `0.0.0.0/0` route is changed.
-
-- A private DNS zone for `googleapis.com` should be created and configured per [this article](https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid#config-domain), as implemented in module `googleapis-private-zone` in [`dns-landing.tf`](./dns-landing.tf)
+To enable PGA access from on premises advertise the private/restricted ranges via the `vpn_onprem_primary_config` and `vpn_onprem_secondary_config` variables, using router or tunnel custom advertisements.
## Customizations
@@ -488,11 +468,11 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [gcp_ranges](variables.tf#L111) | GCP address ranges in name => range format. | map(string)
| | {…}
| |
| [onprem_cidr](variables.tf#L126) | Onprem addresses in name => range format. | map(string)
| | {…}
| |
| [outputs_location](variables.tf#L144) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
-| [psa_ranges](variables.tf#L161) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…})
| | null
| |
-| [regions](variables.tf#L178) | Region definitions. | object({…})
| | {…}
| |
-| [service_accounts](variables.tf#L190) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
-| [vpn_onprem_primary_config](variables.tf#L204) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
-| [vpn_onprem_secondary_config](variables.tf#L247) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…})
| | null
| |
+| [psa_ranges](variables.tf#L161) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…})
| | null
| |
+| [regions](variables.tf#L180) | Region definitions. | object({…})
| | {…}
| |
+| [service_accounts](variables.tf#L192) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
+| [vpn_onprem_primary_config](variables.tf#L206) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
+| [vpn_onprem_secondary_config](variables.tf#L249) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…})
| | null
| |
## Outputs
diff --git a/fast/stages/2-networking-c-nva/variables.tf b/fast/stages/2-networking-c-nva/variables.tf
index 0780cfd9..508584d0 100644
--- a/fast/stages/2-networking-c-nva/variables.tf
+++ b/fast/stages/2-networking-c-nva/variables.tf
@@ -162,14 +162,16 @@ variable "psa_ranges" {
description = "IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format."
type = object({
dev = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
prod = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
})
default = null
diff --git a/fast/stages/2-networking-d-separate-envs/README.md b/fast/stages/2-networking-d-separate-envs/README.md
index 3473e778..e84530e8 100644
--- a/fast/stages/2-networking-d-separate-envs/README.md
+++ b/fast/stages/2-networking-d-separate-envs/README.md
@@ -112,15 +112,12 @@ This configuration is battle-tested, and flexible enough to lend itself to simpl
### VPCs
VPCs are defined in separate files, one for each of `prod` and `dev`.
-Each file contains the same resources, described in the following paragraphs.
-The **project** ([`project`](../../../modules/project)) contains the VPC, and enables the required APIs and sets itself as a "[host project](https://cloud.google.com/vpc/docs/shared-vpc)".
+These files contain different resources:
-The **VPC** ([`net-vpc`](../../../modules/net-vpc)) manages the DNS inbound policy, explicit routes for `{private,restricted}.googleapis.com`, and its **subnets**. Subnets are created leveraging a "resource factory" paradigm, where the configuration is separated from the module that implements it, and stored in a well-structured file. To add a new subnet, simply create a new file in the `data_folder` directory defined in the module, following the examples found in the [Fabric `net-vpc` documentation](../../../modules/net-vpc#subnet-factory). Sample subnets are shipped in [data/subnets](./data/subnets), and can be easily customised to fit your needs.
-
-Subnets for [L7 ILBs](https://cloud.google.com/load-balancing/docs/l7-internal/proxy-only-subnets) are handled differently, and defined in variable `l7ilb_subnets`, while ranges for [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by variable `psa_ranges` - such variables are consumed by spoke VPCs.
-
-**Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
+- **project** ([`project`](../../../modules/project)) contains the VPC, and enables the required APIs and sets itself as a "[host project](https://cloud.google.com/vpc/docs/shared-vpc)".
+- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manages the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy for the trusted landing VPC. Non-infrastructural subnets are created leveraging resource factories. Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs. [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by the variable `psa_ranges` if managed services are needed.
+- **Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) manages the networking infrastructure required to enable internet egress.
### VPNs
@@ -244,17 +241,12 @@ terraform apply
#### Private Google Access
-[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment.
+[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment:
-For PGA to work:
+- DNS response policies in the landing project implement rules for all supported domains reachable via PGA
+- routes for the private and restricted ranges are defined in all VPCs
-- Private Google Access should be enabled on the subnet. \
-Subnets created by the `net-vpc` module are PGA-enabled by default.
-
-- 199.36.153.4/30 (`restricted.googleapis.com`) and 199.36.153.8/30 (`private.googleapis.com`) should be routed from on-prem to VPC, and from there to the `default-internet-gateway`. \
-Per variable `vpn_onprem_configs` such ranges are advertised to onprem - furthermore every VPC has explicit routes set in case the `0.0.0.0/0` route is changed.
-
-- A private DNS zone for `googleapis.com` should be created and configured per [this article](https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid#config-domain)
+To enable PGA access from on premises advertise the private/restricted ranges via the `vpn_onprem_dev_primary_config` and `vpn_onprem_prod_primary_config` variables, using router or tunnel custom advertisements.
## Customizations
@@ -348,11 +340,11 @@ Regions are defined via the `regions` variable which sets up a mapping between t
| [dns](variables.tf#L72) | Onprem DNS resolvers. | map(list(string))
| | {…}
| |
| [factories_config](variables.tf#L81) | Configuration for network resource factories. | object({…})
| | {…}
| |
| [outputs_location](variables.tf#L122) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
-| [psa_ranges](variables.tf#L139) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…})
| | null
| |
-| [regions](variables.tf#L156) | Region definitions. | object({…})
| | {…}
| |
-| [service_accounts](variables.tf#L166) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
-| [vpn_onprem_dev_primary_config](variables.tf#L180) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…})
| | null
| |
-| [vpn_onprem_prod_primary_config](variables.tf#L223) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…})
| | null
| |
+| [psa_ranges](variables.tf#L139) | IP ranges used for Private Service Access (e.g. CloudSQL). | object({…})
| | null
| |
+| [regions](variables.tf#L158) | Region definitions. | object({…})
| | {…}
| |
+| [service_accounts](variables.tf#L168) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
+| [vpn_onprem_dev_primary_config](variables.tf#L182) | VPN gateway configuration for onprem interconnection from dev in the primary region. | object({…})
| | null
| |
+| [vpn_onprem_prod_primary_config](variables.tf#L225) | VPN gateway configuration for onprem interconnection from prod in the primary region. | object({…})
| | null
| |
## Outputs
diff --git a/fast/stages/2-networking-d-separate-envs/variables.tf b/fast/stages/2-networking-d-separate-envs/variables.tf
index 8edcd72c..d8cb8d83 100644
--- a/fast/stages/2-networking-d-separate-envs/variables.tf
+++ b/fast/stages/2-networking-d-separate-envs/variables.tf
@@ -140,14 +140,16 @@ variable "psa_ranges" {
description = "IP ranges used for Private Service Access (e.g. CloudSQL)."
type = object({
dev = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
prod = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
})
default = null
diff --git a/fast/stages/2-networking-e-nva-bgp/README.md b/fast/stages/2-networking-e-nva-bgp/README.md
index 3b00bdd8..4b3d6fad 100644
--- a/fast/stages/2-networking-e-nva-bgp/README.md
+++ b/fast/stages/2-networking-e-nva-bgp/README.md
@@ -148,19 +148,7 @@ This stage uses a dedicated /11 block (10.64.0.0/11), which should be sized to t
The /11 block is evenly split in eight, smaller /16 blocks, assigned to different areas of the GCP network: *landing untrusted europe-west1*, *landing untrusted europe-west4*, *landing trusted europe-west1*, *landing untrusted europe-west4*, *development europe-west1*, *development europe-west4*, *production europe-west1*, *production europe-west4*.
-The first /24 range in every area is allocated for a default subnet, which can be removed or modified as needed.
-
-Spoke VPCs also define and reserve three "special" CIDR ranges, derived from their respective /16, dedicated to
-
-- [PSA (Private Service Access)](https://cloud.google.com/vpc/docs/private-services-access):
-
- - The second-last /24 range is used for PSA (CloudSQL, Postrgres)
-
- - The third-last /24 range is used for PSA (CloudSQL, MySQL)
-
-- [Internal Application Load Balancers (L7 LBs)](https://cloud.google.com/load-balancing/docs/l7-internal):
-
- - The last /24 range
+The first /24 range in every area is allocated for a default subnet, which can be removed or modified as needed. The last three /24 ranges can be used for [PSA (Private Service Access)](https://cloud.google.com/vpc/docs/private-services-access)via the `psa_ranges` variable, or for [Internal Application Load Balancers (L7 LBs)](https://cloud.google.com/load-balancing/docs/l7-internal) subnets via the factory.
This is a summary of the subnets allocated by default in this setup:
@@ -171,23 +159,23 @@ This is a summary of the subnets allocated by default in this setup:
| landing-untrusted-default-ew1 | Untrusted landing subnet - europe-west1 | 10.128.0.0/24 |
| landing-untrusted-default-ew4 | Untrusted landing subnet - europe-west4 | 10.128.32.0/24 |
| dev-default-ew1 | Dev spoke subnet - europe-west1 | 10.68.0.0/24 |
-| dev-default-ew1 (PSA MySQL) | PSA subnet for MySQL in dev spoke - europe-west1 | 10.68.253.0/24 |
-| dev-default-ew1 (PSA SQL Server) | PSA subnet for Postgres in dev spoke - europe-west1 | 10.68.254.0/24 |
-| dev-default-ew1 (L7 ILB) | L7 ILB subnet for dev spoke - europe-west1 | 10.68.255.0/24 |
+| dev-default-ew1 | Free (PSA) - europe-west1 | 10.68.253.0/24 |
+| dev-default-ew1 | Free (PSA) - europe-west1 | 10.68.254.0/24 |
+| dev-default-ew1 | Free (L7 ILB) - europe-west1 | 10.68.255.0/24 |
| dev-default-ew4 | Dev spoke subnet - europe-west4 | 10.84.0.0/24 |
-| dev-default-ew4 (PSA MySQL) | PSA subnet for MySQL in dev spoke - europe-west4 | 10.84.253.0/24 |
-| dev-default-ew4 (PSA SQL Server) | PSA subnet for Postgres in dev spoke - europe-west4 | 10.84.254.0/24 |
-| dev-default-ew4 (L7 ILB) | L7 ILB subnet for dev spoke - europe-west4 | 10.84.255.0/24 |
+| dev-default-ew4 | Free (PSA) - europe-west4 | 10.84.253.0/24 |
+| dev-default-ew4 | Free (PSA) - europe-west4 | 10.84.254.0/24 |
+| dev-default-ew4 | Free (L7 ILB) - europe-west4 | 10.84.255.0/24 |
| prod-default-ew1 | Prod spoke subnet - europe-west1 | 10.72.0.0/24 |
-| prod-default-ew1 (PSA MySQL) | PSA subnet for MySQL in prod spoke - europe-west1 | 10.72.253.0/24 |
-| prod-default-ew1 (PSA SQL Server) | PSA subnet for Postgres in prod spoke - europe-west1 | 10.72.254.0/24 |
-| prod-default-ew1 (L7 ILB) | L7 ILB subnet for prod spoke - europe-west1 | 10.72.255.0/24 |
+| prod-default-ew1 | Free (PSA) - europe-west1 | 10.72.253.0/24 |
+| prod-default-ew1 | Free (PSA) - europe-west1 | 10.72.254.0/24 |
+| prod-default-ew1 | Free (L7 ILB) - europe-west1 | 10.72.255.0/24 |
| prod-default-ew4 | Prod spoke subnet - europe-west4 | 10.88.0.0/24 |
-| prod-default-ew4 (PSA MySQL) | PSA subnet for MySQL in prod spoke - europe-west4 | 10.88.253.0/24 |
-| prod-default-ew4 (PSA SQL Server) | PSA subnet for Postgres in prod spoke - europe-west4 | 10.88.254.0/24 |
-| prod-default-ew4 (L7 ILB) | L7 ILB subnet for prod spoke - europe-west4 | 10.88.255.0/24 |
+| prod-default-ew4 | Free (PSA) - europe-west4 | 10.88.253.0/24 |
+| prod-default-ew4 | Free (PSA) - europe-west4 | 10.88.254.0/24 |
+| prod-default-ew4 | Free (L7 ILB) - europe-west4 | 10.88.255.0/24 |
-These subnets can advertised to on-premises as an aggregate /11 range (10.64.0.0/11). Refer to the `var.vpn_onprem_primary_config.router_config` and `var.vpn_onprem_secondary_config.router_config` variables to configure it.
+These subnets can be advertised to on-premises as an aggregate /11 range (10.64.0.0/11). Refer to the `var.vpn_onprem_primary_config.router_config` and `var.vpn_onprem_secondary_config.router_config` variables to configure it.
Routes in GCP are either automatically created (for example, when a subnet is added to a VPC), manually created via static routes, dynamically exchanged through VPC peerings, or dynamically programmed by [Cloud Routers](https://cloud.google.com/network-connectivity/docs/router#docs) when a BGP session is established. BGP sessions can be configured to advertise VPC ranges, and/or custom ranges via custom advertisements.
@@ -252,10 +240,7 @@ VPCs are defined in separate files, one for `landing` (trusted and untrusted), o
These files contain different resources:
- **project** ([`projects`](../../../modules/project)): the "[host projects](https://cloud.google.com/vpc/docs/shared-vpc)" containing the VPCs and enabling the required APIs.
-- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manage the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy (for the trusted landing VPC). Subnets are created leveraging "resource factories": the configuration is separated from the module that implements it, and stored in a well-structured file. To add a new subnet, simply create a new file in the `data_folder` directory defined in the module, following the examples found in the [Fabric `net-vpc` documentation](../../../modules/net-vpc#subnet-factory). Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs.
-
-Subnets for [L7 ILBs](https://cloud.google.com/load-balancing/docs/l7-internal/proxy-only-subnets) are handled differently, and defined in variable `l7ilb_subnets`, while ranges for [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by variable `psa_ranges` - such variables are consumed by spoke VPCs.
-
+- **VPCs** ([`net-vpc`](../../../modules/net-vpc)): manages the subnets, the explicit routes for `{private,restricted}.googleapis.com` and the DNS inbound policy for the trusted landing VPC. Non-infrastructural subnets are created leveraging resource factories. Sample subnets are shipped in [data/subnets](./data/subnets) and can be easily customized to fit users' needs. [PSA](https://cloud.google.com/vpc/docs/configure-private-services-access#allocating-range) are configured by the variable `psa_ranges` if managed services are needed.
- **Cloud NAT** ([`net-cloudnat`](../../../modules/net-cloudnat)) (in the untrusted landing VPC only): it manages the networking infrastructure required to enable the Internet egress.
### VPNs
@@ -387,17 +372,12 @@ terraform apply
#### Private Google Access
-[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment.
+[Private Google Access](https://cloud.google.com/vpc/docs/private-google-access) (or PGA) enables VMs and on-prem systems to consume Google APIs from within the Google network, and is already fully configured on this environment:
-For PGA to work:
+- DNS response policies in the landing project implement rules for all supported domains reachable via PGA
+- routes for the private and restricted ranges are defined in all VPCs except untrusted
-- Private Google Access should be enabled on the subnet. \
-Subnets created by the `net-vpc` module are PGA-enabled by default.
-
-- 199.36.153.4/30 (`restricted.googleapis.com`) and 199.36.153.8/30 (`private.googleapis.com`) should be routed from on-prem to VPC, and from there to the `default-internet-gateway`. \
-Per variable `vpn_onprem_configs` such ranges are advertised to onprem - furthermore every VPC (e.g. see `landing-vpc` in [`landing.tf`](./landing.tf)) has explicit routes set in case the `0.0.0.0/0` route is changed.
-
-- A private DNS zone for `googleapis.com` should be created and configured per [this article](https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid#config-domain), as implemented in module `googleapis-private-zone` in [`dns-landing.tf`](./dns-landing.tf)
+To enable PGA access from on premises advertise the private/restricted ranges via the `vpn_onprem_primary_config` and `vpn_onprem_secondary_config` variables, using router or tunnel custom advertisements.
## Customizations
@@ -515,12 +495,12 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [ncc_asn](variables.tf#L126) | The NCC Cloud Routers ASN configuration. | map(number)
| | {…}
| |
| [onprem_cidr](variables.tf#L137) | Onprem addresses in name => range format. | map(string)
| | {…}
| |
| [outputs_location](variables.tf#L155) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string
| | null
| |
-| [psa_ranges](variables.tf#L172) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…})
| | null
| |
-| [regions](variables.tf#L189) | Region definitions. | object({…})
| | {…}
| |
-| [service_accounts](variables.tf#L201) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
-| [vpn_onprem_primary_config](variables.tf#L215) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
-| [vpn_onprem_secondary_config](variables.tf#L258) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…})
| | null
| |
-| [zones](variables.tf#L301) | Zones in which NVAs are deployed. | list(string)
| | ["b", "c"]
| |
+| [psa_ranges](variables.tf#L172) | IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format. | object({…})
| | null
| |
+| [regions](variables.tf#L191) | Region definitions. | object({…})
| | {…}
| |
+| [service_accounts](variables.tf#L203) | Automation service accounts in name => email format. | object({…})
| | null
| 1-resman
|
+| [vpn_onprem_primary_config](variables.tf#L217) | VPN gateway configuration for onprem interconnection in the primary region. | object({…})
| | null
| |
+| [vpn_onprem_secondary_config](variables.tf#L260) | VPN gateway configuration for onprem interconnection in the secondary region. | object({…})
| | null
| |
+| [zones](variables.tf#L303) | Zones in which NVAs are deployed. | list(string)
| | ["b", "c"]
| |
## Outputs
diff --git a/fast/stages/2-networking-e-nva-bgp/variables.tf b/fast/stages/2-networking-e-nva-bgp/variables.tf
index 7ae8c048..3e443c44 100644
--- a/fast/stages/2-networking-e-nva-bgp/variables.tf
+++ b/fast/stages/2-networking-e-nva-bgp/variables.tf
@@ -173,14 +173,16 @@ variable "psa_ranges" {
description = "IP ranges used for Private Service Access (e.g. CloudSQL). Ranges is in name => range format."
type = object({
dev = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
prod = object({
- ranges = map(string)
- export_routes = optional(bool, false)
- import_routes = optional(bool, false)
+ ranges = map(string)
+ export_routes = optional(bool, false)
+ import_routes = optional(bool, false)
+ peered_domains = optional(list(string), [])
})
})
default = null
diff --git a/modules/README.md b/modules/README.md
index 44df93be..4fbbd140 100644
--- a/modules/README.md
+++ b/modules/README.md
@@ -30,14 +30,14 @@ These modules are used in the examples included in this repository. If you are u
## Foundational modules
-- [billing budget](./billing-budget)
+- [Billing account](./billing-account)
- [Cloud Identity group](./cloud-identity-group/)
-- [folder](./folder)
-- [service accounts](./iam-service-account)
-- [logging bucket](./logging-bucket)
-- [organization](./organization)
-- [project](./project)
-- [projects-data-source](./projects-data-source)
+- [Folder](./folder)
+- [Service accounts](./iam-service-account)
+- [Logging bucket](./logging-bucket)
+- [Organization](./organization)
+- [Project](./project)
+- [Projects (data source)](./projects-data-source)
## Networking modules
diff --git a/modules/billing-account/README.md b/modules/billing-account/README.md
new file mode 100644
index 00000000..f5fd4e2f
--- /dev/null
+++ b/modules/billing-account/README.md
@@ -0,0 +1,237 @@
+# Billing Account Module
+
+This module allows managing resources and policies related to a billing account:
+
+- IAM bindings
+- log sinks
+- billing budgets and their notifications
+
+Managing billing-related resources via application default credentials [requires a billing project to be set](https://cloud.google.com/docs/authentication/troubleshoot-adc#user-creds-client-based). To configure one via Terraform you can use a snippet similar to this one:
+
+```hcl
+provider "google" {
+ billing_project = "my-project"
+ user_project_override = true
+}
+# tftest skip
+```
+
+
+- [Examples](#examples)
+ - [IAM bindings](#iam-bindings)
+ - [Log sinks](#log-sinks)
+ - [Billing budgets](#billing-budgets)
+ - [PubSub update rules](#pubsub-update-rules)
+ - [Monitoring channels](#monitoring-channels)
+- [Variables](#variables)
+- [Outputs](#outputs)
+
+
+## Examples
+
+### IAM bindings
+
+Billing account IAM bindings implement [the same interface](../__docs/20230816-iam-refactor.md) used for all other modules.
+
+```hcl
+module "billing-account" {
+ source = "./fabric/modules/billing-account"
+ id = "012345-ABCDEF-012345"
+ group_iam = {
+ "billing-admins@example.org" = ["roles/billing.admin"]
+ }
+ iam = {
+ "roles/billing.admin" = [
+ "serviceAccount:foo@myprj.iam.gserviceaccount.com"
+ ]
+ }
+ iam_bindings = {
+ conditional-admin = {
+ members = [
+ "serviceAccount:pf-dev@myprj.iam.gserviceaccount.com"
+ ]
+ role = "roles/billing.admin"
+ condition = {
+ title = "pf-dev-conditional-billing-admin"
+ expression = (
+ "resource.matchTag('123456/environment', 'development')"
+ )
+ }
+ }
+ }
+ iam_bindings_additive = {
+ sa-net-iac-user = {
+ member = "serviceAccount:net-iac-0@myprj.iam.gserviceaccount.com"
+ role = "roles/billing.user"
+ }
+ }
+}
+# tftest modules=1 resources=3 inventory=iam.yaml
+```
+
+### Log sinks
+
+Billing account log sinks use the same format used for log sinks in the resource manager modules (organization, folder, project).
+
+```hcl
+module "log-bucket-all" {
+ source = "./fabric/modules/logging-bucket"
+ parent_type = "project"
+ parent = "myprj"
+ id = "billing-account-all"
+}
+
+module "billing-account" {
+ source = "./fabric/modules/billing-account"
+ id = "012345-ABCDEF-012345"
+ logging_sinks = {
+ all = {
+ destination = module.log-bucket-all.id
+ type = "logging"
+ }
+ }
+}
+# tftest modules=2 resources=3 inventory=logging.yaml
+```
+
+### Billing budgets
+
+Billing budgets expose all the attributes of the underlying resource, and allow using external notification channels, or creating them via this same module.
+
+```hcl
+module "billing-account" {
+ source = "./fabric/modules/billing-account"
+ id = "012345-ABCDEF-012345"
+ budgets = {
+ folder-net-month-current-100 = {
+ display_name = "100 dollars in current spend"
+ amount = {
+ units = 100
+ }
+ filter = {
+ period = {
+ calendar = "MONTH"
+ }
+ resource_ancestors = ["folders/1234567890"]
+ }
+ threshold_rules = [
+ { percent = 0.5 },
+ { percent = 0.75 }
+ ]
+ }
+ }
+}
+# tftest modules=1 resources=1 inventory=budget-simple.yaml
+```
+
+#### PubSub update rules
+
+Update rules can notify pubsub topics.
+
+```hcl
+module "pubsub-billing-topic" {
+ source = "./fabric/modules/pubsub"
+ project_id = "my-prj"
+ name = "budget-default"
+}
+
+module "billing-account" {
+ source = "./fabric/modules/billing-account"
+ id = "012345-ABCDEF-012345"
+ budgets = {
+ folder-net-month-current-100 = {
+ display_name = "100 dollars in current spend"
+ amount = {
+ units = 100
+ }
+ filter = {
+ period = {
+ calendar = "MONTH"
+ }
+ resource_ancestors = ["folders/1234567890"]
+ }
+ threshold_rules = [
+ { percent = 0.5 },
+ { percent = 0.75 }
+ ]
+ update_rules = {
+ default = {
+ pubsub_topic = module.pubsub-billing-topic.id
+ }
+ }
+ }
+ }
+}
+# tftest modules=2 resources=2 inventory=budget-pubsub.yaml
+```
+
+#### Monitoring channels
+
+Monitoring channels can be referenced in update rules either by passing in an existing channel id, or by using a reference to a key in the `budget_notification_channels` variable, that allows managing ad hoc monitoring channels.
+
+
+
+```hcl
+module "billing-account" {
+ source = "./fabric/modules/billing-account"
+ id = "012345-ABCDEF-012345"
+ budget_notification_channels = {
+ billing-default = {
+ project_id = "tf-playground-simple"
+ type = "email"
+ labels = {
+ email_address = "gcp-billing-admins@example.com"
+ }
+ }
+ }
+ budgets = {
+ folder-net-month-current-100 = {
+ display_name = "100 dollars in current spend"
+ amount = {
+ units = 100
+ }
+ filter = {
+ period = {
+ calendar = "MONTH"
+ }
+ resource_ancestors = ["folders/1234567890"]
+ }
+ threshold_rules = [
+ { percent = 0.5 },
+ { percent = 0.75 }
+ ]
+ update_rules = {
+ default = {
+ disable_default_iam_recipients = true
+ monitoring_notification_channels = ["billing-default"]
+ }
+ }
+ }
+ }
+}
+# tftest modules=1 resources=2 inventory=budget-monitoring-channel.yaml
+```
+
+
+
+## Variables
+
+| name | description | type | required | default |
+|---|---|:---:|:---:|:---:|
+| [id](variables.tf#L165) | Billing account id. | string
| ✓ | |
+| [budget_notification_channels](variables.tf#L17) | Notification channels used by budget alerts. | map(object({…}))
| | {}
|
+| [budgets](variables.tf#L47) | Billing budgets. Notification channels are either keys in corresponding variable, or external ids. | map(object({…}))
| | {}
|
+| [group_iam](variables.tf#L121) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | map(list(string))
| | {}
|
+| [iam](variables.tf#L128) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
+| [iam_bindings](variables.tf#L135) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…}))
| | {}
|
+| [iam_bindings_additive](variables.tf#L150) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
+| [logging_sinks](variables.tf#L170) | Logging sinks to create for the organization. | map(object({…}))
| | {}
|
+| [projects](variables.tf#L203) | Projects associated with this billing account. | list(string)
| | []
|
+
+## Outputs
+
+| name | description | sensitive |
+|---|---|:---:|
+| [billing_budget_ids](outputs.tf#L17) | Billing budget ids. | |
+| [monitoring_notification_channel_ids](outputs.tf#L25) | Monitoring notification channel ids. | |
+
diff --git a/modules/billing-account/budgets.tf b/modules/billing-account/budgets.tf
new file mode 100644
index 00000000..a1aed400
--- /dev/null
+++ b/modules/billing-account/budgets.tf
@@ -0,0 +1,126 @@
+/**
+ * Copyright 2023 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.
+ */
+
+resource "google_monitoring_notification_channel" "default" {
+ for_each = var.budget_notification_channels
+ description = each.value.description
+ display_name = coalesce(
+ each.value.display_name, "Budget email notification ${each.key}."
+ )
+ project = each.value.project_id
+ enabled = each.value.enabled
+ force_delete = each.value.force_delete
+ type = each.value.type
+ labels = each.value.labels
+ user_labels = each.value.user_labels
+ dynamic "sensitive_labels" {
+ for_each = toset(coalesce(each.value.sensitive_labels, []))
+ content {
+ auth_token = sensitive_labels.value.auth_token
+ password = sensitive_labels.value.password
+ service_key = sensitive_labels.value.service_key
+ }
+ }
+}
+
+resource "google_billing_budget" "default" {
+ for_each = var.budgets
+ billing_account = var.id
+ display_name = each.value.display_name
+ dynamic "amount" {
+ for_each = each.value.amount.use_last_period == true ? [""] : []
+ content {
+ last_period_amount = true
+ }
+ }
+ dynamic "amount" {
+ for_each = each.value.amount.use_last_period != true ? [""] : []
+ content {
+ specified_amount {
+ currency_code = each.value.amount.currency_code
+ nanos = each.value.amount.nanos
+ units = each.value.amount.units
+ }
+ }
+ }
+ budget_filter {
+ calendar_period = try(each.value.filter.period.calendar, null)
+ credit_types_treatment = (
+ try(each.value.filter.credit_types_treatment.exclude_all, null) == true
+ ? "EXCLUDE_ALL_CREDITS"
+ : (
+ try(each.value.filter.credit_types_treatment.include_specified, null) != null
+ ? "INCLUDE_SPECIFIED_CREDITS"
+ : "INCLUDE_ALL_CREDITS"
+ )
+ )
+ labels = each.value.filter.label == null ? null : {
+ (each.value.filter.label.key) = each.value.filter.label.value
+ }
+ projects = each.value.filter.projects
+ resource_ancestors = each.value.filter.resource_ancestors
+ services = each.value.filter.services
+ subaccounts = each.value.filter.subaccounts
+ dynamic "custom_period" {
+ for_each = try(each.value.filter.period.custom, null) != null ? [""] : []
+ content {
+ start_date {
+ day = each.value.filter.period.custom.start_date.day
+ month = each.value.filter.period.custom.start_date.month
+ year = each.value.filter.period.custom.start_date.year
+ }
+ dynamic "end_date" {
+ for_each = try(each.value.filter.period.custom.end_date, null) != null ? [""] : []
+ content {
+ day = each.value.filter.period.custom.end_date.day
+ month = each.value.filter.period.custom.end_date.month
+ year = each.value.filter.period.custom.end_date.year
+ }
+ }
+ }
+ }
+ }
+ dynamic "threshold_rules" {
+ for_each = toset(each.value.threshold_rules)
+ iterator = rule
+ content {
+ threshold_percent = rule.value.percent
+ spend_basis = (
+ rule.value.forecasted_spend == true
+ ? "FORECASTED_SPEND"
+ : "CURRENT_SPEND"
+ )
+ }
+ }
+ dynamic "all_updates_rule" {
+ for_each = each.value.update_rules
+ iterator = rule
+ content {
+ pubsub_topic = rule.value.pubsub_topic
+ schema_version = "1.0"
+ disable_default_iam_recipients = rule.value.disable_default_iam_recipients
+ monitoring_notification_channels = (
+ rule.value.monitoring_notification_channels == null
+ ? null
+ : [
+ for v in rule.value.monitoring_notification_channels : try(
+ google_monitoring_notification_channel.default[v].id, v
+ )
+ ]
+ )
+ }
+ }
+}
diff --git a/modules/billing-account/iam.tf b/modules/billing-account/iam.tf
new file mode 100644
index 00000000..d8cec258
--- /dev/null
+++ b/modules/billing-account/iam.tf
@@ -0,0 +1,70 @@
+/**
+ * Copyright 2022 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.
+ */
+
+# tfdoc:file:description IAM bindings.
+
+locals {
+ _group_iam_roles = distinct(flatten(values(var.group_iam)))
+ _group_iam = {
+ for r in local._group_iam_roles : r => [
+ for k, v in var.group_iam : "group:${k}" if try(index(v, r), null) != null
+ ]
+ }
+ iam = {
+ for role in distinct(concat(keys(var.iam), keys(local._group_iam))) :
+ role => concat(
+ try(var.iam[role], []),
+ try(local._group_iam[role], [])
+ )
+ }
+}
+
+resource "google_billing_account_iam_binding" "authoritative" {
+ for_each = local.iam
+ billing_account_id = var.id
+ role = each.key
+ members = each.value
+}
+
+resource "google_billing_account_iam_binding" "bindings" {
+ for_each = var.iam_bindings
+ billing_account_id = var.id
+ role = each.value.role
+ members = each.value.members
+ 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_billing_account_iam_member" "bindings" {
+ for_each = var.iam_bindings_additive
+ billing_account_id = var.id
+ role = each.value.role
+ member = each.value.member
+ 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/billing-account/logging.tf b/modules/billing-account/logging.tf
new file mode 100644
index 00000000..9c96ea93
--- /dev/null
+++ b/modules/billing-account/logging.tf
@@ -0,0 +1,92 @@
+/**
+ * Copyright 2023 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.
+ */
+
+# tfdoc:file:description Log sinks and supporting resources.
+
+locals {
+ sink_bindings = {
+ for type in ["bigquery", "pubsub", "logging", "storage"] :
+ type => {
+ for name, sink in var.logging_sinks :
+ name => sink
+ if sink.type == type
+ }
+ }
+}
+
+resource "google_logging_billing_account_sink" "sink" {
+ for_each = var.logging_sinks
+ name = each.key
+ description = coalesce(each.value.description, "${each.key} (Terraform-managed).")
+ billing_account = var.id
+ destination = "${each.value.type}.googleapis.com/${each.value.destination}"
+ filter = each.value.filter
+ disabled = each.value.disabled
+
+ dynamic "bigquery_options" {
+ for_each = each.value.type == "biquery" && each.value.bq_partitioned_table != false ? [""] : []
+ content {
+ use_partitioned_tables = each.value.bq_partitioned_table
+ }
+ }
+
+ dynamic "exclusions" {
+ for_each = each.value.exclusions
+ iterator = exclusion
+ content {
+ name = exclusion.key
+ filter = exclusion.value.filter
+ description = exclusion.value.description
+ disabled = exclusion.value.disabled
+ }
+ }
+}
+
+resource "google_storage_bucket_iam_member" "gcs-sinks-binding" {
+ for_each = local.sink_bindings["storage"]
+ bucket = each.value.destination
+ role = "roles/storage.objectCreator"
+ member = google_logging_billing_account_sink.sink[each.key].writer_identity
+}
+
+resource "google_bigquery_dataset_iam_member" "bq-sinks-binding" {
+ for_each = local.sink_bindings["bigquery"]
+ project = split("/", each.value.destination)[1]
+ dataset_id = split("/", each.value.destination)[3]
+ role = "roles/bigquery.dataEditor"
+ member = google_logging_billing_account_sink.sink[each.key].writer_identity
+}
+
+resource "google_pubsub_topic_iam_member" "pubsub-sinks-binding" {
+ for_each = local.sink_bindings["pubsub"]
+ project = split("/", each.value.destination)[1]
+ topic = split("/", each.value.destination)[3]
+ role = "roles/pubsub.publisher"
+ member = google_logging_billing_account_sink.sink[each.key].writer_identity
+}
+
+resource "google_project_iam_member" "bucket-sinks-binding" {
+ for_each = local.sink_bindings["logging"]
+ project = split("/", each.value.destination)[1]
+ role = "roles/logging.bucketWriter"
+ member = google_logging_billing_account_sink.sink[each.key].writer_identity
+
+ condition {
+ title = "${each.key} bucket writer"
+ description = "Grants bucketWriter to ${google_logging_billing_account_sink.sink[each.key].writer_identity} used by log sink ${each.key} on billing account ${var.id}"
+ expression = "resource.name.endsWith('${each.value.destination}')"
+ }
+}
diff --git a/modules/billing-budget/outputs.tf b/modules/billing-account/main.tf
similarity index 70%
rename from modules/billing-budget/outputs.tf
rename to modules/billing-account/main.tf
index 530f8573..f477cbb4 100644
--- a/modules/billing-budget/outputs.tf
+++ b/modules/billing-account/main.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2023 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,12 +14,8 @@
* limitations under the License.
*/
-output "budget" {
- description = "Budget resource."
- value = google_billing_budget.budget
-}
-
-output "id" {
- description = "Fully qualified budget id."
- value = google_billing_budget.budget.id
+resource "google_billing_project_info" "default" {
+ for_each = toset(var.projects)
+ billing_account = var.id
+ project = each.key
}
diff --git a/modules/billing-account/outputs.tf b/modules/billing-account/outputs.tf
new file mode 100644
index 00000000..f8359c53
--- /dev/null
+++ b/modules/billing-account/outputs.tf
@@ -0,0 +1,31 @@
+/**
+ * Copyright 2023 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 "billing_budget_ids" {
+ description = "Billing budget ids."
+ value = {
+ for k, v in google_billing_budget.default :
+ k => v.id
+ }
+}
+
+output "monitoring_notification_channel_ids" {
+ description = "Monitoring notification channel ids."
+ value = {
+ for k, v in google_monitoring_notification_channel.default :
+ k => v.id
+ }
+}
diff --git a/modules/billing-account/variables.tf b/modules/billing-account/variables.tf
new file mode 100644
index 00000000..6d949ea6
--- /dev/null
+++ b/modules/billing-account/variables.tf
@@ -0,0 +1,208 @@
+/**
+ * Copyright 2023 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 "budget_notification_channels" {
+ description = "Notification channels used by budget alerts."
+ type = map(object({
+ project_id = string
+ type = string
+ description = optional(string)
+ display_name = optional(string)
+ enabled = optional(bool, true)
+ force_delete = optional(bool)
+ labels = optional(map(string))
+ sensitive_labels = optional(list(object({
+ auth_token = optional(string)
+ password = optional(string)
+ service_key = optional(string)
+ })))
+ user_labels = optional(map(string))
+ }))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue([
+ for k, v in var.budget_notification_channels : contains([
+ "campfire", "email", "google_chat", "hipchat", "pagerduty",
+ "pubsub", "slack", "sms", "webhook_basicauth", "webhook_tokenauth"
+ ], v.type)
+ ])
+ error_message = "Invalid notification channel type."
+ }
+}
+
+variable "budgets" {
+ description = "Billing budgets. Notification channels are either keys in corresponding variable, or external ids."
+ type = map(object({
+ amount = object({
+ currency_code = optional(string)
+ nanos = optional(number)
+ units = optional(number)
+ use_last_period = optional(bool)
+ })
+ display_name = optional(string)
+ filter = optional(object({
+ credit_types_treatment = optional(object({
+ exclude_all = optional(bool)
+ include_specified = optional(list(string))
+ }))
+ label = optional(object({
+ key = string
+ value = string
+ }))
+ period = optional(object({
+ calendar = optional(string)
+ custom = optional(object({
+ start_date = object({
+ day = number
+ month = number
+ year = number
+ })
+ end_date = optional(object({
+ day = number
+ month = number
+ year = number
+ }))
+ }))
+ }))
+ projects = optional(list(string))
+ resource_ancestors = optional(list(string))
+ services = optional(list(string))
+ subaccounts = optional(list(string))
+ }))
+ threshold_rules = optional(list(object({
+ percent = number
+ forecasted_spend = optional(bool)
+ })), [])
+ update_rules = optional(map(object({
+ disable_default_iam_recipients = optional(bool)
+ monitoring_notification_channels = optional(list(string))
+ pubsub_topic = optional(string)
+ })), {})
+ }))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue([
+ for k, v in var.budgets : v.amount != null && (
+ try(v.amount.use_last_period, null) == true ||
+ try(v.amount.units, null) != null
+ )
+ ])
+ error_message = "Each budget needs to have amount units specified, or use last period."
+ }
+ validation {
+ condition = alltrue(flatten([
+ for k, v in var.budgets : [
+ for kk, vv in v.update_rules : [
+ vv.monitoring_notification_channels != null
+ ||
+ vv.pubsub_topic != null
+ ]
+ ]
+ ]))
+ error_message = "Budget notification rules need either a pubsub topic or monitoring channels defined."
+ }
+}
+
+variable "group_iam" {
+ description = "Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable."
+ type = map(list(string))
+ default = {}
+ nullable = false
+}
+
+variable "iam" {
+ description = "IAM bindings in {ROLE => [MEMBERS]} format."
+ type = map(list(string))
+ default = {}
+ nullable = false
+}
+
+variable "iam_bindings" {
+ description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary."
+ type = map(object({
+ members = list(string)
+ role = string
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ }))
+ nullable = false
+ default = {}
+}
+
+variable "iam_bindings_additive" {
+ description = "Individual additive IAM bindings. Keys are arbitrary."
+ type = map(object({
+ member = string
+ role = string
+ condition = optional(object({
+ expression = string
+ title = string
+ description = optional(string)
+ }))
+ }))
+ nullable = false
+ default = {}
+}
+
+variable "id" {
+ description = "Billing account id."
+ type = string
+}
+
+variable "logging_sinks" {
+ description = "Logging sinks to create for the organization."
+ type = map(object({
+ destination = string
+ type = string
+ bq_partitioned_table = optional(bool)
+ description = optional(string)
+ disabled = optional(bool, false)
+ exclusions = optional(map(object({
+ filter = string
+ description = optional(string)
+ disabled = optional(bool)
+ })), {})
+ filter = optional(string)
+ }))
+ default = {}
+ nullable = false
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ contains(["bigquery", "logging", "pubsub", "storage"], v.type)
+ ])
+ error_message = "Type must be one of 'bigquery', 'logging', '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 "projects" {
+ description = "Projects associated with this billing account."
+ type = list(string)
+ nullable = false
+ default = []
+}
diff --git a/modules/billing-budget/versions.tf b/modules/billing-account/versions.tf
similarity index 99%
rename from modules/billing-budget/versions.tf
rename to modules/billing-account/versions.tf
index 3963660f..3adb6d44 100644
--- a/modules/billing-budget/versions.tf
+++ b/modules/billing-account/versions.tf
@@ -25,5 +25,3 @@ terraform {
}
}
}
-
-
diff --git a/modules/billing-budget/README.md b/modules/billing-budget/README.md
deleted file mode 100644
index 72fe574b..00000000
--- a/modules/billing-budget/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# Google Cloud Billing Budget Module
-
-This module allows creating a Cloud Billing budget for a set of services and projects.
-
-To create billing budgets you need one of the following IAM roles on the target billing account:
-
-* Billing Account Administrator
-* Billing Account Costs Manager
-
-## Examples
-
-### Simple email notification
-
-Send a notification to an email when a set of projects reach $100 of spend.
-
-```hcl
-module "budget" {
- source = "./fabric/modules/billing-budget"
- billing_account = var.billing_account_id
- name = "$100 budget"
- amount = 100
- thresholds = {
- current = [0.5, 0.75, 1.0]
- forecasted = [1.0]
- }
- projects = [
- "projects/123456789000",
- "projects/123456789111"
- ]
- email_recipients = {
- project_id = "my-project"
- emails = ["user@example.com"]
- }
-}
-# tftest modules=1 resources=2 inventory=email.yaml
-```
-
-### Pubsub notification
-
-Send a notification to a PubSub topic the total spend of a billing account reaches the previous month's spend.
-
-
-```hcl
-module "budget" {
- source = "./fabric/modules/billing-budget"
- billing_account = var.billing_account_id
- name = "previous period budget"
- amount = 0
- thresholds = {
- current = [1.0]
- forecasted = []
- }
- pubsub_topic = module.pubsub.id
-}
-
-module "pubsub" {
- source = "./fabric/modules/pubsub"
- project_id = var.project_id
- name = "budget-topic"
-}
-
-# tftest modules=2 resources=2 inventory=pubsub.yaml
-```
-
-
-## Variables
-
-| name | description | type | required | default |
-|---|---|:---:|:---:|:---:|
-| [billing_account](variables.tf#L23) | Billing account id. | string
| ✓ | |
-| [name](variables.tf#L50) | Budget name. | string
| ✓ | |
-| [thresholds](variables.tf#L85) | Thresholds percentages at which alerts are sent. Must be a value between 0 and 1. | object({…})
| ✓ | |
-| [amount](variables.tf#L17) | Amount in the billing account's currency for the budget. Use 0 to set budget to 100% of last period's spend. | number
| | 0
|
-| [credit_treatment](variables.tf#L28) | How credits should be treated when determining spend for threshold calculations. Only INCLUDE_ALL_CREDITS or EXCLUDE_ALL_CREDITS are supported. | string
| | "INCLUDE_ALL_CREDITS"
|
-| [email_recipients](variables.tf#L41) | Emails where budget notifications will be sent. Setting this will create a notification channel for each email in the specified project. | object({…})
| | null
|
-| [notification_channels](variables.tf#L55) | Monitoring notification channels where to send updates. | list(string)
| | null
|
-| [notify_default_recipients](variables.tf#L61) | Notify Billing Account Administrators and Billing Account Users IAM roles for the target account. | bool
| | false
|
-| [projects](variables.tf#L67) | List of projects of the form projects/{project_number}, specifying that usage from only this set of projects should be included in the budget. Set to null to include all projects linked to the billing account. | list(string)
| | null
|
-| [pubsub_topic](variables.tf#L73) | The ID of the Cloud Pub/Sub topic where budget related messages will be published. | string
| | null
|
-| [services](variables.tf#L79) | List of services of the form services/{service_id}, specifying that usage from only this set of services should be included in the budget. Set to null to include usage for all services. | list(string)
| | null
|
-
-## Outputs
-
-| name | description | sensitive |
-|---|---|:---:|
-| [budget](outputs.tf#L17) | Budget resource. | |
-| [id](outputs.tf#L22) | Fully qualified budget id. | |
-
-
diff --git a/modules/billing-budget/main.tf b/modules/billing-budget/main.tf
deleted file mode 100644
index 2c6838dc..00000000
--- a/modules/billing-budget/main.tf
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Copyright 2022 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 {
- spend_basis = {
- current = "CURRENT_SPEND"
- forecasted = "FORECASTED_SPEND"
- }
- threshold_pairs = flatten([
- for type, values in var.thresholds : [
- for value in values : {
- spend_basis = local.spend_basis[type]
- threshold_percent = value
- }
- ]
- ])
-
- notification_channels = concat(
- [for channel in google_monitoring_notification_channel.email_channels : channel.id],
- coalesce(var.notification_channels, [])
- )
-}
-
-resource "google_monitoring_notification_channel" "email_channels" {
- for_each = toset(try(var.email_recipients.emails, []))
- display_name = "${var.name} budget email notification (${each.value})"
- type = "email"
- project = var.email_recipients.project_id
- labels = {
- email_address = each.value
- }
- user_labels = {}
-}
-
-
-resource "google_billing_budget" "budget" {
- billing_account = var.billing_account
- display_name = var.name
-
- budget_filter {
- projects = var.projects
- credit_types_treatment = var.credit_treatment
- services = var.services
- }
-
- dynamic "amount" {
- for_each = var.amount == 0 ? [1] : []
- content {
- last_period_amount = true
- }
- }
-
- dynamic "amount" {
- for_each = var.amount != 0 ? [1] : []
- content {
- dynamic "specified_amount" {
- for_each = var.amount != 0 ? [1] : []
- content {
- units = var.amount
- }
- }
- }
- }
-
- dynamic "threshold_rules" {
- for_each = local.threshold_pairs
- iterator = threshold
- content {
- threshold_percent = threshold.value.threshold_percent
- spend_basis = threshold.value.spend_basis
- }
- }
-
- all_updates_rule {
- monitoring_notification_channels = local.notification_channels
- pubsub_topic = var.pubsub_topic
- # disable_default_iam_recipients can only be set if
- # monitoring_notification_channels is nonempty
- disable_default_iam_recipients = try(length(var.notification_channels), 0) > 0 && !var.notify_default_recipients
- schema_version = "1.0"
- }
-}
diff --git a/modules/billing-budget/variables.tf b/modules/billing-budget/variables.tf
deleted file mode 100644
index 003f928e..00000000
--- a/modules/billing-budget/variables.tf
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * Copyright 2022 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 "amount" {
- description = "Amount in the billing account's currency for the budget. Use 0 to set budget to 100% of last period's spend."
- type = number
- default = 0
-}
-
-variable "billing_account" {
- description = "Billing account id."
- type = string
-}
-
-variable "credit_treatment" {
- description = "How credits should be treated when determining spend for threshold calculations. Only INCLUDE_ALL_CREDITS or EXCLUDE_ALL_CREDITS are supported."
- type = string
- default = "INCLUDE_ALL_CREDITS"
- validation {
- condition = (
- var.credit_treatment == "INCLUDE_ALL_CREDITS" ||
- var.credit_treatment == "EXCLUDE_ALL_CREDITS"
- )
- error_message = "Argument credit_treatment must be INCLUDE_ALL_CREDITS or EXCLUDE_ALL_CREDITS."
- }
-}
-
-variable "email_recipients" {
- description = "Emails where budget notifications will be sent. Setting this will create a notification channel for each email in the specified project."
- type = object({
- project_id = string
- emails = list(string)
- })
- default = null
-}
-
-variable "name" {
- description = "Budget name."
- type = string
-}
-
-variable "notification_channels" {
- description = "Monitoring notification channels where to send updates."
- type = list(string)
- default = null
-}
-
-variable "notify_default_recipients" {
- description = "Notify Billing Account Administrators and Billing Account Users IAM roles for the target account."
- type = bool
- default = false
-}
-
-variable "projects" {
- description = "List of projects of the form projects/{project_number}, specifying that usage from only this set of projects should be included in the budget. Set to null to include all projects linked to the billing account."
- type = list(string)
- default = null
-}
-
-variable "pubsub_topic" {
- description = "The ID of the Cloud Pub/Sub topic where budget related messages will be published."
- type = string
- default = null
-}
-
-variable "services" {
- description = "List of services of the form services/{service_id}, specifying that usage from only this set of services should be included in the budget. Set to null to include usage for all services."
- type = list(string)
- default = null
-}
-
-variable "thresholds" {
- description = "Thresholds percentages at which alerts are sent. Must be a value between 0 and 1."
- type = object({
- current = list(number)
- forecasted = list(number)
- })
- validation {
- condition = length(var.thresholds.current) > 0 || length(var.thresholds.forecasted) > 0
- error_message = "Must specify at least one budget threshold."
- }
-}
diff --git a/modules/compute-vm/README.md b/modules/compute-vm/README.md
index 69a68447..5f6e18e3 100644
--- a/modules/compute-vm/README.md
+++ b/modules/compute-vm/README.md
@@ -683,9 +683,9 @@ module "instance" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L235) | Instance name. | string
| ✓ | |
-| [network_interfaces](variables.tf#L240) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…}))
| ✓ | |
-| [project_id](variables.tf#L277) | Project id. | string
| ✓ | |
-| [zone](variables.tf#L369) | Compute zone. | string
| ✓ | |
+| [network_interfaces](variables.tf#L240) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…}))
| ✓ | |
+| [project_id](variables.tf#L278) | Project id. | string
| ✓ | |
+| [zone](variables.tf#L370) | Compute zone. | string
| ✓ | |
| [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | object({…})
| | {…}
|
| [attached_disks](variables.tf#L37) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | list(object({…}))
| | []
|
| [boot_disk](variables.tf#L83) | Boot disk properties. | object({…})
| | {…}
|
@@ -703,13 +703,13 @@ module "instance" {
| [labels](variables.tf#L217) | Instance labels. | map(string)
| | {}
|
| [metadata](variables.tf#L223) | Instance metadata. | map(string)
| | {}
|
| [min_cpu_platform](variables.tf#L229) | Minimum CPU platform. | string
| | null
|
-| [options](variables.tf#L255) | Instance options. | object({…})
| | {…}
|
-| [scratch_disks](variables.tf#L282) | Scratch disks configuration. | object({…})
| | {…}
|
-| [service_account](variables.tf#L294) | Service account email and scopes. If email is null, the default Compute service account will be used unless auto_create is true, in which case a service account will be created. Set the variable to null to avoid attaching a service account. | object({…})
| | {}
|
-| [shielded_config](variables.tf#L304) | Shielded VM configuration of the instances. | object({…})
| | null
|
-| [snapshot_schedules](variables.tf#L314) | Snapshot schedule resource policies that can be attached to disks. | map(object({…}))
| | {}
|
-| [tag_bindings](variables.tf#L357) | Tag bindings for this instance, in key => tag value id format. | map(string)
| | null
|
-| [tags](variables.tf#L363) | Instance network tags for firewall rule targets. | list(string)
| | []
|
+| [options](variables.tf#L256) | Instance options. | object({…})
| | {…}
|
+| [scratch_disks](variables.tf#L283) | Scratch disks configuration. | object({…})
| | {…}
|
+| [service_account](variables.tf#L295) | Service account email and scopes. If email is null, the default Compute service account will be used unless auto_create is true, in which case a service account will be created. Set the variable to null to avoid attaching a service account. | object({…})
| | {}
|
+| [shielded_config](variables.tf#L305) | Shielded VM configuration of the instances. | object({…})
| | null
|
+| [snapshot_schedules](variables.tf#L315) | Snapshot schedule resource policies that can be attached to disks. | map(object({…}))
| | {}
|
+| [tag_bindings](variables.tf#L358) | Tag bindings for this instance, in key => tag value id format. | map(string)
| | null
|
+| [tags](variables.tf#L364) | Instance network tags for firewall rule targets. | list(string)
| | []
|
## Outputs
diff --git a/modules/compute-vm/main.tf b/modules/compute-vm/main.tf
index 6d20a323..e236e454 100644
--- a/modules/compute-vm/main.tf
+++ b/modules/compute-vm/main.tf
@@ -237,6 +237,8 @@ resource "google_compute_instance" "default" {
network = config.value.network
subnetwork = config.value.subnetwork
network_ip = try(config.value.addresses.internal, null)
+ nic_type = config.value.nic_type
+ stack_type = config.value.stack_type
dynamic "access_config" {
for_each = config.value.nat ? [""] : []
content {
@@ -251,7 +253,6 @@ resource "google_compute_instance" "default" {
ip_cidr_range = config_alias.value
}
}
- nic_type = config.value.nic_type
}
}
@@ -374,6 +375,8 @@ resource "google_compute_instance_template" "default" {
network = config.value.network
subnetwork = config.value.subnetwork
network_ip = try(config.value.addresses.internal, null)
+ nic_type = config.value.nic_type
+ stack_type = config.value.stack_type
dynamic "access_config" {
for_each = config.value.nat ? [""] : []
content {
@@ -388,7 +391,6 @@ resource "google_compute_instance_template" "default" {
ip_cidr_range = config_alias.value
}
}
- nic_type = config.value.nic_type
}
}
diff --git a/modules/compute-vm/variables.tf b/modules/compute-vm/variables.tf
index e6a0a4c3..6d04f01b 100644
--- a/modules/compute-vm/variables.tf
+++ b/modules/compute-vm/variables.tf
@@ -240,15 +240,16 @@ variable "name" {
variable "network_interfaces" {
description = "Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed."
type = list(object({
- nat = optional(bool, false)
network = string
subnetwork = string
+ alias_ips = optional(map(string), {})
+ nat = optional(bool, false)
+ nic_type = optional(string)
+ stack_type = optional(string)
addresses = optional(object({
internal = optional(string)
external = optional(string)
}), null)
- alias_ips = optional(map(string), {})
- nic_type = optional(string)
}))
}
diff --git a/modules/folder/README.md b/modules/folder/README.md
index 65661210..2ba7e910 100644
--- a/modules/folder/README.md
+++ b/modules/folder/README.md
@@ -272,7 +272,7 @@ module "folder" {
| name | description | resources |
|---|---|---|
-| [iam.tf](./iam.tf) | IAM bindings, roles and audit logging resources. | google_folder_iam_binding
· google_folder_iam_member
|
+| [iam.tf](./iam.tf) | IAM bindings. | google_folder_iam_binding
· google_folder_iam_member
|
| [logging.tf](./logging.tf) | Log sinks and supporting resources. | google_bigquery_dataset_iam_member
· google_folder_iam_audit_config
· google_logging_folder_exclusion
· google_logging_folder_sink
· 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_firewall_policy_association
· google_essential_contacts_contact
· google_folder
|
| [organization-policies.tf](./organization-policies.tf) | Folder-level organization policies. | google_org_policy_policy
|
@@ -295,7 +295,7 @@ module "folder" {
| [id](variables.tf#L83) | Folder ID in case you use folder_create=false. | string
| | null
|
| [logging_data_access](variables.tf#L89) | 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#L104) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string)
| | {}
|
-| [logging_sinks](variables.tf#L111) | Logging sinks to create for the organization. | map(object({…}))
| | {}
|
+| [logging_sinks](variables.tf#L111) | Logging sinks to create for the folder. | map(object({…}))
| | {}
|
| [name](variables.tf#L141) | Folder name. | string
| | null
|
| [org_policies](variables.tf#L147) | Organization policies applied to this folder keyed by policy name. | map(object({…}))
| | {}
|
| [org_policies_data_path](variables.tf#L174) | Path containing org policies in YAML format. | string
| | null
|
diff --git a/modules/folder/iam.tf b/modules/folder/iam.tf
index 20025b28..56ed6212 100644
--- a/modules/folder/iam.tf
+++ b/modules/folder/iam.tf
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-# tfdoc:file:description IAM bindings, roles and audit logging resources.
+# tfdoc:file:description IAM bindings.
locals {
_group_iam_roles = distinct(flatten(values(var.group_iam)))
diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf
index 86efc215..1c551681 100644
--- a/modules/folder/variables.tf
+++ b/modules/folder/variables.tf
@@ -109,7 +109,7 @@ variable "logging_exclusions" {
}
variable "logging_sinks" {
- description = "Logging sinks to create for the organization."
+ description = "Logging sinks to create for the folder."
type = map(object({
bq_partitioned_table = optional(bool)
description = optional(string)
diff --git a/modules/gcs/README.md b/modules/gcs/README.md
index 3ea52db6..8a26958d 100644
--- a/modules/gcs/README.md
+++ b/modules/gcs/README.md
@@ -178,29 +178,30 @@ module "bucket" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L158) | Bucket name suffix. | string
| ✓ | |
-| [project_id](variables.tf#L213) | Bucket project id. | string
| ✓ | |
-| [cors](variables.tf#L17) | CORS configuration for the bucket. Defaults to null. | object({…})
| | null
|
-| [custom_placement_config](variables.tf#L28) | The bucket's custom location configuration, which specifies the individual regions that comprise a dual-region bucket. If the bucket is designated as REGIONAL or MULTI_REGIONAL, the parameters are empty. | list(string)
| | null
|
-| [default_event_based_hold](variables.tf#L34) | Enable event based hold to new objects added to specific bucket, defaults to false. | bool
| | null
|
-| [encryption_key](variables.tf#L40) | KMS key that will be used for encryption. | string
| | null
|
-| [force_destroy](variables.tf#L46) | Optional map to set force destroy keyed by name, defaults to false. | bool
| | false
|
-| [iam](variables.tf#L52) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
-| [iam_bindings](variables.tf#L58) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…}))
| | {}
|
-| [iam_bindings_additive](variables.tf#L73) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
-| [labels](variables.tf#L88) | Labels to be attached to all buckets. | map(string)
| | {}
|
-| [lifecycle_rules](variables.tf#L94) | Bucket lifecycle rule. | map(object({…}))
| | {}
|
-| [location](variables.tf#L143) | Bucket location. | string
| | "EU"
|
-| [logging_config](variables.tf#L149) | Bucket logging configuration. | object({…})
| | null
|
-| [notification_config](variables.tf#L163) | GCS Notification configuration. | object({…})
| | null
|
-| [objects_to_upload](variables.tf#L177) | Objects to be uploaded to bucket. | map(object({…}))
| | {}
|
-| [prefix](variables.tf#L203) | Optional prefix used to generate the bucket name. | string
| | null
|
-| [requester_pays](variables.tf#L218) | Enables Requester Pays on a storage bucket. | bool
| | null
|
-| [retention_policy](variables.tf#L224) | Bucket retention policy. | object({…})
| | null
|
-| [storage_class](variables.tf#L233) | Bucket storage class. | string
| | "MULTI_REGIONAL"
|
-| [uniform_bucket_level_access](variables.tf#L243) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool
| | true
|
-| [versioning](variables.tf#L249) | Enable versioning, defaults to false. | bool
| | false
|
-| [website](variables.tf#L255) | Bucket website. | object({…})
| | null
|
+| [name](variables.tf#L164) | Bucket name suffix. | string
| ✓ | |
+| [project_id](variables.tf#L219) | Bucket project id. | string
| ✓ | |
+| [autoclass](variables.tf#L17) | Enable autoclass to automatically transition objects to appropriate storage classes based on their access pattern. If set to true, storage_class must be set to STANDARD. Defaults to false. | bool
| | false
|
+| [cors](variables.tf#L23) | CORS configuration for the bucket. Defaults to null. | object({…})
| | null
|
+| [custom_placement_config](variables.tf#L34) | The bucket's custom location configuration, which specifies the individual regions that comprise a dual-region bucket. If the bucket is designated as REGIONAL or MULTI_REGIONAL, the parameters are empty. | list(string)
| | null
|
+| [default_event_based_hold](variables.tf#L40) | Enable event based hold to new objects added to specific bucket, defaults to false. | bool
| | null
|
+| [encryption_key](variables.tf#L46) | KMS key that will be used for encryption. | string
| | null
|
+| [force_destroy](variables.tf#L52) | Optional map to set force destroy keyed by name, defaults to false. | bool
| | false
|
+| [iam](variables.tf#L58) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string))
| | {}
|
+| [iam_bindings](variables.tf#L64) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…}))
| | {}
|
+| [iam_bindings_additive](variables.tf#L79) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
+| [labels](variables.tf#L94) | Labels to be attached to all buckets. | map(string)
| | {}
|
+| [lifecycle_rules](variables.tf#L100) | Bucket lifecycle rule. | map(object({…}))
| | {}
|
+| [location](variables.tf#L149) | Bucket location. | string
| | "EU"
|
+| [logging_config](variables.tf#L155) | Bucket logging configuration. | object({…})
| | null
|
+| [notification_config](variables.tf#L169) | GCS Notification configuration. | object({…})
| | null
|
+| [objects_to_upload](variables.tf#L183) | Objects to be uploaded to bucket. | map(object({…}))
| | {}
|
+| [prefix](variables.tf#L209) | Optional prefix used to generate the bucket name. | string
| | null
|
+| [requester_pays](variables.tf#L224) | Enables Requester Pays on a storage bucket. | bool
| | null
|
+| [retention_policy](variables.tf#L230) | Bucket retention policy. | object({…})
| | null
|
+| [storage_class](variables.tf#L239) | Bucket storage class. | string
| | "MULTI_REGIONAL"
|
+| [uniform_bucket_level_access](variables.tf#L249) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool
| | true
|
+| [versioning](variables.tf#L255) | Enable versioning, defaults to false. | bool
| | false
|
+| [website](variables.tf#L261) | Bucket website. | object({…})
| | null
|
## Outputs
diff --git a/modules/gcs/main.tf b/modules/gcs/main.tf
index bd1a4429..1341e707 100644
--- a/modules/gcs/main.tf
+++ b/modules/gcs/main.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,13 @@ resource "google_storage_bucket" "bucket" {
enabled = var.versioning
}
+ dynamic "autoclass" {
+ for_each = var.autoclass == null ? [] : [""]
+ content {
+ enabled = var.autoclass
+ }
+ }
+
dynamic "website" {
for_each = var.website == null ? [] : [""]
diff --git a/modules/gcs/variables.tf b/modules/gcs/variables.tf
index 2579c09c..350c74ba 100644
--- a/modules/gcs/variables.tf
+++ b/modules/gcs/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2023 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,12 @@
* limitations under the License.
*/
+variable "autoclass" {
+ description = "Enable autoclass to automatically transition objects to appropriate storage classes based on their access pattern. If set to true, storage_class must be set to STANDARD. Defaults to false."
+ type = bool
+ default = false
+}
+
variable "cors" {
description = "CORS configuration for the bucket. Defaults to null."
type = object({
diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md
index e3cc75fd..e171125b 100644
--- a/modules/net-vpc/README.md
+++ b/modules/net-vpc/README.md
@@ -571,12 +571,12 @@ module "vpc" {
| [project_id](outputs.tf#L58) | Project ID containing the network. Use this when you need to create resources *after* the VPC is fully set up (e.g. subnets created, shared VPC service projects attached, Private Service Networking configured). | |
| [self_link](outputs.tf#L71) | Network self link. | |
| [subnet_ids](outputs.tf#L83) | Map of subnet IDs keyed by name. | |
-| [subnet_ips](outputs.tf#L88) | Map of subnet address ranges keyed by name. | |
-| [subnet_ipv6_external_prefixes](outputs.tf#L95) | Map of subnet external IPv6 prefixes keyed by name. | |
-| [subnet_regions](outputs.tf#L103) | Map of subnet regions keyed by name. | |
-| [subnet_secondary_ranges](outputs.tf#L110) | Map of subnet secondary ranges keyed by name. | |
-| [subnet_self_links](outputs.tf#L121) | Map of subnet self links keyed by name. | |
-| [subnets](outputs.tf#L126) | Subnet resources. | |
-| [subnets_proxy_only](outputs.tf#L131) | L7 ILB or L7 Regional LB subnet resources. | |
-| [subnets_psc](outputs.tf#L136) | Private Service Connect subnet resources. | |
+| [subnet_ips](outputs.tf#L92) | Map of subnet address ranges keyed by name. | |
+| [subnet_ipv6_external_prefixes](outputs.tf#L99) | Map of subnet external IPv6 prefixes keyed by name. | |
+| [subnet_regions](outputs.tf#L107) | Map of subnet regions keyed by name. | |
+| [subnet_secondary_ranges](outputs.tf#L114) | Map of subnet secondary ranges keyed by name. | |
+| [subnet_self_links](outputs.tf#L125) | Map of subnet self links keyed by name. | |
+| [subnets](outputs.tf#L134) | Subnet resources. | |
+| [subnets_proxy_only](outputs.tf#L143) | L7 ILB or L7 Regional LB subnet resources. | |
+| [subnets_psc](outputs.tf#L148) | Private Service Connect subnet resources. | |
diff --git a/modules/net-vpc/outputs.tf b/modules/net-vpc/outputs.tf
index 503923d9..d0bb139f 100644
--- a/modules/net-vpc/outputs.tf
+++ b/modules/net-vpc/outputs.tf
@@ -83,6 +83,10 @@ output "self_link" {
output "subnet_ids" {
description = "Map of subnet IDs keyed by name."
value = { for k, v in google_compute_subnetwork.subnetwork : k => v.id }
+ depends_on = [
+ # allows correct destruction of internal application load balancers
+ google_compute_subnetwork.proxy_only
+ ]
}
output "subnet_ips" {
@@ -121,11 +125,19 @@ output "subnet_secondary_ranges" {
output "subnet_self_links" {
description = "Map of subnet self links keyed by name."
value = { for k, v in google_compute_subnetwork.subnetwork : k => v.self_link }
+ depends_on = [
+ # allows correct destruction of internal application load balancers
+ google_compute_subnetwork.proxy_only
+ ]
}
output "subnets" {
description = "Subnet resources."
value = { for k, v in google_compute_subnetwork.subnetwork : k => v }
+ depends_on = [
+ # allows correct destruction of internal application load balancers
+ google_compute_subnetwork.proxy_only
+ ]
}
output "subnets_proxy_only" {
@@ -136,4 +148,4 @@ output "subnets_proxy_only" {
output "subnets_psc" {
description = "Private Service Connect subnet resources."
value = { for k, v in google_compute_subnetwork.psc : k => v }
-}
\ No newline at end of file
+}
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index b73cda2b..0afb9d02 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -18,7 +18,7 @@ counts:
google_logging_organization_sink: 2
google_organization_iam_binding: 20
google_organization_iam_custom_role: 3
- google_organization_iam_member: 17
+ google_organization_iam_member: 13
google_project: 3
google_project_iam_binding: 9
google_project_iam_member: 3
diff --git a/tests/modules/billing_account/examples/budget-monitoring-channel.yaml b/tests/modules/billing_account/examples/budget-monitoring-channel.yaml
new file mode 100644
index 00000000..3909336c
--- /dev/null
+++ b/tests/modules/billing_account/examples/budget-monitoring-channel.yaml
@@ -0,0 +1,60 @@
+# Copyright 2023 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.billing-account.google_billing_budget.default["folder-net-month-current-100"]:
+ all_updates_rule:
+ - disable_default_iam_recipients: true
+ pubsub_topic: null
+ schema_version: '1.0'
+ amount:
+ - last_period_amount: null
+ specified_amount:
+ - nanos: null
+ units: '100'
+ billing_account: 012345-ABCDEF-012345
+ budget_filter:
+ - calendar_period: null
+ credit_types_treatment: INCLUDE_ALL_CREDITS
+ custom_period: []
+ projects: null
+ resource_ancestors:
+ - folders/1234567890
+ display_name: 100 dollars in current spend
+ threshold_rules:
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.5
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.75
+ timeouts: null
+ module.billing-account.google_monitoring_notification_channel.default["billing-default"]:
+ description: null
+ display_name: Budget email notification billing-default.
+ enabled: true
+ force_delete: false
+ labels:
+ email_address: gcp-billing-admins@example.com
+ project: tf-playground-simple
+ sensitive_labels: []
+ timeouts: null
+ type: email
+ user_labels: null
+
+counts:
+ google_billing_budget: 1
+ google_monitoring_notification_channel: 1
+ modules: 1
+ resources: 2
+
+outputs: {}
diff --git a/tests/modules/billing_account/examples/budget-pubsub.yaml b/tests/modules/billing_account/examples/budget-pubsub.yaml
new file mode 100644
index 00000000..76c1f559
--- /dev/null
+++ b/tests/modules/billing_account/examples/budget-pubsub.yaml
@@ -0,0 +1,56 @@
+# Copyright 2023 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.billing-account.google_billing_budget.default["folder-net-month-current-100"]:
+ all_updates_rule:
+ - disable_default_iam_recipients: false
+ monitoring_notification_channels: null
+ pubsub_topic: projects/my-prj/topics/budget-default
+ schema_version: '1.0'
+ amount:
+ - last_period_amount: null
+ specified_amount:
+ - nanos: null
+ units: '100'
+ billing_account: 012345-ABCDEF-012345
+ budget_filter:
+ - calendar_period: null
+ credit_types_treatment: INCLUDE_ALL_CREDITS
+ custom_period: []
+ projects: null
+ resource_ancestors:
+ - folders/1234567890
+ display_name: 100 dollars in current spend
+ threshold_rules:
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.5
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.75
+ timeouts: null
+ module.pubsub-billing-topic.google_pubsub_topic.default:
+ kms_key_name: null
+ labels: null
+ message_retention_duration: null
+ name: budget-default
+ project: my-prj
+ timeouts: null
+
+counts:
+ google_billing_budget: 1
+ google_pubsub_topic: 1
+ modules: 2
+ resources: 2
+
+outputs: {}
diff --git a/tests/modules/billing_account/examples/budget-simple.yaml b/tests/modules/billing_account/examples/budget-simple.yaml
new file mode 100644
index 00000000..8fd87441
--- /dev/null
+++ b/tests/modules/billing_account/examples/budget-simple.yaml
@@ -0,0 +1,44 @@
+# Copyright 2023 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.billing-account.google_billing_budget.default["folder-net-month-current-100"]:
+ all_updates_rule: []
+ amount:
+ - last_period_amount: null
+ specified_amount:
+ - nanos: null
+ units: '100'
+ billing_account: 012345-ABCDEF-012345
+ budget_filter:
+ - calendar_period: null
+ credit_types_treatment: INCLUDE_ALL_CREDITS
+ custom_period: []
+ projects: null
+ resource_ancestors:
+ - folders/1234567890
+ display_name: 100 dollars in current spend
+ threshold_rules:
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.5
+ - spend_basis: CURRENT_SPEND
+ threshold_percent: 0.75
+ timeouts: null
+
+counts:
+ google_billing_budget: 1
+ modules: 1
+ resources: 1
+
+outputs: {}
diff --git a/tests/modules/billing_account/examples/iam.yaml b/tests/modules/billing_account/examples/iam.yaml
new file mode 100644
index 00000000..1cac36d5
--- /dev/null
+++ b/tests/modules/billing_account/examples/iam.yaml
@@ -0,0 +1,45 @@
+# Copyright 2023 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.billing-account.google_billing_account_iam_binding.authoritative["roles/billing.admin"]:
+ billing_account_id: 012345-ABCDEF-012345
+ condition: []
+ members:
+ - group:billing-admins@example.org
+ - serviceAccount:foo@myprj.iam.gserviceaccount.com
+ role: roles/billing.admin
+ module.billing-account.google_billing_account_iam_binding.bindings["conditional-admin"]:
+ billing_account_id: 012345-ABCDEF-012345
+ condition:
+ - description: null
+ expression: resource.matchTag('123456/environment', 'development')
+ title: pf-dev-conditional-billing-admin
+ members:
+ - serviceAccount:pf-dev@myprj.iam.gserviceaccount.com
+ role: roles/billing.admin
+ module.billing-account.google_billing_account_iam_member.bindings["sa-net-iac-user"]:
+ billing_account_id: 012345-ABCDEF-012345
+ condition: []
+ member: serviceAccount:net-iac-0@myprj.iam.gserviceaccount.com
+ role: roles/billing.user
+
+counts:
+ google_billing_account_iam_binding: 2
+ google_billing_account_iam_member: 1
+ modules: 1
+ resources: 3
+
+outputs: {}
+
diff --git a/tests/modules/billing_account/examples/logging.yaml b/tests/modules/billing_account/examples/logging.yaml
new file mode 100644
index 00000000..4496f01a
--- /dev/null
+++ b/tests/modules/billing_account/examples/logging.yaml
@@ -0,0 +1,43 @@
+# Copyright 2023 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.billing-account.google_logging_billing_account_sink.sink["all"]:
+ billing_account: 012345-ABCDEF-012345
+ description: all (Terraform-managed).
+ disabled: false
+ exclusions: []
+ filter: null
+ name: all
+ module.billing-account.google_project_iam_member.bucket-sinks-binding["all"]:
+ condition:
+ - title: all bucket writer
+ role: roles/logging.bucketWriter
+ module.log-bucket-all.google_logging_project_bucket_config.bucket[0]:
+ bucket_id: billing-account-all
+ cmek_settings: []
+ enable_analytics: false
+ location: global
+ locked: null
+ project: myprj
+ retention_days: 30
+
+counts:
+ google_logging_billing_account_sink: 1
+ google_logging_project_bucket_config: 1
+ google_project_iam_member: 1
+ modules: 2
+ resources: 3
+
+outputs: {}
diff --git a/tests/modules/gcs/examples/iam-authoritative.yaml b/tests/modules/gcs/examples/iam-authoritative.yaml
index 84398c3c..8956adc6 100644
--- a/tests/modules/gcs/examples/iam-authoritative.yaml
+++ b/tests/modules/gcs/examples/iam-authoritative.yaml
@@ -33,6 +33,8 @@ values:
uniform_bucket_level_access: true
versioning:
- enabled: false
+ autoclass:
+ - enabled: false
module.bucket.google_storage_bucket_iam_binding.authoritative["roles/storage.admin"]:
bucket: my-bucket
condition: []
diff --git a/tests/modules/gcs/examples/iam-bindings-additive.yaml b/tests/modules/gcs/examples/iam-bindings-additive.yaml
index edc6c6a7..2c20f9aa 100644
--- a/tests/modules/gcs/examples/iam-bindings-additive.yaml
+++ b/tests/modules/gcs/examples/iam-bindings-additive.yaml
@@ -33,6 +33,8 @@ values:
uniform_bucket_level_access: true
versioning:
- enabled: false
+ autoclass:
+ - enabled: false
module.bucket.google_storage_bucket_iam_member.bindings["storage-admin-with-delegated_roles"]:
bucket: my-bucket
condition:
diff --git a/tests/modules/gcs/examples/iam-bindings.yaml b/tests/modules/gcs/examples/iam-bindings.yaml
index ff3740b1..45113fae 100644
--- a/tests/modules/gcs/examples/iam-bindings.yaml
+++ b/tests/modules/gcs/examples/iam-bindings.yaml
@@ -33,6 +33,8 @@ values:
uniform_bucket_level_access: true
versioning:
- enabled: false
+ autoclass:
+ - enabled: false
module.bucket.google_storage_bucket_iam_binding.bindings["storage-admin-with-delegated_roles"]:
bucket: my-bucket
condition:
diff --git a/tests/modules/gcs/examples/simple.yaml b/tests/modules/gcs/examples/simple.yaml
index 3e7a646d..0bc34c06 100644
--- a/tests/modules/gcs/examples/simple.yaml
+++ b/tests/modules/gcs/examples/simple.yaml
@@ -34,6 +34,8 @@ values:
uniform_bucket_level_access: true
versioning:
- enabled: true
+ autoclass:
+ - enabled: false
counts:
google_storage_bucket: 1
\ No newline at end of file