Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow projects as destinations for log sinks #2102

Merged
merged 8 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions modules/billing-account/logging.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions modules/billing-account/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
20 changes: 18 additions & 2 deletions modules/folder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -353,7 +369,7 @@ module "folder" {
| [id](variables.tf#L48) | Folder ID in case you use folder_create=false. | <code>string</code> | | <code>null</code> |
| [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. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_exclusions](variables.tf#L69) | Logging exclusions for this folder in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L76) | Logging sinks to create for the folder. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; iam &#61; optional&#40;bool, true&#41;&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L76) | Logging sinks to create for the folder. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; optional&#40;string&#41;&#10; iam &#61; optional&#40;bool, true&#41;&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [name](variables.tf#L107) | Folder name. | <code>string</code> | | <code>null</code> |
| [org_policies](variables.tf#L113) | Organization policies applied to this folder keyed by policy name. | <code title="map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; optional&#40;bool&#41; &#35; for list policies only.&#10; reset &#61; optional&#40;bool&#41;&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; expression &#61; optional&#40;string&#41;&#10; location &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [parent](variables.tf#L140) | Parent in folders/folder_id or organizations/org_id format. | <code>string</code> | | <code>null</code> |
Expand Down
19 changes: 17 additions & 2 deletions modules/folder/logging.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions modules/folder/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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([
Expand Down
20 changes: 18 additions & 2 deletions modules/organization/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -500,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. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [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. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_exclusions](variables.tf#L66) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L73) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; iam &#61; optional&#40;bool, true&#41;&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L73) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool, false&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; optional&#40;string&#41;&#10; iam &#61; optional&#40;bool, true&#41;&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [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. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; network &#61; string &#35; project_id&#47;vpc_name&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L104) | Organization policies applied to this organization keyed by policy name. | <code title="map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; optional&#40;bool&#41; &#35; for list policies only.&#10; reset &#61; optional&#40;bool&#41;&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; expression &#61; optional&#40;string&#41;&#10; location &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policy_custom_constraints](variables.tf#L131) | Organization policy custom constraints keyed by constraint name. | <code title="map&#40;object&#40;&#123;&#10; display_name &#61; optional&#40;string&#41;&#10; description &#61; optional&#40;string&#41;&#10; action_type &#61; string&#10; condition &#61; string&#10; method_types &#61; list&#40;string&#41;&#10; resource_types &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
Expand Down
19 changes: 17 additions & 2 deletions modules/organization/logging.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions modules/organization/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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([
Expand Down
Loading
Loading