From 8d30076f834313499ab085e8e5c300f6b26d9123 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 20:51:25 +0100 Subject: [PATCH 1/7] Add project log sink destination to project module --- modules/project/README.md | 18 +++- modules/project/logging.tf | 19 +++- modules/project/variables.tf | 4 +- tests/modules/project/examples/logging.yaml | 101 +++++++++++++++++++- 4 files changed, 133 insertions(+), 9 deletions(-) diff --git a/modules/project/README.md b/modules/project/README.md index 292b63a42a..6a24ed74dd 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -561,6 +561,17 @@ module "bucket" { id = "${var.prefix}-bucket" } +module "destination-project" { + source = "./fabric/modules/project" + name = "destination-project" + billing_account = var.billing_account_id + parent = var.folder_id + prefix = var.prefix + services = [ + "logging.googleapis.com" + ] +} + module "project-host" { source = "./fabric/modules/project" name = "project" @@ -594,12 +605,17 @@ module "project-host" { } type = "logging" } + alert = { + destination = module.destination-project.id + filter = "severity=ALERT" + type = "project" + } } logging_exclusions = { no-gce-instances = "resource.type=gce_instance" } } -# tftest modules=5 resources=15 inventory=logging.yaml e2e +# tftest modules=6 resources=19 inventory=logging.yaml e2e ``` ## Data Access Logs diff --git a/modules/project/logging.tf b/modules/project/logging.tf index efd61ec266..4262fe6bac 100644 --- a/modules/project/logging.tf +++ b/modules/project/logging.tf @@ -17,8 +17,16 @@ # tfdoc:file:description Log sinks and supporting resources. locals { + logging_sinks = { + for k, v in var.logging_sinks : + # rewrite destination and type and type="project" + k => merge(v, v.type == "project" ? { + destination = "projects/${v.destination}" + type = "logging" + } : {}) + } sink_bindings = { - for type in ["bigquery", "pubsub", "logging", "storage"] : + for type in ["bigquery", "logging", "project", "pubsub", "storage"] : type => { for name, sink in var.logging_sinks : name => sink if sink.iam && sink.type == type @@ -41,7 +49,7 @@ resource "google_project_iam_audit_config" "default" { } resource "google_logging_project_sink" "sink" { - for_each = var.logging_sinks + for_each = local.logging_sinks name = each.key description = coalesce(each.value.description, "${each.key} (Terraform-managed).") project = local.project.project_id @@ -110,6 +118,13 @@ resource "google_project_iam_member" "bucket-sinks-binding" { } } +resource "google_project_iam_member" "project-sinks-binding" { + for_each = local.sink_bindings["project"] + project = each.value.destination + role = "roles/logging.logWriter" + member = google_logging_project_sink.sink[each.key].writer_identity +} + resource "google_logging_project_exclusion" "logging-exclusion" { for_each = var.logging_exclusions name = each.key diff --git a/modules/project/variables.tf b/modules/project/variables.tf index 85ad34c0ee..a82186c867 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -129,9 +129,9 @@ variable "logging_sinks" { validation { condition = alltrue([ for k, v in var.logging_sinks : - contains(["bigquery", "logging", "pubsub", "storage"], v.type) + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) ]) - error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'." + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." } validation { condition = alltrue([ diff --git a/tests/modules/project/examples/logging.yaml b/tests/modules/project/examples/logging.yaml index e07ef12287..55231cadd6 100644 --- a/tests/modules/project/examples/logging.yaml +++ b/tests/modules/project/examples/logging.yaml @@ -13,6 +13,62 @@ # limitations under the License. values: + module.bucket.google_logging_project_bucket_config.bucket[0]: + bucket_id: test-bucket + cmek_settings: [] + enable_analytics: false + index_configs: [] + location: global + locked: null + project: project-id + retention_days: 30 + module.dataset.google_bigquery_dataset.default: + dataset_id: bq_sink + default_encryption_configuration: [] + default_partition_expiration_ms: null + default_table_expiration_ms: null + delete_contents_on_destroy: true + description: Terraform managed. + friendly_name: null + labels: null + location: EU + max_time_travel_hours: '168' + project: project-id + module.destination-project.google_project.project[0]: + auto_create_network: false + billing_account: 123456-123456-123456 + folder_id: '1122334455' + labels: null + name: test-destination-project + org_id: null + project_id: test-destination-project + skip_delete: false + module.destination-project.google_project_service.project_services["logging.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-destination-project + service: logging.googleapis.com + module.gcs.google_storage_bucket.bucket: + autoclass: + - enabled: false + cors: [] + custom_placement_config: [] + default_event_based_hold: null + enable_object_retention: null + encryption: [] + force_destroy: true + labels: null + lifecycle_rule: [] + location: EU + logging: [] + name: test-gcs_sink + project: project-id + requester_pays: null + retention_policy: [] + storage_class: MULTI_REGIONAL + uniform_bucket_level_access: true + versioning: + - enabled: false module.project-host.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: condition: [] role: roles/bigquery.dataEditor @@ -22,7 +78,18 @@ values: filter: resource.type=gce_instance name: no-gce-instances project: test-project + module.project-host.google_logging_project_sink.sink["alert"]: + custom_writer_identity: null + description: alert (Terraform-managed). + destination: logging.googleapis.com/projects/test-destination-project + disabled: false + exclusions: [] + filter: severity=ALERT + name: alert + project: test-project + unique_writer_identity: true module.project-host.google_logging_project_sink.sink["debug"]: + custom_writer_identity: null description: debug (Terraform-managed). disabled: false exclusions: @@ -36,7 +103,8 @@ values: unique_writer_identity: true module.project-host.google_logging_project_sink.sink["info"]: bigquery_options: - - use_partitioned_tables: false + - use_partitioned_tables: false + custom_writer_identity: null description: info (Terraform-managed). disabled: false exclusions: [] @@ -45,7 +113,9 @@ values: project: test-project unique_writer_identity: true module.project-host.google_logging_project_sink.sink["notice"]: + custom_writer_identity: null description: notice (Terraform-managed). + destination: pubsub.googleapis.com/projects/project-id/topics/pubsub_sink disabled: false exclusions: [] filter: severity=NOTICE @@ -53,6 +123,7 @@ values: project: test-project unique_writer_identity: true module.project-host.google_logging_project_sink.sink["warnings"]: + custom_writer_identity: null description: warnings (Terraform-managed). destination: storage.googleapis.com/test-gcs_sink disabled: false @@ -74,23 +145,45 @@ values: condition: - title: debug bucket writer role: roles/logging.bucketWriter + module.project-host.google_project_iam_member.project-sinks-binding["alert"]: + condition: [] + project: test-destination-project + role: roles/logging.logWriter + module.project-host.google_project_service.project_services["logging.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-project + service: logging.googleapis.com module.project-host.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: condition: [] + project: project-id role: roles/pubsub.publisher + topic: pubsub_sink module.project-host.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]: bucket: test-gcs_sink condition: [] role: roles/storage.objectCreator + module.pubsub.google_pubsub_topic.default: + kms_key_name: null + labels: null + message_retention_duration: null + name: pubsub_sink + project: project-id counts: google_bigquery_dataset: 1 google_bigquery_dataset_iam_member: 1 google_logging_project_bucket_config: 1 google_logging_project_exclusion: 1 - google_logging_project_sink: 4 - google_project: 1 - google_project_iam_member: 1 + google_logging_project_sink: 5 + google_project: 2 + google_project_iam_member: 2 + google_project_service: 2 google_pubsub_topic: 1 google_pubsub_topic_iam_member: 1 google_storage_bucket: 1 google_storage_bucket_iam_member: 1 + modules: 6 + resources: 19 + + From 2b7df349adfb644be8150bafd18db158212719ed Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:14:48 +0100 Subject: [PATCH 2/7] Add project log sink destination to folder module --- modules/folder/README.md | 18 +++- modules/folder/logging.tf | 19 ++++- modules/folder/variables.tf | 4 +- modules/project/logging.tf | 4 +- tests/modules/folder/examples/logging.yaml | 97 +++++++++++++++++++++- 5 files changed, 132 insertions(+), 10 deletions(-) diff --git a/modules/folder/README.md b/modules/folder/README.md index e52eb1e130..a102f2027b 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -231,6 +231,17 @@ module "bucket" { id = "${var.prefix}-bucket" } +module "destination-project" { + source = "./fabric/modules/project" + name = "destination-project" + billing_account = var.billing_account_id + parent = var.folder_id + prefix = var.prefix + services = [ + "logging.googleapis.com" + ] +} + module "folder-sink" { source = "./fabric/modules/folder" name = "Folder name" @@ -259,12 +270,17 @@ module "folder-sink" { } type = "logging" } + alert = { + destination = module.destination-project.id + filter = "severity=ALERT" + type = "project" + } } logging_exclusions = { no-gce-instances = "resource.type=gce_instance" } } -# tftest modules=5 resources=14 inventory=logging.yaml e2e +# tftest modules=6 resources=18 inventory=logging.yaml e2e ``` ## Data Access Logs diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf index 9df1c5c3fb..5a46b59cf1 100644 --- a/modules/folder/logging.tf +++ b/modules/folder/logging.tf @@ -17,8 +17,16 @@ # tfdoc:file:description Log sinks and supporting resources. locals { + logging_sinks = { + for k, v in var.logging_sinks : + # rewrite destination and type and type="project" + k => merge(v, v.type != "project" ? {} : { + destination = "projects/${v.destination}" + type = "logging" + }) + } sink_bindings = { - for type in ["bigquery", "pubsub", "logging", "storage"] : + for type in ["bigquery", "logging", "project", "pubsub", "storage"] : type => { for name, sink in var.logging_sinks : name => sink @@ -42,7 +50,7 @@ resource "google_folder_iam_audit_config" "default" { } resource "google_logging_folder_sink" "sink" { - for_each = var.logging_sinks + for_each = local.logging_sinks name = each.key description = coalesce(each.value.description, "${each.key} (Terraform-managed).") folder = local.folder.name @@ -108,6 +116,13 @@ resource "google_project_iam_member" "bucket-sinks-binding" { } } +resource "google_project_iam_member" "project-sinks-binding" { + for_each = local.sink_bindings["project"] + project = each.value.destination + role = "roles/logging.logWriter" + member = google_logging_folder_sink.sink[each.key].writer_identity +} + resource "google_logging_folder_exclusion" "logging-exclusion" { for_each = var.logging_exclusions name = each.key diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index 414593e941..11094c2e96 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -91,9 +91,9 @@ variable "logging_sinks" { validation { condition = alltrue([ for k, v in var.logging_sinks : - contains(["bigquery", "logging", "pubsub", "storage"], v.type) + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) ]) - error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'." + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." } validation { condition = alltrue([ diff --git a/modules/project/logging.tf b/modules/project/logging.tf index 4262fe6bac..dbbbacdb66 100644 --- a/modules/project/logging.tf +++ b/modules/project/logging.tf @@ -20,10 +20,10 @@ locals { logging_sinks = { for k, v in var.logging_sinks : # rewrite destination and type and type="project" - k => merge(v, v.type == "project" ? { + k => merge(v, v.type != "project" ? {} : { destination = "projects/${v.destination}" type = "logging" - } : {}) + }) } sink_bindings = { for type in ["bigquery", "logging", "project", "pubsub", "storage"] : diff --git a/tests/modules/folder/examples/logging.yaml b/tests/modules/folder/examples/logging.yaml index adaa03fba8..1218189c5f 100644 --- a/tests/modules/folder/examples/logging.yaml +++ b/tests/modules/folder/examples/logging.yaml @@ -13,16 +13,62 @@ # limitations under the License. values: + module.bucket.google_logging_project_bucket_config.bucket[0]: + bucket_id: test-bucket + cmek_settings: [] + enable_analytics: false + index_configs: [] + location: global + locked: null + project: project-id + retention_days: 30 + module.dataset.google_bigquery_dataset.default: + dataset_id: bq_sink + default_encryption_configuration: [] + default_partition_expiration_ms: null + default_table_expiration_ms: null + delete_contents_on_destroy: false + description: Terraform managed. + friendly_name: null + labels: null + location: EU + max_time_travel_hours: '168' + project: project-id + module.destination-project.google_project.project[0]: + auto_create_network: false + billing_account: 123456-123456-123456 + folder_id: '1122334455' + labels: null + name: test-destination-project + org_id: null + project_id: test-destination-project + skip_delete: false + module.destination-project.google_project_service.project_services["logging.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-destination-project + service: logging.googleapis.com module.folder-sink.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: + condition: [] role: roles/bigquery.dataEditor module.folder-sink.google_folder.folder[0]: display_name: Folder name parent: folders/1122334455 module.folder-sink.google_logging_folder_exclusion.logging-exclusion["no-gce-instances"]: description: no-gce-instances (Terraform-managed). + disabled: null filter: resource.type=gce_instance name: no-gce-instances + module.folder-sink.google_logging_folder_sink.sink["alert"]: + description: alert (Terraform-managed). + destination: logging.googleapis.com/projects/test-destination-project + disabled: false + exclusions: [] + filter: severity=ALERT + include_children: true + name: alert module.folder-sink.google_logging_folder_sink.sink["debug"]: + description: debug (Terraform-managed). disabled: false exclusions: - description: null @@ -34,13 +80,16 @@ values: name: debug module.folder-sink.google_logging_folder_sink.sink["info"]: bigquery_options: - - use_partitioned_tables: false + - use_partitioned_tables: false + description: info (Terraform-managed). disabled: false exclusions: [] filter: severity=INFO include_children: true name: info module.folder-sink.google_logging_folder_sink.sink["notice"]: + description: notice (Terraform-managed). + destination: pubsub.googleapis.com/projects/project-id/topics/pubsub_sink disabled: false exclusions: [] filter: severity=NOTICE @@ -58,20 +107,62 @@ values: condition: - title: debug bucket writer role: roles/logging.bucketWriter + module.folder-sink.google_project_iam_member.project-sinks-binding["alert"]: + condition: [] + project: test-destination-project + role: roles/logging.logWriter module.folder-sink.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: condition: [] + project: project-id role: roles/pubsub.publisher + topic: pubsub_sink module.folder-sink.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]: bucket: test-gcs_sink condition: [] role: roles/storage.objectCreator + module.gcs.google_storage_bucket.bucket: + autoclass: + - enabled: false + cors: [] + custom_placement_config: [] + default_event_based_hold: null + enable_object_retention: null + encryption: [] + force_destroy: true + labels: null + lifecycle_rule: [] + location: EU + logging: [] + name: test-gcs_sink + project: project-id + requester_pays: null + retention_policy: [] + storage_class: MULTI_REGIONAL + uniform_bucket_level_access: true + versioning: + - enabled: false + module.pubsub.google_pubsub_topic.default: + kms_key_name: null + labels: null + message_retention_duration: null + name: pubsub_sink + project: project-id counts: + google_bigquery_dataset: 1 google_bigquery_dataset_iam_member: 1 google_folder: 1 google_logging_folder_exclusion: 1 - google_logging_folder_sink: 4 + google_logging_folder_sink: 5 google_logging_project_bucket_config: 1 - google_project_iam_member: 1 + google_project: 1 + google_project_iam_member: 2 + google_project_service: 1 + google_pubsub_topic: 1 google_pubsub_topic_iam_member: 1 + google_storage_bucket: 1 google_storage_bucket_iam_member: 1 + modules: 6 + resources: 18 + + From fef3a635807ff6d104ff220a99ae2756fb18acbc Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:21:44 +0100 Subject: [PATCH 3/7] Add project log sink destination to organization module --- modules/organization/README.md | 18 ++- modules/organization/logging.tf | 19 +++- modules/organization/variables.tf | 4 +- .../organization/examples/logging.yaml | 103 +++++++++++++++++- 4 files changed, 136 insertions(+), 8 deletions(-) diff --git a/modules/organization/README.md b/modules/organization/README.md index f21bee99b6..cdec6b0cda 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -293,6 +293,17 @@ module "bucket" { id = "${var.prefix}-bucket" } +module "destination-project" { + source = "./fabric/modules/project" + name = "destination-project" + billing_account = var.billing_account_id + parent = var.folder_id + prefix = var.prefix + services = [ + "logging.googleapis.com" + ] +} + module "org" { source = "./fabric/modules/organization" organization_id = var.organization_id @@ -322,12 +333,17 @@ module "org" { } type = "logging" } + alert = { + destination = module.destination-project.id + filter = "severity=ALERT" + type = "project" + } } logging_exclusions = { no-gce-instances = "resource.type=gce_instance" } } -# tftest modules=5 resources=13 inventory=logging.yaml e2e serial +# tftest modules=6 resources=17 inventory=logging.yaml e2e serial ``` ## Data Access Logs diff --git a/modules/organization/logging.tf b/modules/organization/logging.tf index f5aeb4c43e..7f78c54683 100644 --- a/modules/organization/logging.tf +++ b/modules/organization/logging.tf @@ -17,8 +17,16 @@ # tfdoc:file:description Log sinks and data access logs. locals { + logging_sinks = { + for k, v in var.logging_sinks : + # rewrite destination and type when type="project" + k => merge(v, v.type != "project" ? {} : { + destination = "projects/${v.destination}" + type = "logging" + }) + } sink_bindings = { - for type in ["bigquery", "logging", "pubsub", "storage"] : + for type in ["bigquery", "logging", "project", "pubsub", "storage"] : type => { for name, sink in var.logging_sinks : name => sink if sink.iam && sink.type == type @@ -41,7 +49,7 @@ resource "google_organization_iam_audit_config" "default" { } resource "google_logging_organization_sink" "sink" { - for_each = var.logging_sinks + for_each = local.logging_sinks name = each.key description = coalesce(each.value.description, "${each.key} (Terraform-managed).") org_id = local.organization_id_numeric @@ -108,6 +116,13 @@ resource "google_project_iam_member" "bucket-sinks-binding" { } } +resource "google_project_iam_member" "project-sinks-binding" { + for_each = local.sink_bindings["project"] + project = each.value.destination + role = "roles/logging.logWriter" + member = google_logging_organization_sink.sink[each.key].writer_identity +} + resource "google_logging_organization_exclusion" "logging-exclusion" { for_each = var.logging_exclusions name = each.key diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index 45aacbe494..76b4945ed4 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -88,9 +88,9 @@ variable "logging_sinks" { validation { condition = alltrue([ for k, v in var.logging_sinks : - contains(["bigquery", "logging", "pubsub", "storage"], v.type) + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) ]) - error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'." + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." } validation { condition = alltrue([ diff --git a/tests/modules/organization/examples/logging.yaml b/tests/modules/organization/examples/logging.yaml index d8e00ed89b..9ee2716ee5 100644 --- a/tests/modules/organization/examples/logging.yaml +++ b/tests/modules/organization/examples/logging.yaml @@ -13,15 +13,82 @@ # limitations under the License. values: + module.bucket.google_logging_project_bucket_config.bucket[0]: + bucket_id: test-bucket + cmek_settings: [] + enable_analytics: false + index_configs: [] + location: global + locked: null + project: project-id + retention_days: 30 + module.dataset.google_bigquery_dataset.default: + dataset_id: bq_sink + default_encryption_configuration: [] + default_partition_expiration_ms: null + default_table_expiration_ms: null + delete_contents_on_destroy: false + description: Terraform managed. + friendly_name: null + labels: null + location: EU + max_time_travel_hours: '168' + project: project-id + module.destination-project.google_project.project[0]: + auto_create_network: false + billing_account: 123456-123456-123456 + folder_id: '1122334455' + labels: null + name: test-destination-project + org_id: null + project_id: test-destination-project + skip_delete: false + module.destination-project.google_project_service.project_services["logging.googleapis.com"]: + disable_dependent_services: false + disable_on_destroy: false + project: test-destination-project + service: logging.googleapis.com + module.gcs.google_storage_bucket.bucket: + autoclass: + - enabled: false + cors: [] + custom_placement_config: [] + default_event_based_hold: null + enable_object_retention: null + encryption: [] + force_destroy: true + labels: null + lifecycle_rule: [] + location: EU + logging: [] + name: test-gcs_sink + project: project-id + requester_pays: null + retention_policy: [] + storage_class: MULTI_REGIONAL + uniform_bucket_level_access: true + versioning: + - enabled: false module.org.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: condition: [] role: roles/bigquery.dataEditor module.org.google_logging_organization_exclusion.logging-exclusion["no-gce-instances"]: + description: no-gce-instances (Terraform-managed). disabled: null filter: resource.type=gce_instance name: no-gce-instances org_id: '1122334455' + module.org.google_logging_organization_sink.sink["alert"]: + description: alert (Terraform-managed). + destination: logging.googleapis.com/projects/test-destination-project + disabled: false + exclusions: [] + filter: severity=ALERT + include_children: true + name: alert + org_id: '1122334455' module.org.google_logging_organization_sink.sink["debug"]: + description: debug (Terraform-managed). disabled: false exclusions: - description: null @@ -34,7 +101,8 @@ values: org_id: '1122334455' module.org.google_logging_organization_sink.sink["info"]: bigquery_options: - - use_partitioned_tables: true + - use_partitioned_tables: true + description: info (Terraform-managed). disabled: false exclusions: [] filter: severity=INFO @@ -42,6 +110,8 @@ values: name: info org_id: '1122334455' module.org.google_logging_organization_sink.sink["notice"]: + description: notice (Terraform-managed). + destination: pubsub.googleapis.com/projects/project-id/topics/pubsub_sink disabled: false exclusions: [] filter: severity=NOTICE @@ -49,6 +119,7 @@ values: name: notice org_id: '1122334455' module.org.google_logging_organization_sink.sink["warnings"]: + description: warnings (Terraform-managed). destination: storage.googleapis.com/test-gcs_sink disabled: false exclusions: [] @@ -56,6 +127,23 @@ values: include_children: true name: warnings org_id: '1122334455' + module.org.google_project_iam_member.bucket-sinks-binding["debug"]: + condition: + - title: debug bucket writer + role: roles/logging.bucketWriter + module.org.google_project_iam_member.project-sinks-binding["alert"]: + condition: [] + project: test-destination-project + role: roles/logging.logWriter + module.org.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: + condition: [] + project: project-id + role: roles/pubsub.publisher + topic: pubsub_sink + module.org.google_storage_bucket_iam_member.storage-sinks-binding["warnings"]: + bucket: test-gcs_sink + condition: [] + role: roles/storage.objectCreator module.pubsub.google_pubsub_topic.default: kms_key_name: null labels: null @@ -64,9 +152,18 @@ values: project: project-id counts: + google_bigquery_dataset: 1 google_bigquery_dataset_iam_member: 1 google_logging_organization_exclusion: 1 - google_logging_organization_sink: 4 - google_project_iam_member: 1 + google_logging_organization_sink: 5 + google_logging_project_bucket_config: 1 + google_project: 1 + google_project_iam_member: 2 + google_project_service: 1 + google_pubsub_topic: 1 google_pubsub_topic_iam_member: 1 + google_storage_bucket: 1 google_storage_bucket_iam_member: 1 + modules: 6 + resources: 17 + From 38800a91414f7843f39157fc1ec8a54550c4e0cd Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:21:59 +0100 Subject: [PATCH 4/7] Fix typos --- modules/folder/logging.tf | 2 +- modules/project/logging.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/folder/logging.tf b/modules/folder/logging.tf index 5a46b59cf1..f6942baa4b 100644 --- a/modules/folder/logging.tf +++ b/modules/folder/logging.tf @@ -19,7 +19,7 @@ locals { logging_sinks = { for k, v in var.logging_sinks : - # rewrite destination and type and type="project" + # rewrite destination and type when type="project" k => merge(v, v.type != "project" ? {} : { destination = "projects/${v.destination}" type = "logging" diff --git a/modules/project/logging.tf b/modules/project/logging.tf index dbbbacdb66..b4f808891a 100644 --- a/modules/project/logging.tf +++ b/modules/project/logging.tf @@ -19,7 +19,7 @@ locals { logging_sinks = { for k, v in var.logging_sinks : - # rewrite destination and type and type="project" + # rewrite destination and type when type="project" k => merge(v, v.type != "project" ? {} : { destination = "projects/${v.destination}" type = "logging" From 21af47602313ac219f3661f5c854f2385d3977a2 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:29:13 +0100 Subject: [PATCH 5/7] Add project log sink destination to billing-account module --- modules/billing-account/logging.tf | 19 +++++++++++++++++-- modules/billing-account/variables.tf | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/billing-account/logging.tf b/modules/billing-account/logging.tf index 66974bff0b..9dcf7e69b7 100644 --- a/modules/billing-account/logging.tf +++ b/modules/billing-account/logging.tf @@ -17,8 +17,16 @@ # tfdoc:file:description Log sinks and supporting resources. locals { + logging_sinks = { + for k, v in var.logging_sinks : + # rewrite destination and type when type="project" + k => merge(v, v.type != "project" ? {} : { + destination = "projects/${v.destination}" + type = "logging" + }) + } sink_bindings = { - for type in ["bigquery", "pubsub", "logging", "storage"] : + for type in ["bigquery", "logging", "project", "pubsub", "storage"] : type => { for name, sink in var.logging_sinks : name => sink @@ -28,7 +36,7 @@ locals { } resource "google_logging_billing_account_sink" "sink" { - for_each = var.logging_sinks + for_each = local.logging_sinks name = each.key description = coalesce(each.value.description, "${each.key} (Terraform-managed).") billing_account = var.id @@ -90,3 +98,10 @@ resource "google_project_iam_member" "bucket-sinks-binding" { expression = "resource.name.endsWith('${each.value.destination}')" } } + +resource "google_project_iam_member" "project-sinks-binding" { + for_each = local.sink_bindings["project"] + project = each.value.destination + role = "roles/logging.logWriter" + member = google_logging_billing_account_sink.sink[each.key].writer_identity +} diff --git a/modules/billing-account/variables.tf b/modules/billing-account/variables.tf index 7ae5bd16ad..3927b05bad 100644 --- a/modules/billing-account/variables.tf +++ b/modules/billing-account/variables.tf @@ -153,9 +153,9 @@ variable "logging_sinks" { validation { condition = alltrue([ for k, v in var.logging_sinks : - contains(["bigquery", "logging", "pubsub", "storage"], v.type) + contains(["bigquery", "logging", "project", "pubsub", "storage"], v.type) ]) - error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'." + error_message = "Type must be one of 'bigquery', 'logging', 'project', 'pubsub', 'storage'." } validation { condition = alltrue([ From 866ce374155fc96baeea1172502eca89ec91e292 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:29:22 +0100 Subject: [PATCH 6/7] Make filter field optional --- modules/folder/variables.tf | 2 +- modules/organization/variables.tf | 2 +- modules/project/variables.tf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index 11094c2e96..6da2685a71 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -81,7 +81,7 @@ variable "logging_sinks" { destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) - filter = string + filter = optional(string) iam = optional(bool, true) include_children = optional(bool, true) type = string diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index 76b4945ed4..a3b24c7e31 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -78,7 +78,7 @@ variable "logging_sinks" { destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) - filter = string + filter = optional(string) iam = optional(bool, true) include_children = optional(bool, true) type = string diff --git a/modules/project/variables.tf b/modules/project/variables.tf index a82186c867..5e38f3ae76 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -119,7 +119,7 @@ variable "logging_sinks" { destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) - filter = string + filter = optional(string) iam = optional(bool, true) type = string unique_writer = optional(bool, true) From b0b2ed2d781acf2642841e7fad5a36013d1eebad Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 20 Feb 2024 21:30:15 +0100 Subject: [PATCH 7/7] Update READMEs --- modules/folder/README.md | 2 +- modules/organization/README.md | 2 +- modules/project/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/folder/README.md b/modules/folder/README.md index a102f2027b..8a5942f081 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -369,7 +369,7 @@ module "folder" { | [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({…})) | | {} | +| [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 | diff --git a/modules/organization/README.md b/modules/organization/README.md index cdec6b0cda..6fb3a4db4d 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -516,7 +516,7 @@ 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_sinks](variables.tf#L73) | 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({…})) | | {} | diff --git a/modules/project/README.md b/modules/project/README.md index 6a24ed74dd..e2ebd872a8 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -1014,7 +1014,7 @@ module "bucket" { | [lien_reason](variables.tf#L86) | If non-empty, creates a project lien with this description. | string | | null | | [logging_data_access](variables.tf#L92) | 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#L107) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | -| [logging_sinks](variables.tf#L114) | Logging sinks to create for this project. | map(object({…})) | | {} | +| [logging_sinks](variables.tf#L114) | Logging sinks to create for this project. | map(object({…})) | | {} | | [metric_scopes](variables.tf#L145) | List of projects that will act as metric scopes for this project. | list(string) | | [] | | [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#L157) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} |