diff --git a/fast/stages/0-org-setup/README.md b/fast/stages/0-org-setup/README.md
index 7402d7b4f..4eea4a287 100644
--- a/fast/stages/0-org-setup/README.md
+++ b/fast/stages/0-org-setup/README.md
@@ -96,9 +96,6 @@ The standard datasets use the `gcp-organization-admins` alias to assign administ
global:
# gcloud beta billing accounts list
billing_account: 123456-123456-123456
- locations:
- bigquery: europe-west1
- logging: europe-west1
organization:
# gcloud organizations list
domain: example.org
@@ -108,11 +105,16 @@ projects:
defaults:
# define a unique prefix with a maximum of 9 characters
prefix: foo-1
- storage_location: europe-west1
+ locations:
+ bigquery: $locations:primary
+ logging: $locations:primary
+ storage: $locations:primary
context:
iam_principals:
# make sure the user running apply is a member of this group
gcp-organization-admins: group:fabric-fast-owners@example.com
+ locations:
+ primary: europe-west1
```
A more detailed example containing a few other attributes that can be set in the file is in a [later section](#defaults-configuration) in this document.
@@ -660,7 +662,6 @@ Define values for the `var.environments` variable in a tfvars file.
| name | description | sensitive |
|---|---|:---:|
| [iam_principals](outputs.tf#L17) | IAM principals. | |
-| [locations](outputs.tf#L22) | Default locations. | |
-| [projects](outputs.tf#L27) | Attributes for managed projects. | |
-| [tfvars](outputs.tf#L32) | Stage tfvars. | ✓ |
+| [projects](outputs.tf#L22) | Attributes for managed projects. | |
+| [tfvars](outputs.tf#L27) | Stage tfvars. | ✓ |
diff --git a/fast/stages/0-org-setup/data/defaults.yaml b/fast/stages/0-org-setup/data/defaults.yaml
index 6512f758a..9c8122b87 100644
--- a/fast/stages/0-org-setup/data/defaults.yaml
+++ b/fast/stages/0-org-setup/data/defaults.yaml
@@ -17,9 +17,6 @@
global:
# use `gcloud beta billing accounts list` to populate
billing_account: ABCDEF-0123456-ABCDEF
- locations:
- bigquery: europe-west1
- logging: europe-west1
organization:
# use `gcloud organizations list`` to populate
domain: fast-test-00.example.com
@@ -29,14 +26,18 @@ projects:
defaults:
# prefix must be unique and less than 9 characters
prefix: test00
- storage_location: europe-west1
- bigquery_location: europe-west1
+ locations:
+ bigquery: $locations:primary
+ logging: $locations:primary
+ storage: $locations:primary
overrides: {}
context:
# you can populate context variables here for use in YAML replacements
iam_principals:
# this is the default group used in boostrap, initial user must be a member
gcp-organization-admins: group:gcp-organization-admins@example.com
+ locations:
+ primary: europe-west1
output_files:
# local path is optional but recommended when starting
local_path: ~/fast-config/fast-test-00
diff --git a/fast/stages/0-org-setup/data/organization/.config.yaml b/fast/stages/0-org-setup/data/organization/.config.yaml
index 5b522e08f..6ce8bb490 100644
--- a/fast/stages/0-org-setup/data/organization/.config.yaml
+++ b/fast/stages/0-org-setup/data/organization/.config.yaml
@@ -94,7 +94,7 @@ iam_by_principals:
- roles/cloudasset.viewer
logging:
# disable_default_log_sink: false
- storage_location: $locations:default
+ storage_location: $locations:primary
sinks:
audit-logs:
# description: foo
diff --git a/fast/stages/0-org-setup/data/projects/core/billing-0.yaml b/fast/stages/0-org-setup/data/projects/core/billing-0.yaml
index fc918affc..78ed0b56e 100644
--- a/fast/stages/0-org-setup/data/projects/core/billing-0.yaml
+++ b/fast/stages/0-org-setup/data/projects/core/billing-0.yaml
@@ -27,4 +27,3 @@ services:
datasets:
billing_export:
friendly_name: Billing export
- location: $locations:bigquery
diff --git a/fast/stages/0-org-setup/main.tf b/fast/stages/0-org-setup/main.tf
index 04015d1a2..f5ed6c9d3 100644
--- a/fast/stages/0-org-setup/main.tf
+++ b/fast/stages/0-org-setup/main.tf
@@ -18,23 +18,19 @@ locals {
paths = {
for k, v in var.factories_config : k => try(pathexpand(v), null)
}
+ _ctx = {
+ for k, v in var.context : k => merge(
+ v,
+ try(local._defaults.context[k], {})
+ )
+ }
# fail if we have no valid defaults
_defaults = yamldecode(file(local.paths.defaults))
- ctx = merge(var.context, {
- iam_principals = local.iam_principals
- locations = {
- for k, v in local.defaults.locations :
- k => v if k != "pubsub"
- }
+ ctx = merge(local._ctx, {
+ iam_principals = merge(local.iam_principals, local._ctx.iam_principals)
})
defaults = {
billing_account = try(local._defaults.global.billing_account, null)
- locations = merge({
- bigquery = "eu"
- logging = "global"
- pubsub = []
- storage = "eu"
- }, try(local._defaults.global.locations, {}))
organization = (
try(local._defaults.global.organization.id, null) == null
? null
@@ -85,12 +81,5 @@ resource "terraform_data" "precondition" {
)
error_message = "Prefix must be set in project defaults or overrides."
}
- precondition {
- condition = (
- try(local.project_defaults.defaults.storage_location, null) != null ||
- try(local.project_defaults.overrides.storage_location, null) != null
- )
- error_message = "Storage location must be set in project defaults or overrides."
- }
}
}
diff --git a/fast/stages/0-org-setup/organization.tf b/fast/stages/0-org-setup/organization.tf
index 79b09ae62..582f67b21 100644
--- a/fast/stages/0-org-setup/organization.tf
+++ b/fast/stages/0-org-setup/organization.tf
@@ -79,9 +79,7 @@ module "organization" {
id = local.organization_id
}
}
- locations = {
- default = local.defaults.locations.logging
- }
+ locations = local.ctx.locations
}
factories_config = {
org_policy_custom_constraints = "${local.paths.organization}/custom-constraints"
diff --git a/fast/stages/0-org-setup/output-files.tf b/fast/stages/0-org-setup/output-files.tf
index 68f542b1b..c3d9f1ba5 100644
--- a/fast/stages/0-org-setup/output-files.tf
+++ b/fast/stages/0-org-setup/output-files.tf
@@ -43,8 +43,7 @@ locals {
billing_account = {
id = local.defaults.billing_account
}
- groups = local.ctx.iam_principals
- locations = local.defaults.locations
+ groups = local.ctx.iam_principals
organization = {
customer_id = try(local.defaults.organization.customer_id, null)
domain = local.organization.domain
diff --git a/fast/stages/0-org-setup/outputs.tf b/fast/stages/0-org-setup/outputs.tf
index 4b3b5ca12..d4a36a32a 100644
--- a/fast/stages/0-org-setup/outputs.tf
+++ b/fast/stages/0-org-setup/outputs.tf
@@ -19,11 +19,6 @@ output "iam_principals" {
value = local.iam_principals
}
-output "locations" {
- description = "Default locations."
- value = local.defaults.locations
-}
-
output "projects" {
description = "Attributes for managed projects."
value = module.factory.projects
diff --git a/fast/stages/0-org-setup/schemas/defaults.schema.json b/fast/stages/0-org-setup/schemas/defaults.schema.json
index 98d662589..9720eb96b 100644
--- a/fast/stages/0-org-setup/schemas/defaults.schema.json
+++ b/fast/stages/0-org-setup/schemas/defaults.schema.json
@@ -11,31 +11,6 @@
"billing_account": {
"type": "string"
},
- "locations": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "bigquery": {
- "type": "string",
- "default": "eu"
- },
- "logging": {
- "type": "string",
- "default": "global"
- },
- "pubsub": {
- "type": "array",
- "items": {
- "type": "string"
- },
- "default": []
- },
- "storage": {
- "type": "string",
- "default": "eu"
- }
- }
- },
"organization": {
"type": "object",
"additionalProperties": false,
@@ -114,6 +89,21 @@
}
}
},
+ "locations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bigquery": {
+ "type": "string"
+ },
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ }
+ }
+ },
"logging_data_access": {
"type": "object",
"default": {},
@@ -281,9 +271,6 @@
"host_project"
]
},
- "storage_location": {
- "type": "string"
- },
"tag_bindings": {
"type": "object",
"default": {},
@@ -352,9 +339,6 @@
"required": [
"perimeter_name"
]
- },
- "bigquery_location": {
- "type": "string"
}
}
},
@@ -395,6 +379,21 @@
"ABANDON"
]
},
+ "locations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bigquery": {
+ "type": "string"
+ },
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ }
+ }
+ },
"logging_data_access": {
"type": "object",
"default": {},
@@ -456,9 +455,6 @@
}
}
},
- "storage_location": {
- "type": "string"
- },
"tag_bindings": {
"type": "object",
"default": {},
@@ -527,9 +523,6 @@
"required": [
"perimeter_name"
]
- },
- "bigquery_location": {
- "type": "string"
}
}
}
@@ -539,11 +532,77 @@
"type": "object",
"additionalProperties": false,
"properties": {
+ "custom_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "folder_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "kms_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"iam_principals": {
"type": "object",
"additionalProperties": {
"type": "string"
}
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "notification_channels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "project_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "service_account_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_values": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_host_projects": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_sc_perimeters": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
}
}
},
@@ -694,4 +753,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/fast/stages/2-project-factory/README.md b/fast/stages/2-project-factory/README.md
index 8bab44a80..f1170471a 100644
--- a/fast/stages/2-project-factory/README.md
+++ b/fast/stages/2-project-factory/README.md
@@ -480,25 +480,24 @@ Pattern-based files make specific assumptions:
|---|---|:---:|:---:|:---:|:---:|
| [automation](variables-fast.tf#L17) | Automation resources created by the bootstrap stage. | object({…}) | ✓ | | 0-org-setup |
| [billing_account](variables-fast.tf#L26) | Billing account id. | object({…}) | ✓ | | 0-org-setup |
-| [prefix](variables-fast.tf#L92) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-org-setup |
+| [prefix](variables-fast.tf#L82) | Prefix used for resources that need unique names. Use a maximum of 9 chars for organizations, and 11 chars for tenants. | string | ✓ | | 0-org-setup |
| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} | |
| [custom_roles](variables-fast.tf#L34) | Custom roles defined at the org level, in key => id format. | map(string) | | {} | 0-org-setup |
-| [data_defaults](variables-projects.tf#L17) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} | |
-| [data_merges](variables-projects.tf#L89) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | |
-| [data_overrides](variables-projects.tf#L108) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | |
+| [data_defaults](variables-projects.tf#L17) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} | |
+| [data_merges](variables-projects.tf#L93) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} | |
+| [data_overrides](variables-projects.tf#L112) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} | |
| [factories_config](variables.tf#L36) | Path to folder with YAML resource description data files. | object({…}) | | {} | |
| [folder_ids](variables-fast.tf#L42) | Folders created in the bootstrap stage. | map(string) | | {} | 0-org-setup |
| [host_project_ids](variables-fast.tf#L58) | Host project for the shared VPC. | map(string) | | {} | 2-networking |
| [iam_principals](variables-fast.tf#L50) | IAM-format principals. | map(string) | | {} | 0-org-setup |
| [kms_keys](variables-fast.tf#L66) | KMS key ids. | map(string) | | {} | 2-security |
-| [locations](variables-fast.tf#L74) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…}) | | {} | 0-org-setup |
-| [perimeters](variables-fast.tf#L84) | Optional VPC-SC perimeter ids. | map(string) | | {} | 1-vpcsc |
-| [project_ids](variables-fast.tf#L102) | Projects created in the bootstrap stage. | map(string) | | {} | 0-org-setup |
-| [service_accounts](variables-fast.tf#L110) | Service accounts created in the bootstrap stage. | map(string) | | {} | 0-org-setup |
+| [perimeters](variables-fast.tf#L74) | Optional VPC-SC perimeter ids. | map(string) | | {} | 1-vpcsc |
+| [project_ids](variables-fast.tf#L92) | Projects created in the bootstrap stage. | map(string) | | {} | 0-org-setup |
+| [service_accounts](variables-fast.tf#L100) | Service accounts created in the bootstrap stage. | map(string) | | {} | 0-org-setup |
| [stage_name](variables.tf#L57) | FAST stage name. Used to separate output files across different factories. | string | | "2-project-factory" | |
-| [subnet_self_links](variables-fast.tf#L118) | Shared VPC subnet IDs. | map(map(string)) | | {} | 2-networking |
-| [tag_values](variables-fast.tf#L126) | FAST-managed resource manager tag values. | map(string) | | {} | 0-org-setup |
-| [universe](variables-fast.tf#L134) | GCP universe where to deploy projects. The prefix will be prepended to the project id. | object({…}) | | null | 0-org-setup |
+| [subnet_self_links](variables-fast.tf#L108) | Shared VPC subnet IDs. | map(map(string)) | | {} | 2-networking |
+| [tag_values](variables-fast.tf#L116) | FAST-managed resource manager tag values. | map(string) | | {} | 0-org-setup |
+| [universe](variables-fast.tf#L124) | GCP universe where to deploy projects. The prefix will be prepended to the project id. | object({…}) | | null | 0-org-setup |
## Outputs
diff --git a/fast/stages/2-project-factory/data/defaults.yaml b/fast/stages/2-project-factory/data/defaults.yaml
index 542f75161..9a77eb222 100644
--- a/fast/stages/2-project-factory/data/defaults.yaml
+++ b/fast/stages/2-project-factory/data/defaults.yaml
@@ -17,8 +17,9 @@
# environment-specific project defaults, merges and overrides can be defined here
projects:
- # defaults:
- # storage_location: europe-west8
+ defaults:
+ locations:
+ storage: $locations:primary
merges:
services:
- logging.googleapis.com
@@ -28,6 +29,8 @@ projects:
# environment-specific static contexts can be defined here
-# context:
+context:
# iam_principals:
-# foo: group:foo@example.com
\ No newline at end of file
+# foo: group:foo@example.com
+ locations:
+ primary: europe-west1
\ No newline at end of file
diff --git a/fast/stages/2-project-factory/main.tf b/fast/stages/2-project-factory/main.tf
index e1f7eb18d..947298f85 100644
--- a/fast/stages/2-project-factory/main.tf
+++ b/fast/stages/2-project-factory/main.tf
@@ -17,7 +17,9 @@
# tfdoc:file:description Project factory.
locals {
- context = merge(var.context, lookup(local.defaults, "context", {}))
+ context = {
+ for k, v in var.context : k => merge(v, try(local.defaults.context[k], {}))
+ }
defaults = yamldecode(file(pathexpand(var.factories_config.defaults)))
fast_defaults = {
billing_account = coalesce(
@@ -27,9 +29,6 @@ locals {
prefix = coalesce(
var.data_defaults.prefix, var.prefix
)
- storage_location = coalesce(
- var.data_defaults.storage_location, var.locations.storage
- )
}
project_defaults = {
defaults = {
@@ -83,7 +82,7 @@ module "factory" {
local.context.iam_principals
)
kms_keys = merge(var.kms_keys, local.context.kms_keys)
- locations = merge(var.locations, local.context.locations)
+ locations = local.context.locations
notification_channels = local.context.notification_channels
project_ids = merge(
var.project_ids, var.host_project_ids, local.context.project_ids
diff --git a/fast/stages/2-project-factory/schemas/defaults.schema.json b/fast/stages/2-project-factory/schemas/defaults.schema.json
index 482ac4c0a..29b4ab2d8 100644
--- a/fast/stages/2-project-factory/schemas/defaults.schema.json
+++ b/fast/stages/2-project-factory/schemas/defaults.schema.json
@@ -58,6 +58,21 @@
}
}
},
+ "locations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bigquery": {
+ "type": "string"
+ },
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ }
+ }
+ },
"logging_data_access": {
"type": "object",
"default": {},
@@ -244,9 +259,6 @@
"host_project"
]
},
- "storage_location": {
- "type": "string"
- },
"tag_bindings": {
"type": "object",
"default": {},
@@ -404,6 +416,21 @@
"ABANDON"
]
},
+ "locations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bigquery": {
+ "type": "string"
+ },
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ }
+ }
+ },
"logging_data_access": {
"type": "object",
"default": {},
@@ -491,9 +518,6 @@
"type": "string"
}
},
- "storage_location": {
- "type": "string"
- },
"tag_bindings": {
"type": "object",
"default": {},
@@ -542,11 +566,77 @@
"type": "object",
"additionalProperties": false,
"properties": {
+ "custom_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "folder_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "kms_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"iam_principals": {
"type": "object",
"additionalProperties": {
"type": "string"
}
+ },
+ "locations": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "notification_channels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "project_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "service_account_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_values": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_host_projects": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_sc_perimeters": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
}
}
},
diff --git a/fast/stages/2-project-factory/variables-fast.tf b/fast/stages/2-project-factory/variables-fast.tf
index b227f7747..65bb622f5 100644
--- a/fast/stages/2-project-factory/variables-fast.tf
+++ b/fast/stages/2-project-factory/variables-fast.tf
@@ -71,16 +71,6 @@ variable "kms_keys" {
default = {}
}
-variable "locations" {
- # tfdoc:variable:source 0-org-setup
- description = "Optional locations for GCS, BigQuery, and logging buckets created here."
- type = object({
- storage = optional(string, "eu")
- })
- nullable = false
- default = {}
-}
-
variable "perimeters" {
# tfdoc:variable:source 1-vpcsc
description = "Optional VPC-SC perimeter ids."
diff --git a/fast/stages/2-project-factory/variables-projects.tf b/fast/stages/2-project-factory/variables-projects.tf
index 815021b1f..b2709b37e 100644
--- a/fast/stages/2-project-factory/variables-projects.tf
+++ b/fast/stages/2-project-factory/variables-projects.tf
@@ -29,7 +29,17 @@ variable "data_defaults" {
org_policies = optional(string)
quotas = optional(string)
}), {})
- labels = optional(map(string), {})
+ labels = optional(map(string), {})
+ locations = optional(object({
+ bigquery = optional(string)
+ logging = optional(string)
+ storage = optional(string)
+ }), {})
+ logging_data_access = optional(map(object({
+ ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
+ DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
+ DATA_WRITE = optional(object({ exempted_members = optional(list(string)) }))
+ })), {})
metric_scopes = optional(list(string), [])
parent = optional(string)
prefix = optional(string)
@@ -41,6 +51,10 @@ variable "data_defaults" {
services_enabled = optional(list(string), [])
}))
}))
+ service_accounts = optional(map(object({
+ display_name = optional(string, "Terraform-managed.")
+ iam_self_roles = optional(list(string))
+ })), {})
service_encryption_key_ids = optional(map(list(string)), {})
services = optional(list(string), [])
shared_vpc_service_config = optional(object({
@@ -60,15 +74,10 @@ variable "data_defaults" {
service_iam_grants = optional(list(string), [])
network_subnet_users = optional(map(list(string)), {})
}))
- storage_location = optional(string)
- tag_bindings = optional(map(string), {})
- # non-project resources
- service_accounts = optional(map(object({
- display_name = optional(string, "Terraform-managed.")
- iam_self_roles = optional(list(string))
- })), {})
+ tag_bindings = optional(map(string), {})
universe = optional(object({
prefix = string
+ forced_jit_service_identities = optional(list(string), [])
unavailable_service_identities = optional(list(string), [])
unavailable_services = optional(list(string), [])
}))
@@ -76,11 +85,6 @@ variable "data_defaults" {
perimeter_name = string
is_dry_run = optional(bool, false)
}))
- logging_data_access = optional(map(object({
- ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
- DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
- DATA_WRITE = optional(object({ exempted_members = optional(list(string)) }))
- })), {})
})
nullable = false
default = {}
@@ -121,19 +125,28 @@ variable "data_overrides" {
org_policies = optional(string)
quotas = optional(string)
}), {})
- parent = optional(string)
- prefix = optional(string)
- service_encryption_key_ids = optional(map(list(string)))
- storage_location = optional(string)
- tag_bindings = optional(map(string))
- services = optional(list(string))
- # non-project resources
+ locations = optional(object({
+ bigquery = optional(string)
+ logging = optional(string)
+ storage = optional(string)
+ }), {})
+ logging_data_access = optional(map(object({
+ ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
+ DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
+ DATA_WRITE = optional(object({ exempted_members = optional(list(string)) }))
+ })))
+ parent = optional(string)
+ prefix = optional(string)
service_accounts = optional(map(object({
display_name = optional(string, "Terraform-managed.")
iam_self_roles = optional(list(string))
})))
+ service_encryption_key_ids = optional(map(list(string)))
+ services = optional(list(string))
+ tag_bindings = optional(map(string))
universe = optional(object({
prefix = string
+ forced_jit_service_identities = optional(list(string), [])
unavailable_service_identities = optional(list(string), [])
unavailable_services = optional(list(string), [])
}))
@@ -141,13 +154,7 @@ variable "data_overrides" {
perimeter_name = string
is_dry_run = optional(bool, false)
}))
- logging_data_access = optional(map(object({
- ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
- DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
- DATA_WRITE = optional(object({ exempted_members = optional(list(string)) }))
- })))
})
nullable = false
default = {}
}
-
diff --git a/fast/stages/2-security/data/defaults.yaml b/fast/stages/2-security/data/defaults.yaml
index ecf913d2c..30ba51145 100644
--- a/fast/stages/2-security/data/defaults.yaml
+++ b/fast/stages/2-security/data/defaults.yaml
@@ -18,6 +18,8 @@ context:
locations:
primary: europe-west1
secondary: europe-west3
+ storage-default: eu
projects:
defaults:
- storage_location: eu
\ No newline at end of file
+ locations:
+ storage: $locations:storage-default
\ No newline at end of file
diff --git a/fast/stages/2-security/main.tf b/fast/stages/2-security/main.tf
index 9e55a5a8e..58efbae82 100644
--- a/fast/stages/2-security/main.tf
+++ b/fast/stages/2-security/main.tf
@@ -18,11 +18,14 @@ locals {
paths = {
for k, v in var.factories_config : k => try(pathexpand(v), null)
}
+ _ctx = {
+ for k, v in var.context : k => merge(v, try(local._defaults.context[k], {}))
+ }
# fail if we have no valid defaults
_defaults = yamldecode(file(local.paths.defaults))
- ctx = merge(var.context, {
+ ctx = merge(local._ctx, {
folder_ids = merge(
- var.folder_ids, var.context.folder_ids
+ var.folder_ids, local._ctx.folder_ids
)
iam_principals = merge(
var.iam_principals,
@@ -30,17 +33,13 @@ locals {
for k, v in var.service_accounts :
"service_accounts/${k}" => "serviceAccount:${v}"
},
- var.context.iam_principals,
- try(local._defaults.context.iam_principals, {})
+ local._ctx.iam_principals
)
- locations = merge(
- var.context.locations,
- try(local._defaults.context.locations, {})
- )
- perimeters = merge(var.perimeters, var.context.vpc_sc_perimeters)
- project_ids = merge(var.project_ids, var.context.project_ids)
- tag_keys = merge(var.tag_keys, var.context.tag_keys)
- tag_values = merge(var.tag_values, var.context.tag_values)
+ locations = local._ctx.locations
+ perimeters = merge(var.perimeters, local._ctx.vpc_sc_perimeters)
+ project_ids = merge(var.project_ids, local._ctx.project_ids)
+ tag_keys = merge(var.tag_keys, local._ctx.tag_keys)
+ tag_values = merge(var.tag_values, local._ctx.tag_values)
})
defaults = {
folder_name = try(local._defaults.global.folder_id, "security")
diff --git a/fast/stages/2-security/schemas/defaults.schema.json b/fast/stages/2-security/schemas/defaults.schema.json
index b8889686e..f7ae98763 100644
--- a/fast/stages/2-security/schemas/defaults.schema.json
+++ b/fast/stages/2-security/schemas/defaults.schema.json
@@ -73,6 +73,63 @@
}
}
},
+ "locations": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "bigquery": {
+ "type": "string"
+ },
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
+ }
+ }
+ },
+ "logging_data_access": {
+ "type": "object",
+ "default": {},
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "ADMIN_READ": {
+ "type": "object",
+ "properties": {
+ "exempted_members": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "DATA_READ": {
+ "type": "object",
+ "properties": {
+ "exempted_members": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "DATA_WRITE": {
+ "type": "object",
+ "properties": {
+ "exempted_members": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"metric_scopes": {
"type": "array",
"default": [],
@@ -198,9 +255,6 @@
"host_project"
]
},
- "storage_location": {
- "type": "string"
- },
"tag_bindings": {
"type": "object",
"default": {},
@@ -227,6 +281,34 @@
}
}
},
+ "universe": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "domain",
+ "prefix"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string"
+ },
+ "forced_jit_service_identities": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "unavailable_service_identities": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
"vpc_sc": {
"type": "object",
"properties": {
@@ -241,48 +323,6 @@
"required": [
"perimeter_name"
]
- },
- "logging_data_access": {
- "type": "object",
- "default": {},
- "additionalProperties": {
- "type": "object",
- "properties": {
- "ADMIN_READ": {
- "type": "object",
- "properties": {
- "exempted_members": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "DATA_READ": {
- "type": "object",
- "properties": {
- "exempted_members": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "DATA_WRITE": {
- "type": "object",
- "properties": {
- "exempted_members": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- }
- }
- }
}
}
},
@@ -323,68 +363,20 @@
"ABANDON"
]
},
- "parent": {
- "type": "string"
- },
- "prefix": {
- "type": "string"
- },
- "service_encryption_key_ids": {
+ "locations": {
"type": "object",
- "default": {},
"additionalProperties": false,
- "patternProperties": {
- "^[a-z0-9_-]+$": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- },
- "storage_location": {
- "type": "string"
- },
- "tag_bindings": {
- "type": "object",
- "default": {},
- "additionalProperties": {
- "type": "string"
- }
- },
- "service_accounts": {
- "type": "object",
- "default": {},
- "additionalProperties": {
- "type": "object",
- "properties": {
- "display_name": {
- "type": "string",
- "default": "Terraform-managed."
- },
- "iam_self_roles": {
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
- }
- },
- "vpc_sc": {
- "type": "object",
"properties": {
- "perimeter_name": {
+ "bigquery": {
"type": "string"
},
- "is_dry_run": {
- "type": "boolean",
- "default": false
+ "logging": {
+ "type": "string"
+ },
+ "storage": {
+ "type": "string"
}
- },
- "required": [
- "perimeter_name"
- ]
+ }
},
"logging_data_access": {
"type": "object",
@@ -427,6 +419,94 @@
}
}
}
+ },
+ "parent": {
+ "type": "string"
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "service_encryption_key_ids": {
+ "type": "object",
+ "default": {},
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-z0-9_-]+$": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "tag_bindings": {
+ "type": "object",
+ "default": {},
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "service_accounts": {
+ "type": "object",
+ "default": {},
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "display_name": {
+ "type": "string",
+ "default": "Terraform-managed."
+ },
+ "iam_self_roles": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "universe": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "domain",
+ "prefix"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string"
+ },
+ "forced_jit_service_identities": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "prefix": {
+ "type": "string"
+ },
+ "unavailable_service_identities": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "vpc_sc": {
+ "type": "object",
+ "properties": {
+ "perimeter_name": {
+ "type": "string"
+ },
+ "is_dry_run": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "required": [
+ "perimeter_name"
+ ]
}
}
}
@@ -436,6 +516,24 @@
"type": "object",
"additionalProperties": false,
"properties": {
+ "custom_roles": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "folder_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "kms_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
"iam_principals": {
"type": "object",
"additionalProperties": {
@@ -447,6 +545,48 @@
"additionalProperties": {
"type": "string"
}
+ },
+ "notification_channels": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "project_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "service_account_ids": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_keys": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tag_values": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_host_projects": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "vpc_sc_perimeters": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
}
}
}
diff --git a/modules/logging-bucket/main.tf b/modules/logging-bucket/main.tf
index 8617fadd9..65178511c 100644
--- a/modules/logging-bucket/main.tf
+++ b/modules/logging-bucket/main.tf
@@ -27,6 +27,9 @@ locals {
}
}
ctx_p = "$"
+ location = lookup(
+ local.ctx.locations, var.location, var.location
+ )
parent_id = (
var.parent_type == "project"
? lookup(local.ctx.project_ids, var.parent, var.parent)
@@ -40,11 +43,9 @@ locals {
}
resource "google_logging_project_bucket_config" "bucket" {
- count = var.parent_type == "project" ? 1 : 0
- project = local.parent_id
- location = lookup(
- local.ctx.locations, var.location, var.location
- )
+ count = var.parent_type == "project" ? 1 : 0
+ project = local.parent_id
+ location = local.location
retention_days = var.retention
bucket_id = var.name
description = var.description
@@ -58,11 +59,9 @@ resource "google_logging_project_bucket_config" "bucket" {
}
resource "google_logging_folder_bucket_config" "bucket" {
- count = var.parent_type == "folder" ? 1 : 0
- folder = local.parent_id
- location = lookup(
- local.ctx.locations, var.location, var.location
- )
+ count = var.parent_type == "folder" ? 1 : 0
+ folder = local.parent_id
+ location = local.location
retention_days = var.retention
bucket_id = var.name
description = var.description
@@ -73,16 +72,14 @@ resource "google_logging_linked_dataset" "dataset" {
link_id = var.log_analytics.dataset_link_id
parent = "projects/${google_logging_project_bucket_config.bucket[0].project}"
bucket = google_logging_project_bucket_config.bucket[0].id
- location = var.location
+ location = local.location
description = var.log_analytics.description
}
resource "google_logging_organization_bucket_config" "bucket" {
- count = var.parent_type == "organization" ? 1 : 0
- organization = local.parent_id
- location = lookup(
- local.ctx.locations, var.location, var.location
- )
+ count = var.parent_type == "organization" ? 1 : 0
+ organization = local.parent_id
+ location = local.location
retention_days = var.retention
bucket_id = var.name
description = var.description
@@ -91,12 +88,10 @@ resource "google_logging_organization_bucket_config" "bucket" {
resource "google_logging_billing_account_bucket_config" "bucket" {
count = var.parent_type == "billing_account" ? 1 : 0
billing_account = local.parent_id
- location = lookup(
- local.ctx.locations, var.location, var.location
- )
- retention_days = var.retention
- bucket_id = var.name
- description = var.description
+ location = local.location
+ retention_days = var.retention
+ bucket_id = var.name
+ description = var.description
}
resource "google_logging_log_view" "views" {
diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md
index 98337dc2a..906db469f 100644
--- a/modules/project-factory/README.md
+++ b/modules/project-factory/README.md
@@ -421,8 +421,10 @@ module "project-factory" {
}
# use a default billing account if none is specified via yaml
data_defaults = {
- billing_account = var.billing_account_id
- storage_location = "EU"
+ billing_account = var.billing_account_id
+ locations = {
+ storage = "EU"
+ }
}
# make sure the environment label and stackdriver service are always added
data_merges = {
@@ -706,14 +708,14 @@ service_accounts:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [factories_config](variables.tf#L175) | Path to folder with YAML resource description data files. | object({…}) | ✓ | |
+| [factories_config](variables.tf#L181) | Path to folder with YAML resource description data files. | object({…}) | ✓ | |
| [context](variables.tf#L17) | Context-specific interpolations. | object({…}) | | {} |
-| [data_defaults](variables.tf#L36) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} |
-| [data_merges](variables.tf#L109) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} |
-| [data_overrides](variables.tf#L128) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} |
+| [data_defaults](variables.tf#L36) | Optional default values used when corresponding project or folder data from files are missing. | object({…}) | | {} |
+| [data_merges](variables.tf#L112) | Optional values that will be merged with corresponding data from files. Combines with `data_defaults`, file data, and `data_overrides`. | object({…}) | | {} |
+| [data_overrides](variables.tf#L131) | Optional values that override corresponding data from files. Takes precedence over file data and `data_defaults`. | object({…}) | | {} |
| [folders](variables-folders.tf#L17) | Folders data merged with factory data. | map(object({…})) | | {} |
| [notification_channels](variables-billing.tf#L17) | Notification channels used by budget alerts. | map(object({…})) | | {} |
-| [projects](variables-projects.tf#L17) | Projects data merged with factory data. | map(object({…})) | | {} |
+| [projects](variables-projects.tf#L17) | Projects data merged with factory data. | map(object({…})) | | {} |
## Outputs
@@ -739,8 +741,10 @@ These tests validate fixes to the project factory.
module "project-factory" {
source = "./fabric/modules/project-factory"
data_defaults = {
- billing_account = "012345-67890A-ABCDEF"
- storage_location = "eu"
+ billing_account = "012345-67890A-ABCDEF"
+ locations = {
+ storage = "eu"
+ }
}
data_merges = {
labels = {
diff --git a/modules/project-factory/automation.tf b/modules/project-factory/automation.tf
index 11a52070f..e503e6310 100644
--- a/modules/project-factory/automation.tf
+++ b/modules/project-factory/automation.tf
@@ -101,9 +101,9 @@ module "automation-bucket" {
labels = lookup(each.value, "labels", {})
managed_folders = lookup(each.value, "managed_folders", {})
location = each.value.create == false ? null : coalesce(
- local.data_defaults.overrides.storage_location,
+ local.data_defaults.overrides.locations.storage,
lookup(each.value, "location", null),
- local.data_defaults.defaults.storage_location
+ local.data_defaults.defaults.locations.storage
)
storage_class = lookup(
each.value, "storage_class", "STANDARD"
diff --git a/modules/project-factory/main.tf b/modules/project-factory/main.tf
index ea74e1d63..8d6194301 100644
--- a/modules/project-factory/main.tf
+++ b/modules/project-factory/main.tf
@@ -32,10 +32,10 @@ resource "terraform_data" "defaults_preconditions" {
lifecycle {
precondition {
condition = (
- var.data_defaults.storage_location != null ||
- var.data_overrides.storage_location != null
+ var.data_defaults.locations.storage != null ||
+ var.data_overrides.locations.storage != null
)
- error_message = "No default storage location defined in defaults or overides variables."
+ error_message = "No default storage location defined in defaults or overrides variables."
}
}
}
diff --git a/modules/project-factory/projects-bigquery.tf b/modules/project-factory/projects-bigquery.tf
index 7f88337f8..7e77ef74b 100644
--- a/modules/project-factory/projects-bigquery.tf
+++ b/modules/project-factory/projects-bigquery.tf
@@ -36,17 +36,18 @@ module "bigquery-datasets" {
project_id = module.projects[each.value.project_key].project_id
id = each.value.id
context = merge(local.ctx, {
- project_ids = local.ctx_project_ids
iam_principals = merge(
local.ctx.iam_principals,
local.projects_sas_iam_emails,
local.automation_sas_iam_emails
)
+ locations = local.ctx.locations
+ project_ids = local.ctx_project_ids
})
friendly_name = each.value.friendly_name
location = coalesce(
- local.data_defaults.overrides.bigquery_location,
+ local.data_defaults.overrides.locations.bigquery,
lookup(each.value, "location", null),
- local.data_defaults.defaults.bigquery_location
+ local.data_defaults.defaults.locations.bigquery
)
}
diff --git a/modules/project-factory/projects-buckets.tf b/modules/project-factory/projects-buckets.tf
index e200c4cd4..91d6d3ac6 100644
--- a/modules/project-factory/projects-buckets.tf
+++ b/modules/project-factory/projects-buckets.tf
@@ -67,12 +67,13 @@ module "buckets" {
encryption_key = each.value.encryption_key
force_destroy = each.value.force_destroy
context = merge(local.ctx, {
- project_ids = local.ctx_project_ids
iam_principals = merge(
local.ctx.iam_principals,
local.projects_sas_iam_emails,
local.automation_sas_iam_emails
)
+ locations = local.ctx.locations
+ project_ids = local.ctx_project_ids
})
iam = each.value.iam
iam_bindings = each.value.iam_bindings
@@ -80,9 +81,9 @@ module "buckets" {
iam_by_principals = each.value.iam_by_principals
labels = each.value.labels
location = coalesce(
- local.data_defaults.overrides.storage_location,
+ local.data_defaults.overrides.locations.storage,
lookup(each.value, "location", null),
- local.data_defaults.defaults.storage_location
+ local.data_defaults.defaults.locations.storage
)
managed_folders = each.value.managed_folders
storage_class = each.value.storage_class
diff --git a/modules/project-factory/projects-defaults.tf b/modules/project-factory/projects-defaults.tf
index 42f90801d..09b1ccbfc 100644
--- a/modules/project-factory/projects-defaults.tf
+++ b/modules/project-factory/projects-defaults.tf
@@ -25,133 +25,6 @@ locals {
defaults = try(var.data_defaults, {})
overrides = try(var.data_overrides, {})
}
- data_defaults = {
- defaults = merge(
- {
- billing_account = null
- contacts = {}
- deletion_policy = null
- factories_config = merge(
- {
- custom_roles = null
- observability = null
- org_policies = null
- quotas = null
- },
- try(local._data_defaults.defaults.factories_config, {
- custom_roles = null
- observability = null
- org_policies = null
- quotas = null
- }
- )
- )
- labels = {}
- metric_scopes = []
- parent = null
- prefix = null
- project_reuse = merge(
- {
- use_data_source = true
- attributes = null
- },
- try(local._data_defaults.defaults.project_reuse, {
- use_data_source = true
- attributes = null
- }
- )
- )
- service_encryption_key_ids = {}
- services = []
- shared_vpc_service_config = merge(
- {
- host_project = null
- iam_bindings_additive = {}
- network_users = []
- service_agent_iam = {}
- service_agent_subnet_iam = {}
- service_iam_grants = []
- network_subnet_users = {}
- },
- try(local._data_defaults.defaults.shared_vpc_service_config, {
- host_project = null
- iam_bindings_additive = {}
- network_users = []
- service_agent_iam = {}
- service_agent_subnet_iam = {}
- service_iam_grants = []
- network_subnet_users = {}
- }
- )
- )
- storage_location = null
- tag_bindings = {}
- service_accounts = {}
- universe = null
- vpc_sc = merge(
- {
- perimeter_name = null
- is_dry_run = false
- },
- try(local._data_defaults.defaults.vpc_sc, {
- perimeter_name = null
- is_dry_run = false
- }
- )
- )
- logging_data_access = {}
- bigquery_location = null
- },
- try(
- local._data_defaults.defaults, {}
- )
- )
- # data_overrides default to null's, to mark that they should not override
- overrides = merge({
- billing_account = null
- contacts = null
- deletion_policy = null
- factories_config = merge(
- {
- custom_roles = null
- observability = null
- org_policies = null
- quotas = null
- },
- try(local._data_defaults.overrides.factories_config, {
- custom_roles = null
- observability = null
- org_policies = null
- quotas = null
- }
- )
- )
- parent = null
- prefix = null
- service_encryption_key_ids = null
- storage_location = null
- tag_bindings = null
- services = null
- service_accounts = null
- universe = null
- vpc_sc = try(
- merge(
- {
- perimeter_name = null
- is_dry_run = false
- },
- local._data_defaults.overrides.vpc_sc
- ),
- null
- )
- logging_data_access = null
- bigquery_location = null
- },
- try(
- local._data_defaults.overrides, {}
- )
- )
- }
_projects_output = {
# Semantics of the merges are:
# - if data_overrides. is not null, use this value
@@ -350,4 +223,137 @@ locals {
for k, v in local._projects_output :
"${v.prefix != null ? v.prefix : ""}-${v.name}" => k
}
+ data_defaults = {
+ defaults = merge(
+ {
+ billing_account = null
+ contacts = {}
+ deletion_policy = null
+ factories_config = merge(
+ {
+ custom_roles = null
+ observability = null
+ org_policies = null
+ quotas = null
+ },
+ try(local._data_defaults.defaults.factories_config, {
+ custom_roles = null
+ observability = null
+ org_policies = null
+ quotas = null
+ }
+ )
+ )
+ labels = {}
+ locations = {
+ bigquery = try(local._data_defaults.defaults.locations.bigquery, null)
+ logging = try(local._data_defaults.defaults.locations.logging, null)
+ storage = try(local._data_defaults.defaults.locations.storage, null)
+ }
+ logging_data_access = {}
+ metric_scopes = []
+ parent = null
+ prefix = null
+ project_reuse = merge(
+ {
+ use_data_source = true
+ attributes = null
+ },
+ try(local._data_defaults.defaults.project_reuse, {
+ use_data_source = true
+ attributes = null
+ }
+ )
+ )
+ service_encryption_key_ids = {}
+ services = []
+ shared_vpc_service_config = merge(
+ {
+ host_project = null
+ iam_bindings_additive = {}
+ network_users = []
+ service_agent_iam = {}
+ service_agent_subnet_iam = {}
+ service_iam_grants = []
+ network_subnet_users = {}
+ },
+ try(local._data_defaults.defaults.shared_vpc_service_config, {
+ host_project = null
+ iam_bindings_additive = {}
+ network_users = []
+ service_agent_iam = {}
+ service_agent_subnet_iam = {}
+ service_iam_grants = []
+ network_subnet_users = {}
+ }
+ )
+ )
+ tag_bindings = {}
+ service_accounts = {}
+ universe = null
+ vpc_sc = merge(
+ {
+ perimeter_name = null
+ is_dry_run = false
+ },
+ try(local._data_defaults.defaults.vpc_sc, {
+ perimeter_name = null
+ is_dry_run = false
+ }
+ )
+ )
+ },
+ try(
+ local._data_defaults.defaults, {}
+ )
+ )
+ # data_overrides default to null's, to mark that they should not override
+ overrides = merge({
+ billing_account = null
+ contacts = null
+ deletion_policy = null
+ factories_config = merge(
+ {
+ custom_roles = null
+ observability = null
+ org_policies = null
+ quotas = null
+ },
+ try(local._data_defaults.overrides.factories_config, {
+ custom_roles = null
+ observability = null
+ org_policies = null
+ quotas = null
+ }
+ )
+ )
+ locations = {
+ bigquery = try(local._data_defaults.overrides.locations.bigquery, null)
+ logging = try(local._data_defaults.overrides.locations.logging, null)
+ storage = try(local._data_defaults.overrides.locations.storage, null)
+ }
+ logging_data_access = null
+ parent = null
+ prefix = null
+ service_encryption_key_ids = null
+ tag_bindings = null
+ services = null
+ service_accounts = null
+ universe = null
+ vpc_sc = try(
+ merge(
+ {
+ perimeter_name = null
+ is_dry_run = false
+ },
+ local._data_defaults.overrides.vpc_sc
+ ),
+ null
+ )
+ },
+ try(
+ local._data_defaults.overrides, {}
+ )
+ )
+ }
}
diff --git a/modules/project-factory/projects-log-buckets.tf b/modules/project-factory/projects-log-buckets.tf
index 69301f665..ce822fd9d 100644
--- a/modules/project-factory/projects-log-buckets.tf
+++ b/modules/project-factory/projects-log-buckets.tf
@@ -23,8 +23,10 @@ locals {
name = name
description = lookup(opts, "description", "Terraform-managed.")
kms_key_name = lookup(opts, "kms_key_name", null)
- location = try(
- lookup(local.ctx.locations, opts.location, opts.location),
+ location = coalesce(
+ local.data_defaults.overrides.locations.logging,
+ lookup(opts, "location", null),
+ local.data_defaults.defaults.locations.logging,
"global"
)
retention = lookup(opts, "retention", null)
@@ -44,13 +46,14 @@ module "log-buckets" {
location = each.value.location
kms_key_name = each.value.kms_key_name
context = merge(local.ctx, {
- folder_ids = local.ctx_folder_ids
- project_ids = local.ctx_project_ids
+ folder_ids = local.ctx_folder_ids
iam_principals = merge(
local.ctx.iam_principals,
local.projects_sas_iam_emails,
local.automation_sas_iam_emails
)
+ locations = local.ctx.locations
+ project_ids = local.ctx_project_ids
})
retention = each.value.retention
log_analytics = each.value.log_analytics
diff --git a/modules/project-factory/schemas/project.schema.json b/modules/project-factory/schemas/project.schema.json
index 6bb9ffe1c..1a326aa52 100644
--- a/modules/project-factory/schemas/project.schema.json
+++ b/modules/project-factory/schemas/project.schema.json
@@ -88,6 +88,24 @@
}
}
},
+ "datasets": {
+ "type": "object",
+ "additionalProperties": false,
+ "patternProperties": {
+ "^[a-z0-9_]+$": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "friendly_name": {
+ "type": "string"
+ },
+ "location": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
"deletion_policy": {
"type": "string",
"enum": [
@@ -529,24 +547,6 @@
"type": "boolean"
}
}
- },
- "datasets": {
- "type": "object",
- "additionalProperties": false,
- "patternProperties": {
- "^[a-z0-9_]+$": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "friendly_name": {
- "type": "string"
- },
- "location": {
- "type": "string"
- }
- }
- }
- }
}
},
"$defs": {
@@ -846,4 +846,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/modules/project-factory/variables-projects.tf b/modules/project-factory/variables-projects.tf
index 9d2b68ea7..4b959a7ae 100644
--- a/modules/project-factory/variables-projects.tf
+++ b/modules/project-factory/variables-projects.tf
@@ -153,7 +153,11 @@ variable "projects" {
})), {})
})), {})
contacts = optional(map(list(string)), {})
- iam = optional(map(list(string)), {})
+ datasets = optional(map(object({
+ friendly_name = optional(string)
+ location = optional(string)
+ })), {})
+ iam = optional(map(list(string)), {})
iam_bindings = optional(map(object({
members = list(string)
role = string
diff --git a/modules/project-factory/variables.tf b/modules/project-factory/variables.tf
index bbfa78d76..2e33347b3 100644
--- a/modules/project-factory/variables.tf
+++ b/modules/project-factory/variables.tf
@@ -49,6 +49,11 @@ variable "data_defaults" {
quotas = optional(string)
}), {})
labels = optional(map(string), {})
+ locations = optional(object({
+ bigquery = optional(string)
+ logging = optional(string)
+ storage = optional(string)
+ }), {})
logging_data_access = optional(map(object({
ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
@@ -88,8 +93,7 @@ variable "data_defaults" {
service_iam_grants = optional(list(string), [])
network_subnet_users = optional(map(list(string)), {})
}))
- storage_location = optional(string)
- tag_bindings = optional(map(string), {})
+ tag_bindings = optional(map(string), {})
universe = optional(object({
prefix = string
forced_jit_service_identities = optional(list(string), [])
@@ -100,7 +104,6 @@ variable "data_defaults" {
perimeter_name = string
is_dry_run = optional(bool, false)
}))
- bigquery_location = optional(string)
})
nullable = false
default = {}
@@ -141,6 +144,11 @@ variable "data_overrides" {
org_policies = optional(string)
quotas = optional(string)
}), {})
+ locations = optional(object({
+ bigquery = optional(string)
+ logging = optional(string)
+ storage = optional(string)
+ }), {})
logging_data_access = optional(map(object({
ADMIN_READ = optional(object({ exempted_members = optional(list(string)) })),
DATA_READ = optional(object({ exempted_members = optional(list(string)) })),
@@ -154,7 +162,6 @@ variable "data_overrides" {
})))
service_encryption_key_ids = optional(map(list(string)))
services = optional(list(string))
- storage_location = optional(string)
tag_bindings = optional(map(string))
universe = optional(object({
prefix = string
@@ -166,7 +173,6 @@ variable "data_overrides" {
perimeter_name = string
is_dry_run = optional(bool, false)
}))
- bigquery_location = optional(string)
})
nullable = false
default = {}
diff --git a/tests/fast/stages/s0_org_setup/data-simple/cicd.yaml b/tests/fast/stages/s0_org_setup/data-simple/cicd.yaml
index eef12642a..726c0ff83 100644
--- a/tests/fast/stages/s0_org_setup/data-simple/cicd.yaml
+++ b/tests/fast/stages/s0_org_setup/data-simple/cicd.yaml
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# yaml-language-server: $schema=../schemas/cicd.schema.json
+# yaml-language-server: $schema=../../../../../fast/stages/0-org-setup/schemas/cicd.schema.json
workload_identity_federation:
pool_name: iac-0
diff --git a/tests/fast/stages/s0_org_setup/data-simple/defaults.yaml b/tests/fast/stages/s0_org_setup/data-simple/defaults.yaml
index c1efefac0..ee5ea6619 100644
--- a/tests/fast/stages/s0_org_setup/data-simple/defaults.yaml
+++ b/tests/fast/stages/s0_org_setup/data-simple/defaults.yaml
@@ -12,15 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# yaml-language-server: $schema=../../../../../fast/stages/0-bootstrap-experimental/schemas/defaults.schema.json
+# yaml-language-server: $schema=../../../../../fast/stages/0-org-setup/schemas/defaults.schema.json
# defaults:
# storage_location: europe-west1
global:
billing_account: 012345-012345-012345
- locations:
- bigquery: europe-west1
- logging: europe-west1
organization:
domain: example.org
id: 1234567890
@@ -28,8 +25,10 @@ global:
projects:
defaults:
prefix: ft0
- storage_location: europe-west1
- bigquery_location: europe-west1
+ locations:
+ bigquery: $locations:primary
+ logging: $locations:primary
+ storage: $locations:primary
overrides: {}
output_files:
local_path: /tmp/fast-config
@@ -60,3 +59,5 @@ output_files:
context:
iam_principals:
gcp-organization-admins: group:fabric-fast-owners@google.com
+ locations:
+ primary: europe-west1
\ No newline at end of file
diff --git a/tests/fast/stages/s0_org_setup/not-simple.yaml b/tests/fast/stages/s0_org_setup/not-simple.yaml
index 86c44055b..3f2530c55 100644
--- a/tests/fast/stages/s0_org_setup/not-simple.yaml
+++ b/tests/fast/stages/s0_org_setup/not-simple.yaml
@@ -243,7 +243,7 @@ values:
google_storage_bucket_object.tfvars["globals"]:
bucket: ft0-prod-iac-core-0-iac-outputs
cache_control: null
- content: '{"billing_account":{"id":"012345-012345-012345"},"groups":{"domain":"domain:example.org","gcp-billing-admins":"group:gcp-billing-admins@example.org","gcp-devops":"group:gcp-devops@example.org","gcp-network-admins":"group:gcp-network-admins@example.org","gcp-organization-admins":"group:fabric-fast-owners@google.com","gcp-secops-admins":"group:gcp-secops-admins@example.org","gcp-security-admins":"group:gcp-security-admins@example.org","gcp-support":"group:gcp-support@example.org"},"locations":{"bigquery":"europe-west1","logging":"europe-west1","pubsub":[],"storage":"eu"},"organization":{"customer_id":"abcd123456","domain":"example.org","id":"1234567890"},"prefix":"ft0","universe":null}'
+ content: '{"billing_account":{"id":"012345-012345-012345"},"groups":{"domain":"domain:example.org","gcp-billing-admins":"group:gcp-billing-admins@example.org","gcp-devops":"group:gcp-devops@example.org","gcp-network-admins":"group:gcp-network-admins@example.org","gcp-organization-admins":"group:fabric-fast-owners@google.com","gcp-secops-admins":"group:gcp-secops-admins@example.org","gcp-security-admins":"group:gcp-security-admins@example.org","gcp-support":"group:gcp-support@example.org"},"organization":{"customer_id":"abcd123456","domain":"example.org","id":"1234567890"},"prefix":"ft0","universe":null}'
content_disposition: null
content_encoding: null
content_language: null
@@ -426,7 +426,7 @@ values:
sensitive_content: null
source: null
local_file.tfvars["globals"]:
- content: '{"billing_account":{"id":"012345-012345-012345"},"groups":{"domain":"domain:example.org","gcp-billing-admins":"group:gcp-billing-admins@example.org","gcp-devops":"group:gcp-devops@example.org","gcp-network-admins":"group:gcp-network-admins@example.org","gcp-organization-admins":"group:fabric-fast-owners@google.com","gcp-secops-admins":"group:gcp-secops-admins@example.org","gcp-security-admins":"group:gcp-security-admins@example.org","gcp-support":"group:gcp-support@example.org"},"locations":{"bigquery":"europe-west1","logging":"europe-west1","pubsub":[],"storage":"eu"},"organization":{"customer_id":"abcd123456","domain":"example.org","id":"1234567890"},"prefix":"ft0","universe":null}'
+ content: '{"billing_account":{"id":"012345-012345-012345"},"groups":{"domain":"domain:example.org","gcp-billing-admins":"group:gcp-billing-admins@example.org","gcp-devops":"group:gcp-devops@example.org","gcp-network-admins":"group:gcp-network-admins@example.org","gcp-organization-admins":"group:fabric-fast-owners@google.com","gcp-secops-admins":"group:gcp-secops-admins@example.org","gcp-security-admins":"group:gcp-security-admins@example.org","gcp-support":"group:gcp-support@example.org"},"organization":{"customer_id":"abcd123456","domain":"example.org","id":"1234567890"},"prefix":"ft0","universe":null}'
content_base64: null
directory_permission: '0777'
file_permission: '0644'
@@ -1011,7 +1011,7 @@ values:
cmek_settings: []
enable_analytics: false
index_configs: []
- location: global
+ location: europe-west1
locked: null
project: ft0-prod-audit-logs-0
retention_days: 30
@@ -1020,7 +1020,7 @@ values:
cmek_settings: []
enable_analytics: false
index_configs: []
- location: global
+ location: europe-west1
locked: null
project: ft0-prod-audit-logs-0
retention_days: 30
@@ -1029,7 +1029,7 @@ values:
cmek_settings: []
enable_analytics: true
index_configs: []
- location: global
+ location: europe-west1
locked: null
project: ft0-prod-audit-logs-0
retention_days: 31
diff --git a/tests/fast/stages/s2_project_factory/simple.tfvars b/tests/fast/stages/s2_project_factory/simple.tfvars
index eaae77f48..70a02d32d 100644
--- a/tests/fast/stages/s2_project_factory/simple.tfvars
+++ b/tests/fast/stages/s2_project_factory/simple.tfvars
@@ -12,3 +12,8 @@ tag_values = {
"environment/development" = "tagValues/1234567890"
"environment/production" = "tagValues/2345678901"
}
+data_defaults = {
+ locations = {
+ storage = "europe-west1"
+ }
+}
diff --git a/tests/fast/stages/s2_security/data-simple/defaults.yaml b/tests/fast/stages/s2_security/data-simple/defaults.yaml
index c674bfe60..070e79741 100644
--- a/tests/fast/stages/s2_security/data-simple/defaults.yaml
+++ b/tests/fast/stages/s2_security/data-simple/defaults.yaml
@@ -20,4 +20,5 @@ context:
secondary: europe-west3
projects:
defaults:
- storage_location: eu
\ No newline at end of file
+ locations:
+ storage: eu