From bf5b7d5fbe8b194c807250c0fb88340ee7846f2e Mon Sep 17 00:00:00 2001 From: Ludo Date: Mon, 13 May 2024 08:40:17 +0200 Subject: [PATCH] add logging settings to folder module --- modules/folder/README.md | 18 +++--- modules/folder/logging.tf | 7 ++ modules/folder/variables-logging.tf | 78 +++++++++++++++++++++++ modules/folder/variables.tf | 53 --------------- modules/organization/README.md | 15 +++-- modules/organization/variables-logging.tf | 78 +++++++++++++++++++++++ modules/organization/variables.tf | 63 ------------------ 7 files changed, 181 insertions(+), 131 deletions(-) create mode 100644 modules/folder/variables-logging.tf create mode 100644 modules/organization/variables-logging.tf 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({