1-org/modules/centralized-logging/main.tf (227 lines of code) (raw):

/** * Copyright 2022 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. */ locals { value_first_resource = values(var.resources)[0] include_children = (var.resource_type == "organization" || var.resource_type == "folder") # Create an intermediate list with all resources X all destinations exports_list = flatten([ # Iterate in all resources for res_k, res_v in var.resources : [ # Iterate in all log destinations for dest_k, dest_v in local.destinations_options : { # Create an object that is the base for a map creation below "res" = res_v, "options" = dest_v, "type" = dest_k } if dest_v != null ] ]) # Create a map based on the intermediate list above # with keys "<resource>_<dest>" that is used by iam permissions on destinations log_exports = { for v in local.exports_list : "${v.res}_${v.type}" => v } destinations_options = { pub = var.pubsub_options sto = var.storage_options prj = var.project_options } logging_sink_name_map = { pub = try("sk-to-tp-logs-${var.logging_destination_project_id}", "sk-to-tp-logs") sto = try("sk-to-bkt-logs-${var.logging_destination_project_id}", "sk-to-bkt-logs") prj = try("sk-to-prj-logs-${var.logging_destination_project_id}", "sk-to-prj-logs") } logging_tgt_name = { pub = "${local.logging_tgt_prefix.pub}${random_string.suffix.result}" sto = "${local.logging_tgt_prefix.sto}${random_string.suffix.result}" prj = "" } destination_uri_map = { pub = try(module.destination_pubsub[0].destination_uri, "") sto = try(module.destination_storage[0].destination_uri, "") prj = try(module.destination_project[0].destination_uri, "") } destination_resource_name = merge( var.pubsub_options != null ? { pub = module.destination_pubsub[0].resource_name } : {}, var.storage_options != null ? { sto = module.destination_storage[0].resource_name } : {}, var.project_options != null ? { prj = module.destination_project[0].project } : {} ) logging_tgt_prefix = { pub = "tp-logs-" sto = try("bkt-logs-${var.logging_destination_project_id}-", "bkt-logs-") prj = "" } } resource "random_string" "suffix" { length = 4 upper = false special = false } module "log_export" { source = "terraform-google-modules/log-export/google" version = "~> 8.0" for_each = local.log_exports destination_uri = local.destination_uri_map[each.value.type] filter = each.value.options.logging_sink_filter log_sink_name = coalesce(each.value.options.logging_sink_name, local.logging_sink_name_map[each.value.type]) parent_resource_id = each.value.res parent_resource_type = var.resource_type unique_writer_identity = true include_children = local.include_children } module "log_export_billing" { source = "terraform-google-modules/log-export/google" version = "~> 8.0" for_each = var.enable_billing_account_sink ? local.destination_resource_name : {} destination_uri = local.destination_uri_map[each.key] filter = "" log_sink_name = "${coalesce(local.destinations_options[each.key].logging_sink_name, local.logging_sink_name_map[each.key])}-billing-${random_string.suffix.result}" parent_resource_id = var.billing_account parent_resource_type = "billing_account" unique_writer_identity = true } resource "time_sleep" "wait_sa_iam_membership" { create_duration = "30s" depends_on = [ module.log_export_billing ] } #--------------------------# # Send logs to Log project # #--------------------------# module "destination_project" { source = "terraform-google-modules/log-export/google//modules/project" version = "~> 8.0" count = var.project_options != null ? 1 : 0 project_id = var.logging_destination_project_id log_sink_writer_identity = module.log_export["${local.value_first_resource}_prj"].writer_identity } #---------------------------------------------# # Log Projects Service account IAM membership # #---------------------------------------------# resource "google_project_iam_member" "project_sink_member" { for_each = var.project_options != null ? var.resources : {} project = var.logging_destination_project_id role = "roles/logging.logWriter" # Set permission only on sinks for this destination using # module.log_export key "<resource>_<dest>" member = module.log_export["${each.value}_prj"].writer_identity } #----------------------------------------------# # Send logs to Log project - Internal Log sink # #----------------------------------------------# module "internal_project_log_export" { source = "terraform-google-modules/log-export/google" version = "~> 8.0" count = var.project_options != null ? 1 : 0 destination_uri = "logging.googleapis.com/projects/${var.logging_destination_project_id}/locations/${var.project_options.location}/buckets/${coalesce(var.project_options.log_bucket_id, "AggregatedLogs")}" filter = var.project_options.logging_sink_filter log_sink_name = "${coalesce(var.project_options.logging_sink_name, local.logging_sink_name_map["prj"])}-la" parent_resource_id = var.logging_destination_project_id parent_resource_type = "project" unique_writer_identity = true } module "destination_aggregated_logs" { source = "terraform-google-modules/log-export/google//modules/logbucket" version = "~> 8.0" count = var.project_options != null ? 1 : 0 project_id = var.logging_destination_project_id name = coalesce(var.project_options.log_bucket_id, "AggregatedLogs") log_sink_writer_identity = module.internal_project_log_export[0].writer_identity location = var.project_options.location enable_analytics = var.project_options.enable_analytics linked_dataset_id = var.project_options.linked_dataset_id linked_dataset_description = var.project_options.linked_dataset_description retention_days = var.project_options.retention_days grant_write_permission_on_bkt = false } #-------------------------------------------------# # Send logs to Log project - update _Default sink # #-------------------------------------------------# data "google_client_config" "default" { } resource "terracurl_request" "exclude_external_logs" { count = var.project_options != null ? 1 : 0 name = "exclude_external_logs" url = "https://logging.googleapis.com/v2/projects/${var.logging_destination_project_id}/sinks/_Default?updateMask=exclusions" method = "PUT" response_codes = [200] headers = { Authorization = "Bearer ${data.google_client_config.default.access_token}" Content-Type = "application/json", } request_body = <<EOF { "exclusions": [ { "name": "exclude_external_logs", "filter": "-logName : \"/${var.logging_destination_project_id}/\"" } ], } EOF lifecycle { ignore_changes = [ headers, ] } } #---------------------------------------------------------------# # Project Service account IAM membership for log_export_billing # #---------------------------------------------------------------# resource "google_project_iam_member" "project_sink_member_billing" { count = var.enable_billing_account_sink == true && var.project_options != null ? 1 : 0 project = var.logging_destination_project_id role = "roles/logging.logWriter" # Set permission only on sinks for this destination using # module.log_export_billing key "<resource>_<dest>" member = module.log_export_billing["prj"].writer_identity depends_on = [ time_sleep.wait_sa_iam_membership ] } #----------------------# # Send logs to Storage # #----------------------# module "destination_storage" { source = "terraform-google-modules/log-export/google//modules/storage" version = "~> 8.0" count = var.storage_options != null ? 1 : 0 project_id = var.logging_destination_project_id storage_bucket_name = coalesce(var.storage_options.storage_bucket_name, local.logging_tgt_name.sto) log_sink_writer_identity = module.log_export["${local.value_first_resource}_sto"].writer_identity uniform_bucket_level_access = true location = var.storage_options.location force_destroy = var.storage_options.force_destroy versioning = var.storage_options.versioning retention_policy = !var.storage_options.retention_policy_enabled ? null : { is_locked = var.storage_options.retention_policy_is_locked retention_period_days = var.storage_options.retention_policy_period_days } } #----------------------------------------# # Storage Service account IAM membership # #----------------------------------------# resource "google_storage_bucket_iam_member" "storage_sink_member" { for_each = var.storage_options != null ? var.resources : {} bucket = module.destination_storage[0].resource_name role = "roles/storage.objectCreator" member = module.log_export["${each.value}_sto"].writer_identity } #---------------------------------------------------------------# # Storage Service account IAM membership for log_export_billing # #---------------------------------------------------------------# resource "google_storage_bucket_iam_member" "storage_sink_member_billing" { count = var.enable_billing_account_sink == true && var.storage_options != null ? length(var.resources) : 0 bucket = module.destination_storage[0].resource_name role = "roles/storage.objectCreator" member = module.log_export_billing["sto"].writer_identity depends_on = [ google_project_iam_member.project_sink_member_billing ] } #----------------------# # Send logs to Pub\Sub # #----------------------# module "destination_pubsub" { source = "terraform-google-modules/log-export/google//modules/pubsub" version = "~> 8.0" count = var.pubsub_options != null ? 1 : 0 project_id = var.logging_destination_project_id topic_name = coalesce(var.pubsub_options.topic_name, local.logging_tgt_name.pub) log_sink_writer_identity = module.log_export["${local.value_first_resource}_pub"].writer_identity create_subscriber = var.pubsub_options.create_subscriber } #---------------------------------------# # Pubsub Service account IAM membership # #---------------------------------------# resource "google_pubsub_topic_iam_member" "pubsub_sink_member" { for_each = var.pubsub_options != null ? var.resources : {} project = var.logging_destination_project_id topic = module.destination_pubsub[0].resource_name role = "roles/pubsub.publisher" member = module.log_export["${each.value}_pub"].writer_identity } #--------------------------------------------------------------# # Pubsub Service account IAM membership for log_export_billing # #--------------------------------------------------------------# resource "google_pubsub_topic_iam_member" "pubsub_sink_member_billing" { count = var.enable_billing_account_sink && var.pubsub_options != null ? length(var.resources) : 0 project = var.logging_destination_project_id topic = module.destination_pubsub[0].resource_name role = "roles/pubsub.publisher" member = module.log_export_billing["pub"].writer_identity depends_on = [ google_storage_bucket_iam_member.storage_sink_member_billing ] }