Merge pull request #970 from GoogleCloudPlatform/jccb/logging-t13
Update logging sinks to tf1.3 in resman modules
This commit is contained in:
commit
f731ec3585
|
@ -194,10 +194,7 @@ module "organization" {
|
|||
for name, attrs in var.log_sinks : name => {
|
||||
bq_partitioned_table = attrs.type == "bigquery"
|
||||
destination = local.log_sink_destinations[name].id
|
||||
exclusions = {}
|
||||
filter = attrs.filter
|
||||
iam = true
|
||||
include_children = true
|
||||
type = attrs.type
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,40 +166,34 @@ module "bucket" {
|
|||
id = "bucket"
|
||||
}
|
||||
|
||||
|
||||
module "folder-sink" {
|
||||
source = "./fabric/modules/folder"
|
||||
parent = "folders/657104291943"
|
||||
name = "my-folder"
|
||||
logging_sinks = {
|
||||
warnings = {
|
||||
type = "storage"
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
type = "storage"
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = module.dataset.id
|
||||
filter = "severity=INFO"
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
destination = module.dataset.id
|
||||
filter = "severity=INFO"
|
||||
type = "bigquery"
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
type = "pubsub"
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
include_children = true
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
}
|
||||
type = "logging"
|
||||
}
|
||||
}
|
||||
logging_exclusions = {
|
||||
|
@ -312,12 +306,12 @@ module "folder" {
|
|||
| [iam_additive_members](variables.tf#L85) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [id](variables.tf#L92) | Folder ID in case you use folder_create=false. | <code>string</code> | | <code>null</code> |
|
||||
| [logging_exclusions](variables.tf#L98) | Logging exclusions for this folder in the form {NAME -> FILTER}. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [logging_sinks](variables.tf#L105) | Logging sinks to create for this folder. | <code title="map(object({ destination = string type = string filter = string include_children = bool exclusions = map(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [name](variables.tf#L126) | Folder name. | <code>string</code> | | <code>null</code> |
|
||||
| [org_policies](variables.tf#L132) | Organization policies applied to this folder keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L172) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [parent](variables.tf#L178) | Parent in folders/folder_id or organizations/org_id format. | <code>string</code> | | <code>null</code> |
|
||||
| [tag_bindings](variables.tf#L188) | Tag bindings for this folder, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [logging_sinks](variables.tf#L105) | Logging sinks to create for the organization. | <code title="map(object({ bq_partitioned_table = optional(bool) description = optional(string) destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = string include_children = optional(bool, true) type = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [name](variables.tf#L135) | Folder name. | <code>string</code> | | <code>null</code> |
|
||||
| [org_policies](variables.tf#L141) | Organization policies applied to this folder keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L181) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [parent](variables.tf#L187) | Parent in folders/folder_id or organizations/org_id format. | <code>string</code> | | <code>null</code> |
|
||||
| [tag_bindings](variables.tf#L197) | Tag bindings for this folder, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -28,13 +28,21 @@ locals {
|
|||
}
|
||||
|
||||
resource "google_logging_folder_sink" "sink" {
|
||||
for_each = var.logging_sinks
|
||||
name = each.key
|
||||
#description = "${each.key} (Terraform-managed)."
|
||||
for_each = var.logging_sinks
|
||||
name = each.key
|
||||
description = coalesce(each.value.description, "${each.key} (Terraform-managed).")
|
||||
folder = local.folder.name
|
||||
destination = "${each.value.type}.googleapis.com/${each.value.destination}"
|
||||
filter = each.value.filter
|
||||
include_children = each.value.include_children
|
||||
disabled = each.value.disabled
|
||||
|
||||
dynamic "bigquery_options" {
|
||||
for_each = each.value.bq_partitioned_table != null ? [""] : []
|
||||
content {
|
||||
use_partitioned_tables = each.value.bq_partitioned_table
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "exclusions" {
|
||||
for_each = each.value.exclusions
|
||||
|
@ -78,8 +86,12 @@ resource "google_project_iam_member" "bucket-sinks-binding" {
|
|||
project = split("/", each.value.destination)[1]
|
||||
role = "roles/logging.bucketWriter"
|
||||
member = google_logging_folder_sink.sink[each.key].writer_identity
|
||||
# TODO(jccb): use a condition to limit writer-identity only to this
|
||||
# bucket
|
||||
|
||||
condition {
|
||||
title = "${each.key} bucket writer"
|
||||
description = "Grants bucketWriter to ${google_logging_folder_sink.sink[each.key].writer_identity} used by log sink ${each.key} on ${local.folder.id}"
|
||||
expression = "resource.name.endsWith('${each.value.destination}')"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_logging_folder_exclusion" "logging-exclusion" {
|
||||
|
|
|
@ -103,24 +103,33 @@ variable "logging_exclusions" {
|
|||
}
|
||||
|
||||
variable "logging_sinks" {
|
||||
description = "Logging sinks to create for this folder."
|
||||
description = "Logging sinks to create for the organization."
|
||||
type = map(object({
|
||||
destination = string
|
||||
type = string
|
||||
filter = string
|
||||
include_children = bool
|
||||
# TODO exclusions also support description and disabled
|
||||
exclusions = map(string)
|
||||
bq_partitioned_table = optional(bool)
|
||||
description = optional(string)
|
||||
destination = string
|
||||
disabled = optional(bool, false)
|
||||
exclusions = optional(map(string), {})
|
||||
filter = string
|
||||
include_children = optional(bool, true)
|
||||
type = string
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in(var.logging_sinks == null ? {} : var.logging_sinks) :
|
||||
for k, v in var.logging_sinks :
|
||||
contains(["bigquery", "logging", "pubsub", "storage"], v.type)
|
||||
])
|
||||
error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'."
|
||||
}
|
||||
default = {}
|
||||
nullable = false
|
||||
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" {
|
||||
|
|
|
@ -311,38 +311,28 @@ module "org" {
|
|||
|
||||
logging_sinks = {
|
||||
warnings = {
|
||||
type = "storage"
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
include_children = true
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
type = "storage"
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
bq_partitioned_table = true
|
||||
destination = module.dataset.id
|
||||
filter = "severity=INFO"
|
||||
include_children = true
|
||||
bq_partitioned_table = true
|
||||
exclusions = {}
|
||||
type = "bigquery"
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
include_children = true
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
type = "pubsub"
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
include_children = false
|
||||
bq_partitioned_table = null
|
||||
exclusions = {
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
}
|
||||
type = "logging"
|
||||
}
|
||||
}
|
||||
logging_exclusions = {
|
||||
|
@ -425,7 +415,7 @@ module "org" {
|
|||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [organization_id](variables.tf#L217) | Organization id in organizations/nnnnnn format. | <code>string</code> | ✓ | |
|
||||
| [organization_id](variables.tf#L225) | Organization id in organizations/nnnnnn format. | <code>string</code> | ✓ | |
|
||||
| [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. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [firewall_policies](variables.tf#L31) | Hierarchical firewall policy rules created in the organization. | <code title="map(map(object({ action = string description = string direction = string logging = bool ports = map(list(string)) priority = number ranges = list(string) target_resources = list(string) target_service_accounts = list(string) })))">map(map(object({…})))</code> | | <code>{}</code> |
|
||||
|
@ -439,13 +429,13 @@ module "org" {
|
|||
| [iam_audit_config_authoritative](variables.tf#L105) | IAM Authoritative service audit logging configuration. Service as key, map of log permission (eg DATA_READ) and excluded members as value for each service. Audit config should also be authoritative when using authoritative bindings. Use with caution. | <code>map(map(list(string)))</code> | | <code>null</code> |
|
||||
| [iam_bindings_authoritative](variables.tf#L116) | IAM authoritative bindings, in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared. Bindings should also be authoritative when using authoritative audit config. Use with caution. | <code>map(list(string))</code> | | <code>null</code> |
|
||||
| [logging_exclusions](variables.tf#L122) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [logging_sinks](variables.tf#L129) | Logging sinks to create for this organization. | <code title="map(object({ destination = string type = string filter = string include_children = bool bq_partitioned_table = bool exclusions = map(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies](variables.tf#L151) | Organization policies applied to this organization keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L191) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [org_policy_custom_constraints](variables.tf#L197) | Organization policiy custom constraints keyed by constraint name. | <code title="map(object({ display_name = optional(string) description = optional(string) action_type = string condition = string method_types = list(string) resource_types = list(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policy_custom_constraints_data_path](variables.tf#L211) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [tag_bindings](variables.tf#L227) | Tag bindings for this organization, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [tags](variables.tf#L233) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map(object({ description = string iam = map(list(string)) values = map(object({ description = string iam = map(list(string)) })) }))">map(object({…}))</code> | | <code>null</code> |
|
||||
| [logging_sinks](variables.tf#L129) | Logging sinks to create for the organization. | <code title="map(object({ bq_partitioned_table = optional(bool) description = optional(string) destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = string include_children = optional(bool, true) type = string }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies](variables.tf#L159) | Organization policies applied to this organization keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L199) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [org_policy_custom_constraints](variables.tf#L205) | Organization policiy custom constraints keyed by constraint name. | <code title="map(object({ display_name = optional(string) description = optional(string) action_type = string condition = string method_types = list(string) resource_types = list(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policy_custom_constraints_data_path](variables.tf#L219) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [tag_bindings](variables.tf#L235) | Tag bindings for this organization, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [tags](variables.tf#L241) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map(object({ description = string iam = map(list(string)) values = map(object({ description = string iam = map(list(string)) })) }))">map(object({…}))</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -29,13 +29,15 @@ locals {
|
|||
resource "google_logging_organization_sink" "sink" {
|
||||
for_each = var.logging_sinks
|
||||
name = each.key
|
||||
description = coalesce(each.value.description, "${each.key} (Terraform-managed).")
|
||||
org_id = local.organization_id_numeric
|
||||
destination = "${each.value.type}.googleapis.com/${each.value.destination}"
|
||||
filter = each.value.filter
|
||||
include_children = each.value.include_children
|
||||
disabled = each.value.disabled
|
||||
|
||||
dynamic "bigquery_options" {
|
||||
for_each = each.value.bq_partitioned_table == true ? [""] : []
|
||||
for_each = each.value.bq_partitioned_table != null ? [""] : []
|
||||
content {
|
||||
use_partitioned_tables = each.value.bq_partitioned_table
|
||||
}
|
||||
|
@ -49,6 +51,7 @@ resource "google_logging_organization_sink" "sink" {
|
|||
filter = exclusion.value
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
google_organization_iam_binding.authoritative,
|
||||
google_organization_iam_member.additive,
|
||||
|
@ -84,7 +87,12 @@ resource "google_project_iam_member" "bucket-sinks-binding" {
|
|||
project = split("/", each.value.destination)[1]
|
||||
role = "roles/logging.bucketWriter"
|
||||
member = google_logging_organization_sink.sink[each.key].writer_identity
|
||||
# TODO(jccb): use a condition to limit writer-identity only to this bucket
|
||||
|
||||
condition {
|
||||
title = "${each.key} bucket writer"
|
||||
description = "Grants bucketWriter to ${google_logging_organization_sink.sink[each.key].writer_identity} used by log sink ${each.key} on ${var.organization_id}"
|
||||
expression = "resource.name.endsWith('${each.value.destination}')"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_logging_organization_exclusion" "logging-exclusion" {
|
||||
|
|
|
@ -127,25 +127,33 @@ variable "logging_exclusions" {
|
|||
}
|
||||
|
||||
variable "logging_sinks" {
|
||||
description = "Logging sinks to create for this organization."
|
||||
description = "Logging sinks to create for the organization."
|
||||
type = map(object({
|
||||
bq_partitioned_table = optional(bool)
|
||||
description = optional(string)
|
||||
destination = string
|
||||
type = string
|
||||
disabled = optional(bool, false)
|
||||
exclusions = optional(map(string), {})
|
||||
filter = string
|
||||
include_children = bool
|
||||
bq_partitioned_table = bool
|
||||
# TODO exclusions also support description and disabled
|
||||
exclusions = map(string)
|
||||
include_children = optional(bool, true)
|
||||
type = string
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in(var.logging_sinks == null ? {} : var.logging_sinks) :
|
||||
for k, v in var.logging_sinks :
|
||||
contains(["bigquery", "logging", "pubsub", "storage"], v.type)
|
||||
])
|
||||
error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'."
|
||||
}
|
||||
default = {}
|
||||
nullable = false
|
||||
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" {
|
||||
|
|
|
@ -276,7 +276,7 @@ compute.restrictLoadBalancerCreationForTypes:
|
|||
```
|
||||
|
||||
|
||||
## Logging Sinks
|
||||
## Logging Sinks (in same project)
|
||||
|
||||
```hcl
|
||||
module "gcs" {
|
||||
|
@ -312,47 +312,66 @@ module "project-host" {
|
|||
parent = "folders/1234567890"
|
||||
logging_sinks = {
|
||||
warnings = {
|
||||
type = "storage"
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
iam = false
|
||||
unique_writer = false
|
||||
exclusions = {}
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
type = "storage"
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = module.dataset.id
|
||||
filter = "severity=INFO"
|
||||
iam = false
|
||||
unique_writer = false
|
||||
exclusions = {}
|
||||
destination = module.dataset.id
|
||||
filter = "severity=INFO"
|
||||
type = "bigquery"
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
unique_writer = false
|
||||
exclusions = {}
|
||||
destination = module.pubsub.id
|
||||
filter = "severity=NOTICE"
|
||||
type = "pubsub"
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
unique_writer = false
|
||||
destination = module.bucket.id
|
||||
filter = "severity=DEBUG"
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
}
|
||||
type = "logging"
|
||||
}
|
||||
}
|
||||
logging_exclusions = {
|
||||
no-gce-instances = "resource.type=gce_instance"
|
||||
}
|
||||
}
|
||||
# tftest modules=5 resources=12
|
||||
# tftest modules=5 resources=14
|
||||
```
|
||||
|
||||
## Logging Sinks (in different project)
|
||||
|
||||
When writing to destinations in a different project, set `unique_writer` to `true`.
|
||||
|
||||
```hcl
|
||||
module "gcs" {
|
||||
source = "./fabric/modules/gcs"
|
||||
project_id = "project-1"
|
||||
name = "gcs_sink"
|
||||
force_destroy = true
|
||||
}
|
||||
|
||||
module "project-host" {
|
||||
source = "./fabric/modules/project"
|
||||
name = "project-2"
|
||||
billing_account = "123456-123456-123456"
|
||||
parent = "folders/1234567890"
|
||||
logging_sinks = {
|
||||
warnings = {
|
||||
destination = module.gcs.id
|
||||
filter = "severity=WARNING"
|
||||
unique_writer = true
|
||||
type = "storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=2 resources=4
|
||||
```
|
||||
|
||||
|
||||
## Cloud KMS encryption keys
|
||||
|
||||
The module offers a simple, centralized way to assign `roles/cloudkms.cryptoKeyEncrypterDecrypter` to service identities.
|
||||
|
@ -455,7 +474,7 @@ output "compute_robot" {
|
|||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [name](variables.tf#L131) | Project name and id suffix. | <code>string</code> | ✓ | |
|
||||
| [name](variables.tf#L140) | Project name and id suffix. | <code>string</code> | ✓ | |
|
||||
| [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | <code>bool</code> | | <code>false</code> |
|
||||
| [billing_account](variables.tf#L23) | Billing account id. | <code>string</code> | | <code>null</code> |
|
||||
| [contacts](variables.tf#L29) | 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. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
|
@ -469,25 +488,25 @@ output "compute_robot" {
|
|||
| [labels](variables.tf#L82) | Resource labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [lien_reason](variables.tf#L89) | If non-empty, creates a project lien with this description. | <code>string</code> | | <code>""</code> |
|
||||
| [logging_exclusions](variables.tf#L95) | Logging exclusions for this project in the form {NAME -> FILTER}. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [logging_sinks](variables.tf#L102) | Logging sinks to create for this project. | <code title="map(object({ destination = string type = string filter = string iam = bool unique_writer = bool exclusions = map(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [metric_scopes](variables.tf#L124) | List of projects that will act as metric scopes for this project. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [org_policies](variables.tf#L136) | Organization policies applied to this project keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L176) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [oslogin](variables.tf#L182) | Enable OS Login. | <code>bool</code> | | <code>false</code> |
|
||||
| [oslogin_admins](variables.tf#L188) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [oslogin_users](variables.tf#L196) | List of IAM-style identities that will be granted roles necessary for OS Login users. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [parent](variables.tf#L203) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | | <code>null</code> |
|
||||
| [prefix](variables.tf#L213) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> |
|
||||
| [project_create](variables.tf#L223) | Create project. When set to false, uses a data source to reference existing project. | <code>bool</code> | | <code>true</code> |
|
||||
| [service_config](variables.tf#L229) | Configure service API activation. | <code title="object({ disable_on_destroy = bool disable_dependent_services = bool })">object({…})</code> | | <code title="{ disable_on_destroy = false disable_dependent_services = false }">{…}</code> |
|
||||
| [service_encryption_key_ids](variables.tf#L241) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [service_perimeter_bridges](variables.tf#L248) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | <code>list(string)</code> | | <code>null</code> |
|
||||
| [service_perimeter_standard](variables.tf#L255) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | <code>string</code> | | <code>null</code> |
|
||||
| [services](variables.tf#L261) | Service APIs to enable. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [shared_vpc_host_config](variables.tf#L267) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | <code title="object({ enabled = bool service_projects = optional(list(string), []) })">object({…})</code> | | <code>null</code> |
|
||||
| [shared_vpc_service_config](variables.tf#L276) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object({ host_project = string service_identity_iam = optional(map(list(string))) })">object({…})</code> | | <code>null</code> |
|
||||
| [skip_delete](variables.tf#L286) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> |
|
||||
| [tag_bindings](variables.tf#L292) | Tag bindings for this project, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [logging_sinks](variables.tf#L102) | Logging sinks to create for this project. | <code title="map(object({ bq_partitioned_table = optional(bool) description = optional(string) destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = string iam = optional(bool, true) type = string unique_writer = optional(bool) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [metric_scopes](variables.tf#L133) | List of projects that will act as metric scopes for this project. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [org_policies](variables.tf#L145) | Organization policies applied to this project keyed by policy name. | <code title="map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool, true) # for boolean policies only. condition = object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }) })), []) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [org_policies_data_path](variables.tf#L185) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
|
||||
| [oslogin](variables.tf#L191) | Enable OS Login. | <code>bool</code> | | <code>false</code> |
|
||||
| [oslogin_admins](variables.tf#L197) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [oslogin_users](variables.tf#L205) | List of IAM-style identities that will be granted roles necessary for OS Login users. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [parent](variables.tf#L212) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | | <code>null</code> |
|
||||
| [prefix](variables.tf#L222) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> |
|
||||
| [project_create](variables.tf#L232) | Create project. When set to false, uses a data source to reference existing project. | <code>bool</code> | | <code>true</code> |
|
||||
| [service_config](variables.tf#L238) | Configure service API activation. | <code title="object({ disable_on_destroy = bool disable_dependent_services = bool })">object({…})</code> | | <code title="{ disable_on_destroy = false disable_dependent_services = false }">{…}</code> |
|
||||
| [service_encryption_key_ids](variables.tf#L250) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [service_perimeter_bridges](variables.tf#L257) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | <code>list(string)</code> | | <code>null</code> |
|
||||
| [service_perimeter_standard](variables.tf#L264) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | <code>string</code> | | <code>null</code> |
|
||||
| [services](variables.tf#L270) | Service APIs to enable. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [shared_vpc_host_config](variables.tf#L276) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | <code title="object({ enabled = bool service_projects = optional(list(string), []) })">object({…})</code> | | <code>null</code> |
|
||||
| [shared_vpc_service_config](variables.tf#L285) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object({ host_project = string service_identity_iam = optional(map(list(string))) })">object({…})</code> | | <code>null</code> |
|
||||
| [skip_delete](variables.tf#L295) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> |
|
||||
| [tag_bindings](variables.tf#L301) | Tag bindings for this project, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -27,13 +27,21 @@ locals {
|
|||
}
|
||||
|
||||
resource "google_logging_project_sink" "sink" {
|
||||
for_each = var.logging_sinks
|
||||
name = each.key
|
||||
#description = "${each.key} (Terraform-managed)."
|
||||
for_each = var.logging_sinks
|
||||
name = each.key
|
||||
description = coalesce(each.value.description, "${each.key} (Terraform-managed).")
|
||||
project = local.project.project_id
|
||||
destination = "${each.value.type}.googleapis.com/${each.value.destination}"
|
||||
filter = each.value.filter
|
||||
unique_writer_identity = each.value.unique_writer
|
||||
disabled = each.value.disabled
|
||||
|
||||
dynamic "bigquery_options" {
|
||||
for_each = each.value.bq_partitioned_table != null ? [""] : []
|
||||
content {
|
||||
use_partitioned_tables = each.value.bq_partitioned_table
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "exclusions" {
|
||||
for_each = each.value.exclusions
|
||||
|
@ -78,8 +86,12 @@ resource "google_project_iam_member" "bucket-sinks-binding" {
|
|||
project = split("/", each.value.destination)[1]
|
||||
role = "roles/logging.bucketWriter"
|
||||
member = google_logging_project_sink.sink[each.key].writer_identity
|
||||
# TODO(jccb): use a condition to limit writer-identity only to this
|
||||
# bucket
|
||||
|
||||
condition {
|
||||
title = "${each.key} bucket writer"
|
||||
description = "Grants bucketWriter to ${google_logging_project_sink.sink[each.key].writer_identity} used by log sink ${each.key} on ${local.project.project_id}"
|
||||
expression = "resource.name.endsWith('${each.value.destination}')"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_logging_project_exclusion" "logging-exclusion" {
|
||||
|
|
|
@ -102,23 +102,32 @@ variable "logging_exclusions" {
|
|||
variable "logging_sinks" {
|
||||
description = "Logging sinks to create for this project."
|
||||
type = map(object({
|
||||
destination = string
|
||||
type = string
|
||||
filter = string
|
||||
iam = bool
|
||||
unique_writer = bool
|
||||
# TODO exclusions also support description and disabled
|
||||
exclusions = map(string)
|
||||
bq_partitioned_table = optional(bool)
|
||||
description = optional(string)
|
||||
destination = string
|
||||
disabled = optional(bool, false)
|
||||
exclusions = optional(map(string), {})
|
||||
filter = string
|
||||
iam = optional(bool, true)
|
||||
type = string
|
||||
unique_writer = optional(bool)
|
||||
}))
|
||||
default = {}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in(var.logging_sinks == null ? {} : var.logging_sinks) :
|
||||
for k, v in var.logging_sinks :
|
||||
contains(["bigquery", "logging", "pubsub", "storage"], v.type)
|
||||
])
|
||||
error_message = "Type must be one of 'bigquery', 'logging', 'pubsub', 'storage'."
|
||||
}
|
||||
default = {}
|
||||
nullable = false
|
||||
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 "metric_scopes" {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
logging_sinks = {
|
||||
warning = {
|
||||
destination = "mybucket"
|
||||
type = "storage"
|
||||
filter = "severity=WARNING"
|
||||
}
|
||||
info = {
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
type = "bigquery"
|
||||
filter = "severity=INFO"
|
||||
disabled = true
|
||||
}
|
||||
notice = {
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
type = "pubsub"
|
||||
filter = "severity=NOTICE"
|
||||
include_children = false
|
||||
}
|
||||
debug = {
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
type = "logging"
|
||||
filter = "severity=DEBUG"
|
||||
include_children = false
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,47 +14,11 @@
|
|||
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def test_sinks(plan_runner):
|
||||
"Test folder-level sinks."
|
||||
logging_sinks = """ {
|
||||
warning = {
|
||||
type = "storage"
|
||||
destination = "mybucket"
|
||||
filter = "severity=WARNING"
|
||||
iam = true
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
filter = "severity=INFO"
|
||||
iam = true
|
||||
include_children = true
|
||||
exclusions = {}
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
include_children = false
|
||||
exclusions = {}
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
include_children = false
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
_, resources = plan_runner(logging_sinks=logging_sinks)
|
||||
tfvars = 'test.logging-sinks.tfvars'
|
||||
_, resources = plan_runner(tf_var_file=tfvars)
|
||||
assert len(resources) == 9
|
||||
|
||||
resource_types = Counter([r["type"] for r in resources])
|
||||
|
@ -74,65 +38,59 @@ def test_sinks(plan_runner):
|
|||
"notice",
|
||||
"warning",
|
||||
]
|
||||
values = [
|
||||
(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["include_children"],
|
||||
)
|
||||
for r in sinks
|
||||
]
|
||||
values = [(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["description"],
|
||||
r["values"]["include_children"],
|
||||
r["values"]["disabled"],
|
||||
) for r in sinks]
|
||||
assert sorted(values) == [
|
||||
(
|
||||
"debug",
|
||||
"severity=DEBUG",
|
||||
"logging.googleapis.com/projects/myproject/locations/global/buckets/mybucket",
|
||||
False,
|
||||
),
|
||||
(
|
||||
"info",
|
||||
"severity=INFO",
|
||||
"bigquery.googleapis.com/projects/myproject/datasets/mydataset",
|
||||
True,
|
||||
),
|
||||
(
|
||||
"notice",
|
||||
"severity=NOTICE",
|
||||
"pubsub.googleapis.com/projects/myproject/topics/mytopic",
|
||||
False,
|
||||
),
|
||||
("warning", "severity=WARNING", "storage.googleapis.com/mybucket", True),
|
||||
("debug", "severity=DEBUG",
|
||||
"logging.googleapis.com/projects/myproject/locations/global/buckets/mybucket",
|
||||
"debug (Terraform-managed).", False, False),
|
||||
("info", "severity=INFO",
|
||||
"bigquery.googleapis.com/projects/myproject/datasets/mydataset",
|
||||
"info (Terraform-managed).", True, True),
|
||||
("notice", "severity=NOTICE",
|
||||
"pubsub.googleapis.com/projects/myproject/topics/mytopic",
|
||||
"notice (Terraform-managed).", False, False),
|
||||
("warning", "severity=WARNING", "storage.googleapis.com/mybucket",
|
||||
"warning (Terraform-managed).", True, False),
|
||||
]
|
||||
|
||||
bindings = [r for r in resources if "member" in r["type"]]
|
||||
values = [(r["index"], r["type"], r["values"]["role"]) for r in bindings]
|
||||
values = [(r["index"], r["type"], r["values"]["role"],
|
||||
r["values"]["condition"]) for r in bindings]
|
||||
assert sorted(values) == [
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter"),
|
||||
("info", "google_bigquery_dataset_iam_member", "roles/bigquery.dataEditor"),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher"),
|
||||
("warning", "google_storage_bucket_iam_member", "roles/storage.objectCreator"),
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter", [{
|
||||
'expression':
|
||||
"resource.name.endsWith('projects/myproject/locations/global/buckets/mybucket')",
|
||||
'title':
|
||||
'debug bucket writer'
|
||||
}]),
|
||||
("info", "google_bigquery_dataset_iam_member",
|
||||
"roles/bigquery.dataEditor", []),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher",
|
||||
[]),
|
||||
("warning", "google_storage_bucket_iam_member",
|
||||
"roles/storage.objectCreator", []),
|
||||
]
|
||||
|
||||
exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks]
|
||||
assert sorted(exclusions) == [
|
||||
(
|
||||
"debug",
|
||||
[
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:compute",
|
||||
"name": "no-compute",
|
||||
},
|
||||
{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:container",
|
||||
"name": "no-container",
|
||||
},
|
||||
],
|
||||
),
|
||||
("debug", [{
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:compute",
|
||||
"name": "no-compute"
|
||||
}, {
|
||||
"description": None,
|
||||
"disabled": False,
|
||||
"filter": "logName:container",
|
||||
"name": "no-container"
|
||||
}]),
|
||||
("info", []),
|
||||
("notice", []),
|
||||
("warning", []),
|
||||
|
@ -141,12 +99,10 @@ def test_sinks(plan_runner):
|
|||
|
||||
def test_exclusions(plan_runner):
|
||||
"Test folder-level logging exclusions."
|
||||
logging_exclusions = (
|
||||
"{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}"
|
||||
)
|
||||
logging_exclusions = ("{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}")
|
||||
_, resources = plan_runner(logging_exclusions=logging_exclusions)
|
||||
assert len(resources) == 3
|
||||
exclusions = [
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
logging_sinks = {
|
||||
warning = {
|
||||
destination = "mybucket"
|
||||
type = "storage"
|
||||
filter = "severity=WARNING"
|
||||
}
|
||||
info = {
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
type = "bigquery"
|
||||
filter = "severity=INFO"
|
||||
disabled = true
|
||||
}
|
||||
notice = {
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
type = "pubsub"
|
||||
filter = "severity=NOTICE"
|
||||
include_children = false
|
||||
}
|
||||
debug = {
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
type = "logging"
|
||||
filter = "severity=DEBUG"
|
||||
include_children = false
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,49 +17,8 @@ from collections import Counter
|
|||
|
||||
def test_sinks(plan_runner):
|
||||
"Test folder-level sinks."
|
||||
logging_sinks = """ {
|
||||
warning = {
|
||||
type = "storage"
|
||||
destination = "mybucket"
|
||||
filter = "severity=WARNING"
|
||||
iam = true
|
||||
include_children = true
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
filter = "severity=INFO"
|
||||
iam = true
|
||||
include_children = true
|
||||
bq_partitioned_table = false
|
||||
exclusions = {}
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
include_children = false
|
||||
bq_partitioned_table = null
|
||||
exclusions = {}
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
include_children = false
|
||||
bq_partitioned_table = null
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
_, resources = plan_runner(logging_sinks=logging_sinks)
|
||||
tfvars = 'test.logging-sinks.tfvars'
|
||||
_, resources = plan_runner(tf_var_file=tfvars)
|
||||
assert len(resources) == 8
|
||||
|
||||
resource_types = Counter([r["type"] for r in resources])
|
||||
|
@ -71,23 +30,21 @@ def test_sinks(plan_runner):
|
|||
"google_storage_bucket_iam_member": 1,
|
||||
}
|
||||
|
||||
sinks = [r for r in resources if r["type"]
|
||||
== "google_logging_organization_sink"]
|
||||
sinks = [
|
||||
r for r in resources if r["type"] == "google_logging_organization_sink"
|
||||
]
|
||||
assert sorted([r["index"] for r in sinks]) == [
|
||||
"debug",
|
||||
"info",
|
||||
"notice",
|
||||
"warning",
|
||||
]
|
||||
values = [
|
||||
(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["include_children"],
|
||||
)
|
||||
for r in sinks
|
||||
]
|
||||
values = [(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["include_children"],
|
||||
) for r in sinks]
|
||||
assert sorted(values) == [
|
||||
(
|
||||
"debug",
|
||||
|
@ -114,9 +71,11 @@ def test_sinks(plan_runner):
|
|||
values = [(r["index"], r["type"], r["values"]["role"]) for r in bindings]
|
||||
assert sorted(values) == [
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter"),
|
||||
("info", "google_bigquery_dataset_iam_member", "roles/bigquery.dataEditor"),
|
||||
("info", "google_bigquery_dataset_iam_member",
|
||||
"roles/bigquery.dataEditor"),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher"),
|
||||
("warning", "google_storage_bucket_iam_member", "roles/storage.objectCreator"),
|
||||
("warning", "google_storage_bucket_iam_member",
|
||||
"roles/storage.objectCreator"),
|
||||
]
|
||||
|
||||
exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks]
|
||||
|
@ -146,16 +105,15 @@ def test_sinks(plan_runner):
|
|||
|
||||
def test_exclusions(plan_runner):
|
||||
"Test folder-level logging exclusions."
|
||||
logging_exclusions = (
|
||||
"{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}"
|
||||
)
|
||||
logging_exclusions = ("{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}")
|
||||
_, resources = plan_runner(logging_exclusions=logging_exclusions)
|
||||
assert len(resources) == 2
|
||||
exclusions = [
|
||||
r for r in resources if r["type"] == "google_logging_organization_exclusion"
|
||||
r for r in resources
|
||||
if r["type"] == "google_logging_organization_exclusion"
|
||||
]
|
||||
assert sorted([r["index"] for r in exclusions]) == [
|
||||
"exclusion1",
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
logging_sinks = {
|
||||
warning = {
|
||||
destination = "mybucket"
|
||||
type = "storage"
|
||||
filter = "severity=WARNING"
|
||||
}
|
||||
info = {
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
type = "bigquery"
|
||||
filter = "severity=INFO"
|
||||
disabled = true
|
||||
}
|
||||
notice = {
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
type = "pubsub"
|
||||
filter = "severity=NOTICE"
|
||||
unique_writer = true
|
||||
}
|
||||
debug = {
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
type = "logging"
|
||||
filter = "severity=DEBUG"
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
unique_writer = true
|
||||
}
|
||||
}
|
|
@ -110,14 +110,7 @@ variable "services" {
|
|||
}
|
||||
|
||||
variable "logging_sinks" {
|
||||
type = map(object({
|
||||
destination = string
|
||||
type = string
|
||||
filter = string
|
||||
iam = bool
|
||||
exclusions = map(string)
|
||||
unique_writer = bool
|
||||
}))
|
||||
type = any
|
||||
default = {}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,45 +17,8 @@ from collections import Counter
|
|||
|
||||
def test_sinks(plan_runner):
|
||||
"Test folder-level sinks."
|
||||
logging_sinks = """ {
|
||||
warning = {
|
||||
type = "storage"
|
||||
destination = "mybucket"
|
||||
filter = "severity=WARNING"
|
||||
iam = true
|
||||
exclusions = {}
|
||||
unique_writer = false
|
||||
}
|
||||
info = {
|
||||
type = "bigquery"
|
||||
destination = "projects/myproject/datasets/mydataset"
|
||||
filter = "severity=INFO"
|
||||
iam = true
|
||||
exclusions = {}
|
||||
unique_writer = false
|
||||
}
|
||||
notice = {
|
||||
type = "pubsub"
|
||||
destination = "projects/myproject/topics/mytopic"
|
||||
filter = "severity=NOTICE"
|
||||
iam = true
|
||||
exclusions = {}
|
||||
unique_writer = false
|
||||
}
|
||||
debug = {
|
||||
type = "logging"
|
||||
destination = "projects/myproject/locations/global/buckets/mybucket"
|
||||
filter = "severity=DEBUG"
|
||||
iam = true
|
||||
exclusions = {
|
||||
no-compute = "logName:compute"
|
||||
no-container = "logName:container"
|
||||
}
|
||||
unique_writer = true
|
||||
}
|
||||
}
|
||||
"""
|
||||
_, resources = plan_runner(logging_sinks=logging_sinks)
|
||||
tfvars = 'test.logging-sinks.tfvars'
|
||||
_, resources = plan_runner(tf_var_file=tfvars)
|
||||
assert len(resources) == 12
|
||||
|
||||
resource_types = Counter([r["type"] for r in resources])
|
||||
|
@ -77,15 +40,12 @@ def test_sinks(plan_runner):
|
|||
"notice",
|
||||
"warning",
|
||||
]
|
||||
values = [
|
||||
(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["unique_writer_identity"],
|
||||
)
|
||||
for r in sinks
|
||||
]
|
||||
values = [(
|
||||
r["index"],
|
||||
r["values"]["filter"],
|
||||
r["values"]["destination"],
|
||||
r["values"]["unique_writer_identity"],
|
||||
) for r in sinks]
|
||||
assert sorted(values) == [
|
||||
(
|
||||
"debug",
|
||||
|
@ -103,7 +63,7 @@ def test_sinks(plan_runner):
|
|||
"notice",
|
||||
"severity=NOTICE",
|
||||
"pubsub.googleapis.com/projects/myproject/topics/mytopic",
|
||||
False,
|
||||
True,
|
||||
),
|
||||
("warning", "severity=WARNING", "storage.googleapis.com/mybucket", False),
|
||||
]
|
||||
|
@ -112,9 +72,11 @@ def test_sinks(plan_runner):
|
|||
values = [(r["index"], r["type"], r["values"]["role"]) for r in bindings]
|
||||
assert sorted(values) == [
|
||||
("debug", "google_project_iam_member", "roles/logging.bucketWriter"),
|
||||
("info", "google_bigquery_dataset_iam_member", "roles/bigquery.dataEditor"),
|
||||
("info", "google_bigquery_dataset_iam_member",
|
||||
"roles/bigquery.dataEditor"),
|
||||
("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher"),
|
||||
("warning", "google_storage_bucket_iam_member", "roles/storage.objectCreator"),
|
||||
("warning", "google_storage_bucket_iam_member",
|
||||
"roles/storage.objectCreator"),
|
||||
]
|
||||
|
||||
exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks]
|
||||
|
@ -144,12 +106,10 @@ def test_sinks(plan_runner):
|
|||
|
||||
def test_exclusions(plan_runner):
|
||||
"Test folder-level logging exclusions."
|
||||
logging_exclusions = (
|
||||
"{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}"
|
||||
)
|
||||
logging_exclusions = ("{"
|
||||
'exclusion1 = "resource.type=gce_instance", '
|
||||
'exclusion2 = "severity=NOTICE", '
|
||||
"}")
|
||||
_, resources = plan_runner(logging_exclusions=logging_exclusions)
|
||||
assert len(resources) == 6
|
||||
exclusions = [
|
||||
|
|
Loading…
Reference in New Issue