diff --git a/fast/stages/0-bootstrap/log-export.tf b/fast/stages/0-bootstrap/log-export.tf
index a9b7337052..ed87c24c7c 100644
--- a/fast/stages/0-bootstrap/log-export.tf
+++ b/fast/stages/0-bootstrap/log-export.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -69,7 +69,7 @@ module "log-export-dataset" {
source = "../../../modules/bigquery-dataset"
count = contains(local.log_types, "bigquery") ? 1 : 0
project_id = module.log-export-project.project_id
- id = "audit_export"
+ id = "logs"
friendly_name = "Audit logs export."
location = local.locations.bq
}
@@ -78,25 +78,29 @@ module "log-export-gcs" {
source = "../../../modules/gcs"
count = contains(local.log_types, "storage") ? 1 : 0
project_id = module.log-export-project.project_id
- name = "audit-logs-0"
+ name = "logs"
prefix = local.prefix
location = local.locations.gcs
storage_class = local.gcs_storage_class
}
module "log-export-logbucket" {
- source = "../../../modules/logging-bucket"
- for_each = toset([for k, v in var.log_sinks : k if v.type == "logging"])
- parent_type = "project"
- parent = module.log-export-project.project_id
- id = "audit-logs-${each.key}"
- location = local.locations.logging
+ source = "../../../modules/logging-bucket"
+ for_each = toset([for k, v in var.log_sinks : k if v.type == "logging"])
+ parent_type = "project"
+ parent = module.log-export-project.project_id
+ id = each.key
+ location = local.locations.logging
+ log_analytics = { enable = true }
+
+ # org-level logging settings ready before we create any logging buckets
+ depends_on = [module.organization-logging]
}
module "log-export-pubsub" {
source = "../../../modules/pubsub"
for_each = toset([for k, v in var.log_sinks : k if v.type == "pubsub"])
project_id = module.log-export-project.project_id
- name = "audit-logs-${each.key}"
+ name = each.key
regions = local.locations.pubsub
}
diff --git a/fast/stages/0-bootstrap/organization.tf b/fast/stages/0-bootstrap/organization.tf
index 44bd78c2dd..9249b57545 100644
--- a/fast/stages/0-bootstrap/organization.tf
+++ b/fast/stages/0-bootstrap/organization.tf
@@ -130,9 +130,22 @@ import {
to = module.organization.google_org_policy_policy.default[each.key]
}
-module "organization" {
+module "organization-logging" {
+ # Preconfigure organization-wide logging settings to ensure project
+ # log buckets (_Default, _Required) are created in the location
+ # specified by `var.locations.logging`. This separate
+ # organization-block prevents circular dependencies with later
+ # project creation.
source = "../../../modules/organization"
organization_id = "organizations/${var.organization.id}"
+ logging_settings = {
+ storage_location = var.locations.logging
+ }
+}
+
+module "organization" {
+ source = "../../../modules/organization"
+ organization_id = module.organization-logging.id
# human (groups) IAM bindings
iam_by_principals = {
for k, v in local.iam_principals :
diff --git a/modules/organization/README.md b/modules/organization/README.md
index 4c8a99b6ad..cc602a6f12 100644
--- a/modules/organization/README.md
+++ b/modules/organization/README.md
@@ -493,7 +493,7 @@ module "org" {
| name | description | resources |
|---|---|---|
| [iam.tf](./iam.tf) | IAM bindings. | google_organization_iam_binding
· google_organization_iam_custom_role
· google_organization_iam_member
|
-| [logging.tf](./logging.tf) | Log sinks and data access logs. | google_bigquery_dataset_iam_member
· google_logging_organization_exclusion
· google_logging_organization_sink
· google_organization_iam_audit_config
· google_project_iam_member
· google_pubsub_topic_iam_member
· google_storage_bucket_iam_member
|
+| [logging.tf](./logging.tf) | Log sinks and data access logs. | google_bigquery_dataset_iam_member
· google_logging_organization_exclusion
· google_logging_organization_settings
· google_logging_organization_sink
· google_organization_iam_audit_config
· google_project_iam_member
· google_pubsub_topic_iam_member
· google_storage_bucket_iam_member
|
| [main.tf](./main.tf) | Module-level locals and resources. | google_compute_firewall_policy_association
· google_essential_contacts_contact
|
| [org-policy-custom-constraints.tf](./org-policy-custom-constraints.tf) | None | google_org_policy_custom_constraint
|
| [organization-policies.tf](./organization-policies.tf) | Organization-level organization policies. | google_org_policy_policy
|
@@ -508,7 +508,7 @@ module "org" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [organization_id](variables.tf#L145) | Organization id in organizations/nnnnnn format. | string
| ✓ | |
+| [organization_id](variables.tf#L155) | Organization id in organizations/nnnnnn format. | string
| ✓ | |
| [contacts](variables.tf#L17) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string))
| | {}
|
| [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | map(list(string))
| | {}
|
| [factories_config](variables.tf#L31) | Paths to data files and folders that enable factory functionality. | object({…})
| | {}
|
@@ -519,10 +519,11 @@ module "org" {
| [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string))
| | {}
|
| [logging_data_access](variables.tf#L51) | 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#L66) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string)
| | {}
|
-| [logging_sinks](variables.tf#L73) | Logging sinks to create for the organization. | map(object({…}))
| | {}
|
+| [logging_settings](variables.tf#L73) | Default settings for logging resources. | object({…})
| | null
|
+| [logging_sinks](variables.tf#L83) | Logging sinks to create for the organization. | map(object({…}))
| | {}
|
| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…}))
| | {}
|
-| [org_policies](variables.tf#L104) | Organization policies applied to this organization keyed by policy name. | map(object({…}))
| | {}
|
-| [org_policy_custom_constraints](variables.tf#L131) | Organization policy custom constraints keyed by constraint name. | map(object({…}))
| | {}
|
+| [org_policies](variables.tf#L114) | Organization policies applied to this organization keyed by policy name. | map(object({…}))
| | {}
|
+| [org_policy_custom_constraints](variables.tf#L141) | Organization policy custom constraints keyed by constraint name. | map(object({…}))
| | {}
|
| [tag_bindings](variables-tags.tf#L45) | Tag bindings for this organization, in key => tag value id format. | map(string)
| | {}
|
| [tags](variables-tags.tf#L52) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…}))
| | {}
|
@@ -534,10 +535,10 @@ module "org" {
| [custom_role_id](outputs.tf#L22) | Map of custom role IDs created in the organization. | |
| [custom_roles](outputs.tf#L32) | Map of custom roles resources created in the organization. | |
| [id](outputs.tf#L37) | Fully qualified organization id. | |
-| [network_tag_keys](outputs.tf#L54) | Tag key resources. | |
-| [network_tag_values](outputs.tf#L63) | Tag value resources. | |
-| [organization_id](outputs.tf#L73) | Organization id dependent on module resources. | |
-| [sink_writer_identities](outputs.tf#L90) | Writer identities created for each sink. | |
-| [tag_keys](outputs.tf#L98) | Tag key resources. | |
-| [tag_values](outputs.tf#L107) | Tag value resources. | |
+| [network_tag_keys](outputs.tf#L55) | Tag key resources. | |
+| [network_tag_values](outputs.tf#L64) | Tag value resources. | |
+| [organization_id](outputs.tf#L74) | Organization id dependent on module resources. | |
+| [sink_writer_identities](outputs.tf#L91) | Writer identities created for each sink. | |
+| [tag_keys](outputs.tf#L99) | Tag key resources. | |
+| [tag_values](outputs.tf#L108) | Tag value resources. | |
diff --git a/modules/organization/logging.tf b/modules/organization/logging.tf
index 7f78c54683..c895c7fa8a 100644
--- a/modules/organization/logging.tf
+++ b/modules/organization/logging.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,13 @@ locals {
}
}
+resource "google_logging_organization_settings" "default" {
+ count = var.logging_settings != null ? 1 : 0
+ organization = local.organization_id_numeric
+ disable_default_sink = var.logging_settings.disable_default_sink
+ storage_location = var.logging_settings.storage_location
+}
+
resource "google_organization_iam_audit_config" "default" {
for_each = var.logging_data_access
org_id = local.organization_id_numeric
diff --git a/modules/organization/outputs.tf b/modules/organization/outputs.tf
index b010b29976..9422134a73 100644
--- a/modules/organization/outputs.tf
+++ b/modules/organization/outputs.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,12 +38,13 @@ output "id" {
description = "Fully qualified organization id."
value = var.organization_id
depends_on = [
+ google_logging_organization_settings.default,
google_org_policy_custom_constraint.constraint,
google_org_policy_policy.default,
google_organization_iam_binding.authoritative,
google_organization_iam_binding.bindings,
- google_organization_iam_member.bindings,
google_organization_iam_custom_role.roles,
+ google_organization_iam_member.bindings,
google_tags_tag_key.default,
google_tags_tag_key_iam_binding.default,
google_tags_tag_value.default,
diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf
index a3b24c7e31..4464558e69 100644
--- a/modules/organization/variables.tf
+++ b/modules/organization/variables.tf
@@ -1,5 +1,5 @@
/**
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,6 +70,16 @@ variable "logging_exclusions" {
nullable = false
}
+variable "logging_settings" {
+ description = "Default settings for logging resources."
+ type = object({
+ # TODO: add support for CMEK
+ disable_default_sink = optional(bool)
+ storage_location = optional(string)
+ })
+ default = null
+}
+
variable "logging_sinks" {
description = "Logging sinks to create for the organization."
type = map(object({
diff --git a/tests/fast/stages/s0_bootstrap/checklist.yaml b/tests/fast/stages/s0_bootstrap/checklist.yaml
index a111eb02c4..c6f6440946 100644
--- a/tests/fast/stages/s0_bootstrap/checklist.yaml
+++ b/tests/fast/stages/s0_bootstrap/checklist.yaml
@@ -14,27 +14,27 @@
values:
module.log-export-logbucket["audit-logs"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: audit-logs-audit-logs
+ bucket_id: audit-logs
cmek_settings: []
- enable_analytics: false
+ enable_analytics: true
index_configs: []
location: europe-west1
locked: null
project: fast-prod-audit-logs-0
retention_days: 30
module.log-export-logbucket["vpc-sc"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: audit-logs-vpc-sc
+ bucket_id: vpc-sc
cmek_settings: []
- enable_analytics: false
+ enable_analytics: true
index_configs: []
location: europe-west1
locked: null
project: fast-prod-audit-logs-0
retention_days: 30
module.log-export-logbucket["workspace-audit-logs"].google_logging_project_bucket_config.bucket[0]:
- bucket_id: audit-logs-workspace-audit-logs
+ bucket_id: workspace-audit-logs
cmek_settings: []
- enable_analytics: false
+ enable_analytics: true
index_configs: []
location: europe-west1
locked: null
@@ -380,5 +380,5 @@ counts:
google_storage_project_service_account: 3
google_tags_tag_key: 1
google_tags_tag_value: 1
- modules: 16
- resources: 191
+ modules: 17
+ resources: 192
diff --git a/tests/fast/stages/s0_bootstrap/simple.yaml b/tests/fast/stages/s0_bootstrap/simple.yaml
index 2180aa4540..0d7174df68 100644
--- a/tests/fast/stages/s0_bootstrap/simple.yaml
+++ b/tests/fast/stages/s0_bootstrap/simple.yaml
@@ -60,8 +60,8 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 1
local_file: 7
- modules: 15
- resources: 182
+ modules: 16
+ resources: 183
outputs:
custom_roles: