diff --git a/modules/folder/README.md b/modules/folder/README.md
index 2efb626b97..ff242aeec0 100644
--- a/modules/folder/README.md
+++ b/modules/folder/README.md
@@ -345,12 +345,13 @@ module "folder" {
| name | description | resources |
|---|---|---|
| [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
|
+| [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_settings
· 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
|
| [outputs.tf](./outputs.tf) | Module outputs. | |
| [tags.tf](./tags.tf) | None | google_tags_tag_binding
|
| [variables-iam.tf](./variables-iam.tf) | None | |
+| [variables-logging.tf](./variables-logging.tf) | None | |
| [variables.tf](./variables.tf) | Module variables. | |
| [versions.tf](./versions.tf) | Version pins. | |
@@ -367,13 +368,14 @@ module "folder" {
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
| [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string))
| | {}
|
| [id](variables.tf#L48) | Folder ID in case you use folder_create=false. | string
| | null
|
-| [logging_data_access](variables.tf#L54) | 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#L69) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string)
| | {}
|
-| [logging_sinks](variables.tf#L76) | Logging sinks to create for the folder. | map(object({…}))
| | {}
|
-| [name](variables.tf#L107) | Folder name. | string
| | null
|
-| [org_policies](variables.tf#L113) | Organization policies applied to this folder keyed by policy name. | map(object({…}))
| | {}
|
-| [parent](variables.tf#L140) | Parent in folders/folder_id or organizations/org_id format. | string
| | null
|
-| [tag_bindings](variables.tf#L150) | Tag bindings for this folder, in key => tag value id format. | map(string)
| | null
|
+| [logging_data_access](variables-logging.tf#L17) | 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-logging.tf#L32) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string)
| | {}
|
+| [logging_settings](variables-logging.tf#L39) | Default settings for logging resources. | object({…})
| | null
|
+| [logging_sinks](variables-logging.tf#L49) | Logging sinks to create for the folder. | map(object({…}))
| | {}
|
+| [name](variables.tf#L54) | Folder name. | string
| | null
|
+| [org_policies](variables.tf#L60) | Organization policies applied to this folder keyed by policy name. | map(object({…}))
| | {}
|
+| [parent](variables.tf#L87) | Parent in folders/folder_id or organizations/org_id format. | string
| | null
|
+| [tag_bindings](variables.tf#L97) | Tag bindings for this folder, in key => tag value id format. | map(string)
| | null
|
## Outputs
diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf
index 817c4d1e06..bb42983c22 100644
--- a/modules/folder/logging.tf
+++ b/modules/folder/logging.tf
@@ -35,6 +35,13 @@ locals {
}
}
+resource "google_logging_folder_settings" "default" {
+ count = var.logging_settings != null ? 1 : 0
+ folder = local.folder_id
+ disable_default_sink = var.logging_settings.disable_default_sink
+ storage_location = var.logging_settings.storage_location
+}
+
resource "google_folder_iam_audit_config" "default" {
for_each = var.logging_data_access
folder = local.folder_id
diff --git a/modules/folder/variables-logging.tf b/modules/folder/variables-logging.tf
new file mode 100644
index 0000000000..89685a6de9
--- /dev/null
+++ b/modules/folder/variables-logging.tf
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "logging_data_access" {
+ description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
+ type = map(map(list(string)))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue(flatten([
+ for k, v in var.logging_data_access : [
+ for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
+ ]
+ ]))
+ error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
+ }
+}
+
+variable "logging_exclusions" {
+ description = "Logging exclusions for this folder in the form {NAME -> FILTER}."
+ type = map(string)
+ default = {}
+ 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 folder."
+ type = map(object({
+ bq_partitioned_table = optional(bool, false)
+ description = optional(string)
+ destination = string
+ disabled = optional(bool, false)
+ exclusions = optional(map(string), {})
+ filter = optional(string)
+ iam = optional(bool, true)
+ include_children = optional(bool, true)
+ type = string
+ }))
+ default = {}
+ nullable = false
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
+ ])
+ error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
+ }
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ v.bq_partitioned_table != true || v.type == "bigquery"
+ ])
+ error_message = "Can only set bq_partitioned_table when type is `bigquery`."
+ }
+}
diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf
index 6da2685a71..e5f6d548be 100644
--- a/modules/folder/variables.tf
+++ b/modules/folder/variables.tf
@@ -51,59 +51,6 @@ variable "id" {
default = null
}
-variable "logging_data_access" {
- description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
- type = map(map(list(string)))
- nullable = false
- default = {}
- validation {
- condition = alltrue(flatten([
- for k, v in var.logging_data_access : [
- for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
- ]
- ]))
- error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
- }
-}
-
-variable "logging_exclusions" {
- description = "Logging exclusions for this folder in the form {NAME -> FILTER}."
- type = map(string)
- default = {}
- nullable = false
-}
-
-variable "logging_sinks" {
- description = "Logging sinks to create for the folder."
- type = map(object({
- bq_partitioned_table = optional(bool, false)
- description = optional(string)
- destination = string
- disabled = optional(bool, false)
- exclusions = optional(map(string), {})
- filter = optional(string)
- iam = optional(bool, true)
- include_children = optional(bool, true)
- type = string
- }))
- default = {}
- nullable = false
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
- ])
- error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
- }
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- v.bq_partitioned_table != true || v.type == "bigquery"
- ])
- error_message = "Can only set bq_partitioned_table when type is `bigquery`."
- }
-}
-
variable "name" {
description = "Folder name."
type = string
diff --git a/modules/organization/README.md b/modules/organization/README.md
index cc602a6f12..1b004aa623 100644
--- a/modules/organization/README.md
+++ b/modules/organization/README.md
@@ -500,6 +500,7 @@ module "org" {
| [outputs.tf](./outputs.tf) | Module outputs. | |
| [tags.tf](./tags.tf) | None | google_tags_tag_binding
· google_tags_tag_key
· google_tags_tag_key_iam_binding
· google_tags_tag_value
· google_tags_tag_value_iam_binding
|
| [variables-iam.tf](./variables-iam.tf) | None | |
+| [variables-logging.tf](./variables-logging.tf) | None | |
| [variables-tags.tf](./variables-tags.tf) | None | |
| [variables.tf](./variables.tf) | Module variables. | |
| [versions.tf](./versions.tf) | Version pins. | |
@@ -508,7 +509,7 @@ module "org" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [organization_id](variables.tf#L155) | Organization id in organizations/nnnnnn format. | string
| ✓ | |
+| [organization_id](variables.tf#L92) | 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({…})
| | {}
|
@@ -517,13 +518,13 @@ module "org" {
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…}))
| | {}
|
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…}))
| | {}
|
| [iam_by_principals](variables-iam.tf#L54) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | map(list(string))
| | {}
|
-| [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_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({…}))
| | {}
|
+| [logging_data_access](variables-logging.tf#L17) | 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-logging.tf#L32) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string)
| | {}
|
+| [logging_settings](variables-logging.tf#L39) | Default settings for logging resources. | object({…})
| | null
|
+| [logging_sinks](variables-logging.tf#L49) | 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#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({…}))
| | {}
|
+| [org_policies](variables.tf#L51) | Organization policies applied to this organization keyed by policy name. | map(object({…}))
| | {}
|
+| [org_policy_custom_constraints](variables.tf#L78) | 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({…}))
| | {}
|
diff --git a/modules/organization/variables-logging.tf b/modules/organization/variables-logging.tf
new file mode 100644
index 0000000000..210352f081
--- /dev/null
+++ b/modules/organization/variables-logging.tf
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+variable "logging_data_access" {
+ description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
+ type = map(map(list(string)))
+ nullable = false
+ default = {}
+ validation {
+ condition = alltrue(flatten([
+ for k, v in var.logging_data_access : [
+ for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
+ ]
+ ]))
+ error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
+ }
+}
+
+variable "logging_exclusions" {
+ description = "Logging exclusions for this organization in the form {NAME -> FILTER}."
+ type = map(string)
+ default = {}
+ 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({
+ bq_partitioned_table = optional(bool, false)
+ description = optional(string)
+ destination = string
+ disabled = optional(bool, false)
+ exclusions = optional(map(string), {})
+ filter = optional(string)
+ iam = optional(bool, true)
+ include_children = optional(bool, true)
+ type = string
+ }))
+ default = {}
+ nullable = false
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
+ ])
+ error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
+ }
+ validation {
+ condition = alltrue([
+ for k, v in var.logging_sinks :
+ v.bq_partitioned_table != true || v.type == "bigquery"
+ ])
+ error_message = "Can only set bq_partitioned_table when type is `bigquery`."
+ }
+}
diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf
index 4464558e69..146cf9b14a 100644
--- a/modules/organization/variables.tf
+++ b/modules/organization/variables.tf
@@ -48,69 +48,6 @@ variable "firewall_policy" {
default = null
}
-variable "logging_data_access" {
- description = "Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services."
- type = map(map(list(string)))
- nullable = false
- default = {}
- validation {
- condition = alltrue(flatten([
- for k, v in var.logging_data_access : [
- for kk, vv in v : contains(["DATA_READ", "DATA_WRITE", "ADMIN_READ"], kk)
- ]
- ]))
- error_message = "Log type keys for each service can only be one of 'DATA_READ', 'DATA_WRITE', 'ADMIN_READ'."
- }
-}
-
-variable "logging_exclusions" {
- description = "Logging exclusions for this organization in the form {NAME -> FILTER}."
- type = map(string)
- default = {}
- 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({
- bq_partitioned_table = optional(bool, false)
- description = optional(string)
- destination = string
- disabled = optional(bool, false)
- exclusions = optional(map(string), {})
- filter = optional(string)
- iam = optional(bool, true)
- include_children = optional(bool, true)
- type = string
- }))
- default = {}
- nullable = false
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type)
- ])
- error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'."
- }
- validation {
- condition = alltrue([
- for k, v in var.logging_sinks :
- v.bq_partitioned_table != true || v.type == "bigquery"
- ])
- error_message = "Can only set bq_partitioned_table when type is `bigquery`."
- }
-}
-
variable "org_policies" {
description = "Organization policies applied to this organization keyed by policy name."
type = map(object({