Merge pull request #1684 from GoogleCloudPlatform/jccb/more-iam
Update resource-level IAM interface for kms and pubsub modules
This commit is contained in:
commit
0c578c067d
|
@ -55,10 +55,12 @@ module "vpc" {
|
|||
}
|
||||
|
||||
module "pubsub" {
|
||||
source = "../../../modules/pubsub"
|
||||
project_id = module.project.project_id
|
||||
name = var.name
|
||||
subscriptions = { "${var.name}-default" = null }
|
||||
source = "../../../modules/pubsub"
|
||||
project_id = module.project.project_id
|
||||
name = var.name
|
||||
subscriptions = {
|
||||
"${var.name}-default" = {}
|
||||
}
|
||||
iam = {
|
||||
"roles/pubsub.publisher" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.cloudasset}"
|
||||
|
|
|
@ -39,7 +39,7 @@ module "pubsub" {
|
|||
project_id = module.project.project_id
|
||||
name = var.name
|
||||
subscriptions = {
|
||||
"${var.name}-default" = null
|
||||
"${var.name}-default" = {}
|
||||
}
|
||||
# the Cloud Scheduler robot service account already has pubsub.topics.publish
|
||||
# at the project level via roles/cloudscheduler.serviceAgent
|
||||
|
|
|
@ -63,7 +63,7 @@ module "pubsub" {
|
|||
project_id = module.project.project_id
|
||||
name = var.name
|
||||
subscriptions = {
|
||||
"${var.name}-default" = null
|
||||
"${var.name}-default" = {}
|
||||
}
|
||||
# the Cloud Scheduler robot service account already has pubsub.topics.publish
|
||||
# at the project level via roles/cloudscheduler.serviceAgent
|
||||
|
@ -74,7 +74,7 @@ module "pubsub_file" {
|
|||
project_id = module.project.project_id
|
||||
name = var.name_cffile
|
||||
subscriptions = {
|
||||
"${var.name_cffile}-default" = null
|
||||
"${var.name_cffile}-default" = {}
|
||||
}
|
||||
# the Cloud Scheduler robot service account already has pubsub.topics.publish
|
||||
# at the project level via roles/cloudscheduler.serviceAgent
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2022 Google LLC
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -106,7 +106,10 @@ module "kms" {
|
|||
name = "${var.prefix}-${var.region}",
|
||||
location = var.region
|
||||
}
|
||||
keys = { key-gce = null, key-gcs = null }
|
||||
keys = {
|
||||
key-gce = {}
|
||||
key-gcs = {}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2022 Google LLC
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
@ -21,26 +21,27 @@ module "kms" {
|
|||
location = var.region
|
||||
}
|
||||
keys = {
|
||||
key-df = null
|
||||
key-gcs = null
|
||||
key-bq = null
|
||||
}
|
||||
key_iam = {
|
||||
key-gcs = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.storage}"
|
||||
]
|
||||
},
|
||||
key-bq = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.bq}"
|
||||
]
|
||||
},
|
||||
key-df = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.dataflow}",
|
||||
"serviceAccount:${module.project.service_accounts.robots.compute}",
|
||||
]
|
||||
iam = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.dataflow}",
|
||||
"serviceAccount:${module.project.service_accounts.robots.compute}",
|
||||
]
|
||||
}
|
||||
}
|
||||
key-gcs = {
|
||||
iam = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.storage}"
|
||||
]
|
||||
}
|
||||
}
|
||||
key-bq = {
|
||||
iam = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.bq}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,18 +159,18 @@ terraform apply
|
|||
|---|---|:---:|:---:|:---:|
|
||||
| [access_policy_config](variables.tf#L17) | Provide 'access_policy_create' values if a folder scoped Access Policy creation is needed, uses existing 'policy_name' otherwise. Parent is in 'organizations/123456' format. Policy will be created scoped to the folder. | <code title="object({ policy_name = optional(string, null) access_policy_create = optional(object({ parent = string title = string }), null) })">object({…})</code> | ✓ | |
|
||||
| [folder_config](variables.tf#L49) | Provide 'folder_create' values if folder creation is needed, uses existing 'folder_id' otherwise. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object({ folder_id = optional(string, null) folder_create = optional(object({ display_name = string parent = string }), null) })">object({…})</code> | ✓ | |
|
||||
| [organization](variables.tf#L129) | Organization details. | <code title="object({ domain = string id = string })">object({…})</code> | ✓ | |
|
||||
| [prefix](variables.tf#L137) | Prefix used for resources that need unique names. | <code>string</code> | ✓ | |
|
||||
| [project_config](variables.tf#L142) | Provide 'billing_account_id' value if project creation is needed, uses existing 'project_ids' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object({ billing_account_id = optional(string, null) project_ids = optional(object({ sec-core = string audit-logs = string }), { sec-core = "sec-core" audit-logs = "audit-logs" } ) })">object({…})</code> | ✓ | |
|
||||
| [organization](variables.tf#L148) | Organization details. | <code title="object({ domain = string id = string })">object({…})</code> | ✓ | |
|
||||
| [prefix](variables.tf#L156) | Prefix used for resources that need unique names. | <code>string</code> | ✓ | |
|
||||
| [project_config](variables.tf#L161) | Provide 'billing_account_id' value if project creation is needed, uses existing 'project_ids' if null. Parent is in 'folders/nnn' or 'organizations/nnn' format. | <code title="object({ billing_account_id = optional(string, null) project_ids = optional(object({ sec-core = string audit-logs = string }), { sec-core = "sec-core" audit-logs = "audit-logs" } ) })">object({…})</code> | ✓ | |
|
||||
| [data_dir](variables.tf#L29) | Relative path for the folder storing configuration data. | <code>string</code> | | <code>"data"</code> |
|
||||
| [enable_features](variables.tf#L35) | Flag to enable features on the solution. | <code title="object({ encryption = optional(bool, false) log_sink = optional(bool, true) vpc_sc = optional(bool, true) })">object({…})</code> | | <code title="{ encryption = false log_sink = true vpc_sc = true }">{…}</code> |
|
||||
| [groups](variables.tf#L65) | User groups. | <code title="object({ workload-engineers = optional(string, "gcp-data-engineers") workload-security = optional(string, "gcp-data-security") })">object({…})</code> | | <code>{}</code> |
|
||||
| [kms_keys](variables.tf#L75) | KMS keys to create, keyed by name. | <code title="map(object({ iam = optional(map(list(string)), {}) iam_bindings_additive = optional(map(map(any)), {}) labels = optional(map(string), {}) locations = optional(list(string), ["global", "europe", "europe-west1"]) rotation_period = optional(string, "7776000s") }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [log_locations](variables.tf#L87) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object({ bq = optional(string, "europe") storage = optional(string, "europe") logging = optional(string, "global") pubsub = optional(string, "global") })">object({…})</code> | | <code title="{ bq = "europe" storage = "europe" logging = "global" pubsub = null }">{…}</code> |
|
||||
| [log_sinks](variables.tf#L104) | Org-level log sinks, in name => {type, filter} format. | <code title="map(object({ filter = string type = string }))">map(object({…}))</code> | | <code title="{ audit-logs = { filter = "logName:\"/logs/cloudaudit.googleapis.com%2Factivity\" OR logName:\"/logs/cloudaudit.googleapis.com%2Fsystem_event\"" type = "bigquery" } vpc-sc = { filter = "protoPayload.metadata.@type=\"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata\"" type = "bigquery" } }">{…}</code> |
|
||||
| [vpc_sc_access_levels](variables.tf#L162) | VPC SC access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [vpc_sc_egress_policies](variables.tf#L191) | VPC SC egress policy definitions. | <code title="map(object({ from = object({ identity_type = optional(string, "ANY_IDENTITY") identities = optional(list(string)) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) resource_type_external = optional(bool, false) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [vpc_sc_ingress_policies](variables.tf#L211) | VPC SC ingress policy definitions. | <code title="map(object({ from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [kms_keys](variables.tf#L75) | KMS keys to create, keyed by name. | <code title="map(object({ labels = optional(map(string)) locations = optional(list(string), ["global", "europe", "europe-west1"]) rotation_period = optional(string, "7776000s") purpose = optional(string, "ENCRYPT_DECRYPT") skip_initial_version_creation = optional(bool, false) version_template = optional(object({ algorithm = string protection_level = optional(string, "SOFTWARE") })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [log_locations](variables.tf#L111) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object({ bq = optional(string, "europe") storage = optional(string, "europe") logging = optional(string, "global") pubsub = optional(string, "global") })">object({…})</code> | | <code>{}</code> |
|
||||
| [log_sinks](variables.tf#L123) | Org-level log sinks, in name => {type, filter} format. | <code title="map(object({ filter = string type = string }))">map(object({…}))</code> | | <code title="{ audit-logs = { filter = "logName:\"/logs/cloudaudit.googleapis.com%2Factivity\" OR logName:\"/logs/cloudaudit.googleapis.com%2Fsystem_event\"" type = "bigquery" } vpc-sc = { filter = "protoPayload.metadata.@type=\"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata\"" type = "bigquery" } }">{…}</code> |
|
||||
| [vpc_sc_access_levels](variables.tf#L181) | VPC SC access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [vpc_sc_egress_policies](variables.tf#L210) | VPC SC egress policy definitions. | <code title="map(object({ from = object({ identity_type = optional(string, "ANY_IDENTITY") identities = optional(list(string)) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) resource_type_external = optional(bool, false) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [vpc_sc_ingress_policies](variables.tf#L230) | VPC SC ingress policy definitions. | <code title="map(object({ from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -17,12 +17,17 @@
|
|||
# tfdoc:file:description Security project, Cloud KMS and Secret Manager resources.
|
||||
|
||||
locals {
|
||||
# list of locations with keys
|
||||
kms_locations = distinct(flatten([
|
||||
for k, v in var.kms_keys : v.locations
|
||||
]))
|
||||
# map { location -> { key_name -> key_details } }
|
||||
kms_locations_keys = {
|
||||
for loc in local.kms_locations : loc => {
|
||||
for k, v in var.kms_keys : k => v if contains(v.locations, loc)
|
||||
for loc in local.kms_locations :
|
||||
loc => {
|
||||
for k, v in var.kms_keys :
|
||||
k => v
|
||||
if contains(v.locations, loc)
|
||||
}
|
||||
}
|
||||
kms_log_locations = distinct(flatten([
|
||||
|
@ -30,17 +35,14 @@ locals {
|
|||
]))
|
||||
kms_log_sink_keys = {
|
||||
"storage" = {
|
||||
labels = {}
|
||||
locations = [var.log_locations.storage]
|
||||
rotation_period = "7776000s"
|
||||
}
|
||||
"bq" = {
|
||||
labels = {}
|
||||
locations = [var.log_locations.bq]
|
||||
rotation_period = "7776000s"
|
||||
}
|
||||
"pubsub" = {
|
||||
labels = {}
|
||||
locations = [var.log_locations.pubsub]
|
||||
rotation_period = "7776000s"
|
||||
}
|
||||
|
@ -88,12 +90,6 @@ module "sec-kms" {
|
|||
location = each.key
|
||||
name = "sec-${each.key}"
|
||||
}
|
||||
key_iam = {
|
||||
for k, v in local.kms_locations_keys[each.key] : k => v.iam
|
||||
}
|
||||
key_iam_bindings_additive = {
|
||||
for k, v in local.kms_locations_keys[each.key] : k => v.iam_bindings_additive
|
||||
}
|
||||
keys = local.kms_locations_keys[each.key]
|
||||
}
|
||||
|
||||
|
|
|
@ -75,11 +75,35 @@ variable "groups" {
|
|||
variable "kms_keys" {
|
||||
description = "KMS keys to create, keyed by name."
|
||||
type = map(object({
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings_additive = optional(map(map(any)), {})
|
||||
labels = optional(map(string), {})
|
||||
locations = optional(list(string), ["global", "europe", "europe-west1"])
|
||||
rotation_period = optional(string, "7776000s")
|
||||
labels = optional(map(string))
|
||||
locations = optional(list(string), ["global", "europe", "europe-west1"])
|
||||
rotation_period = optional(string, "7776000s")
|
||||
purpose = optional(string, "ENCRYPT_DECRYPT")
|
||||
skip_initial_version_creation = optional(bool, false)
|
||||
version_template = optional(object({
|
||||
algorithm = string
|
||||
protection_level = optional(string, "SOFTWARE")
|
||||
}))
|
||||
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings = optional(map(object({
|
||||
members = list(string)
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
iam_bindings_additive = optional(map(object({
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
@ -92,12 +116,7 @@ variable "log_locations" {
|
|||
logging = optional(string, "global")
|
||||
pubsub = optional(string, "global")
|
||||
})
|
||||
default = {
|
||||
bq = "europe"
|
||||
storage = "europe"
|
||||
logging = "global"
|
||||
pubsub = null
|
||||
}
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -115,20 +115,16 @@ module "kms" {
|
|||
project_id = module.project.project_id
|
||||
keyring = { location = var.region, name = "test-keyring" }
|
||||
keyring_create = true
|
||||
keys = { test-key = null }
|
||||
key_purpose = {
|
||||
keys = {
|
||||
test-key = {
|
||||
purpose = "ASYMMETRIC_SIGN"
|
||||
version_template = {
|
||||
algorithm = "RSA_SIGN_PKCS1_4096_SHA512"
|
||||
protection_level = null
|
||||
algorithm = "RSA_SIGN_PKCS1_4096_SHA512"
|
||||
}
|
||||
iam = {
|
||||
"roles/cloudkms.publicKeyViewer" = [module.image_cb_sa.iam_email]
|
||||
"roles/cloudkms.signer" = [module.image_cb_sa.iam_email]
|
||||
}
|
||||
}
|
||||
}
|
||||
key_iam = {
|
||||
test-key = {
|
||||
"roles/cloudkms.publicKeyViewer" = [module.image_cb_sa.iam_email]
|
||||
"roles/cloudkms.signer" = [module.image_cb_sa.iam_email]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -284,13 +284,12 @@ Some references that might be useful in setting up this stage:
|
|||
|
||||
<!-- TFDOC OPTS files:1 show_extra:1 -->
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Files
|
||||
|
||||
| name | description | modules | resources |
|
||||
|---|---|---|---|
|
||||
| [core-dev.tf](./core-dev.tf) | None | <code>kms</code> · <code>project</code> | <code>google_project_iam_member</code> |
|
||||
| [core-prod.tf](./core-prod.tf) | None | <code>kms</code> · <code>project</code> | <code>google_project_iam_member</code> |
|
||||
| [core-dev.tf](./core-dev.tf) | None | <code>kms</code> · <code>project</code> | |
|
||||
| [core-prod.tf](./core-prod.tf) | None | <code>kms</code> · <code>project</code> | |
|
||||
| [main.tf](./main.tf) | Module-level locals and resources. | | |
|
||||
| [outputs.tf](./outputs.tf) | Module outputs. | | <code>google_storage_bucket_object</code> · <code>local_file</code> |
|
||||
| [variables.tf](./variables.tf) | Module variables. | | |
|
||||
|
@ -303,17 +302,16 @@ Some references that might be useful in setting up this stage:
|
|||
| [automation](variables.tf#L17) | Automation resources created by the bootstrap stage. | <code title="object({ outputs_bucket = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [billing_account](variables.tf#L25) | Billing account id. If billing account is not part of the same org set `is_org_level` to false. | <code title="object({ id = string is_org_level = optional(bool, true) })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [folder_ids](variables.tf#L38) | Folder name => id mappings, the 'security' folder name must exist. | <code title="object({ security = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L84) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L100) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [service_accounts](variables.tf#L111) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | <code title="object({ data-platform-dev = string data-platform-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [organization](variables.tf#L97) | Organization details. | <code title="object({ domain = string id = number customer_id = string })">object({…})</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [prefix](variables.tf#L113) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [service_accounts](variables.tf#L124) | Automation service accounts that can assign the encrypt/decrypt roles on keys. | <code title="object({ data-platform-dev = string data-platform-prod = string project-factory-dev = string project-factory-prod = string })">object({…})</code> | ✓ | | <code>1-resman</code> |
|
||||
| [groups](variables.tf#L46) | Group names to grant organization-level permissions. | <code>map(string)</code> | | <code title="{ gcp-billing-admins = "gcp-billing-admins", gcp-devops = "gcp-devops", gcp-network-admins = "gcp-network-admins" gcp-organization-admins = "gcp-organization-admins" gcp-security-admins = "gcp-security-admins" gcp-support = "gcp-support" }">{…}</code> | <code>0-bootstrap</code> |
|
||||
| [kms_defaults](variables.tf#L61) | Defaults used for KMS keys. | <code title="object({ locations = list(string) rotation_period = string })">object({…})</code> | | <code title="{ locations = ["europe", "europe-west1", "europe-west3", "global"] rotation_period = "7776000s" }">{…}</code> | |
|
||||
| [kms_keys](variables.tf#L73) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | <code title="map(object({ iam = map(list(string)) labels = map(string) locations = list(string) rotation_period = string }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [outputs_location](variables.tf#L94) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [vpc_sc_access_levels](variables.tf#L122) | VPC SC access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_egress_policies](variables.tf#L151) | VPC SC egress policy definitions. | <code title="map(object({ from = object({ identity_type = optional(string, "ANY_IDENTITY") identities = optional(list(string)) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) resource_type_external = optional(bool, false) }) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_ingress_policies](variables.tf#L171) | VPC SC ingress policy definitions. | <code title="map(object({ from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_perimeters](variables.tf#L192) | VPC SC regular perimeter definitions. | <code title="object({ dev = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) landing = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) prod = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [kms_keys](variables.tf#L61) | KMS keys to create, keyed by name. | <code title="map(object({ rotation_period = optional(string, "7776000s") labels = optional(map(string)) locations = optional(list(string), ["europe", "europe-west1", "europe-west3", "global"]) purpose = optional(string, "ENCRYPT_DECRYPT") skip_initial_version_creation = optional(bool, false) version_template = optional(object({ algorithm = string protection_level = optional(string, "SOFTWARE") })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [outputs_location](variables.tf#L107) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [vpc_sc_access_levels](variables.tf#L135) | VPC SC access level definitions. | <code title="map(object({ combining_function = optional(string) conditions = optional(list(object({ device_policy = optional(object({ allowed_device_management_levels = optional(list(string)) allowed_encryption_statuses = optional(list(string)) require_admin_approval = bool require_corp_owned = bool require_screen_lock = optional(bool) os_constraints = optional(list(object({ os_type = string minimum_version = optional(string) require_verified_chrome_os = optional(bool) }))) })) ip_subnetworks = optional(list(string), []) members = optional(list(string), []) negate = optional(bool) regions = optional(list(string), []) required_access_levels = optional(list(string), []) })), []) description = optional(string) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_egress_policies](variables.tf#L164) | VPC SC egress policy definitions. | <code title="map(object({ from = object({ identity_type = optional(string, "ANY_IDENTITY") identities = optional(list(string)) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) resource_type_external = optional(bool, false) }) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_ingress_policies](variables.tf#L184) | VPC SC ingress policy definitions. | <code title="map(object({ from = object({ access_levels = optional(list(string), []) identity_type = optional(string) identities = optional(list(string)) resources = optional(list(string), []) }) to = object({ operations = optional(list(object({ method_selectors = optional(list(string)) service_name = string })), []) resources = optional(list(string)) }) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [vpc_sc_perimeters](variables.tf#L205) | VPC SC regular perimeter definitions. | <code title="object({ dev = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) landing = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) prod = optional(object({ access_levels = optional(list(string), []) egress_policies = optional(list(string), []) ingress_policies = optional(list(string), []) resources = optional(list(string), []) }), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
@ -322,5 +320,4 @@ Some references that might be useful in setting up this stage:
|
|||
| [kms_keys](outputs.tf#L59) | KMS key ids. | | |
|
||||
| [stage_perimeter_projects](outputs.tf#L64) | Security project numbers. They can be added to perimeter resources. | | |
|
||||
| [tfvars](outputs.tf#L74) | Terraform variable files for the following stages. | ✓ | |
|
||||
|
||||
<!-- END TFDOC -->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,11 +16,11 @@
|
|||
|
||||
locals {
|
||||
dev_kms_restricted_admins = [
|
||||
for sa in compact([
|
||||
for sa in distinct(compact([
|
||||
var.service_accounts.data-platform-dev,
|
||||
var.service_accounts.project-factory-dev,
|
||||
var.service_accounts.project-factory-prod
|
||||
]) : "serviceAccount:${sa}"
|
||||
])) : "serviceAccount:${sa}"
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,12 @@ module "dev-sec-project" {
|
|||
iam = {
|
||||
"roles/cloudkms.viewer" = local.dev_kms_restricted_admins
|
||||
}
|
||||
iam_bindings_additive = {
|
||||
for member in local.dev_kms_restricted_admins :
|
||||
"kms_restricted_admin.${member}" => merge(local.kms_restricted_admin_template, {
|
||||
member = member
|
||||
})
|
||||
}
|
||||
labels = { environment = "dev", team = "security" }
|
||||
services = local.project_services
|
||||
}
|
||||
|
@ -45,30 +51,5 @@ module "dev-sec-kms" {
|
|||
location = each.key
|
||||
name = "dev-${each.key}"
|
||||
}
|
||||
# rename to `key_iam` to switch to authoritative bindings
|
||||
key_iam = {
|
||||
for k, v in local.kms_locations_keys[each.key] : k => v.iam
|
||||
}
|
||||
keys = local.kms_locations_keys[each.key]
|
||||
}
|
||||
|
||||
# TODO(ludo): add support for conditions to Fabric modules
|
||||
|
||||
resource "google_project_iam_member" "dev_key_admin_delegated" {
|
||||
for_each = toset(local.dev_kms_restricted_admins)
|
||||
project = module.dev-sec-project.project_id
|
||||
role = "roles/cloudkms.admin"
|
||||
member = each.key
|
||||
condition {
|
||||
title = "kms_sa_delegated_grants"
|
||||
description = "Automation service account delegated grants."
|
||||
expression = format(
|
||||
"api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) && resource.type == 'cloudkms.googleapis.com/CryptoKey'",
|
||||
join(",", formatlist("'%s'", [
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter",
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation"
|
||||
]))
|
||||
)
|
||||
}
|
||||
depends_on = [module.dev-sec-project]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,10 +16,10 @@
|
|||
|
||||
locals {
|
||||
prod_kms_restricted_admins = [
|
||||
for sa in compact([
|
||||
for sa in distinct(compact([
|
||||
var.service_accounts.data-platform-prod,
|
||||
var.service_accounts.project-factory-prod
|
||||
]) : "serviceAccount:${sa}"
|
||||
])) : "serviceAccount:${sa}"
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,12 @@ module "prod-sec-project" {
|
|||
iam = {
|
||||
"roles/cloudkms.viewer" = local.prod_kms_restricted_admins
|
||||
}
|
||||
iam_bindings_additive = {
|
||||
for member in local.prod_kms_restricted_admins :
|
||||
"kms_restricted_admin.${member}" => merge(local.kms_restricted_admin_template, {
|
||||
member = member
|
||||
})
|
||||
}
|
||||
labels = { environment = "prod", team = "security" }
|
||||
services = local.project_services
|
||||
}
|
||||
|
@ -44,30 +50,5 @@ module "prod-sec-kms" {
|
|||
location = each.key
|
||||
name = "prod-${each.key}"
|
||||
}
|
||||
# rename to `key_iam` to switch to authoritative bindings
|
||||
key_iam = {
|
||||
for k, v in local.kms_locations_keys[each.key] : k => v.iam
|
||||
}
|
||||
keys = local.kms_locations_keys[each.key]
|
||||
}
|
||||
|
||||
# TODO(ludo): add support for conditions to Fabric modules
|
||||
|
||||
resource "google_project_iam_member" "prod_key_admin_delegated" {
|
||||
for_each = toset(local.prod_kms_restricted_admins)
|
||||
project = module.prod-sec-project.project_id
|
||||
role = "roles/cloudkms.admin"
|
||||
member = each.key
|
||||
condition {
|
||||
title = "kms_sa_delegated_grants"
|
||||
description = "Automation service account delegated grants."
|
||||
expression = format(
|
||||
"api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) && resource.type == 'cloudkms.googleapis.com/CryptoKey'",
|
||||
join(",", formatlist("'%s'", [
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter",
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation"
|
||||
]))
|
||||
)
|
||||
}
|
||||
depends_on = [module.prod-sec-project]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,28 +15,36 @@
|
|||
*/
|
||||
|
||||
locals {
|
||||
kms_keys = {
|
||||
for k, v in var.kms_keys : k => {
|
||||
iam = coalesce(v.iam, {})
|
||||
labels = coalesce(v.labels, {})
|
||||
locations = (
|
||||
v.locations == null
|
||||
? var.kms_defaults.locations
|
||||
: v.locations
|
||||
)
|
||||
rotation_period = (
|
||||
v.rotation_period == null
|
||||
? var.kms_defaults.rotation_period
|
||||
: v.rotation_period
|
||||
# additive IAM binding for delegated KMS admins
|
||||
kms_restricted_admin_template = {
|
||||
role = "roles/cloudkms.admin"
|
||||
condition = {
|
||||
title = "kms_sa_delegated_grants"
|
||||
description = "Automation service account delegated grants."
|
||||
expression = format(
|
||||
<<-EOT
|
||||
api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s]) &&
|
||||
resource.type == 'cloudkms.googleapis.com/CryptoKey'
|
||||
EOT
|
||||
, join(",", formatlist("'%s'", [
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter",
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypterViaDelegation"
|
||||
]))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# list of locations with keys
|
||||
kms_locations = distinct(flatten([
|
||||
for k, v in local.kms_keys : v.locations
|
||||
for k, v in var.kms_keys : v.locations
|
||||
]))
|
||||
# map { location -> { key_name -> key_details } }
|
||||
kms_locations_keys = {
|
||||
for loc in local.kms_locations : loc => {
|
||||
for k, v in local.kms_keys : k => v if contains(v.locations, loc)
|
||||
for loc in local.kms_locations :
|
||||
loc => {
|
||||
for k, v in var.kms_keys :
|
||||
k => v
|
||||
if contains(v.locations, loc)
|
||||
}
|
||||
}
|
||||
project_services = [
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -58,27 +58,40 @@ variable "groups" {
|
|||
}
|
||||
}
|
||||
|
||||
variable "kms_defaults" {
|
||||
description = "Defaults used for KMS keys."
|
||||
type = object({
|
||||
locations = list(string)
|
||||
rotation_period = string
|
||||
})
|
||||
default = {
|
||||
locations = ["europe", "europe-west1", "europe-west3", "global"]
|
||||
rotation_period = "7776000s"
|
||||
}
|
||||
}
|
||||
|
||||
variable "kms_keys" {
|
||||
description = "KMS keys to create, keyed by name. Null attributes will be interpolated with defaults."
|
||||
description = "KMS keys to create, keyed by name."
|
||||
type = map(object({
|
||||
iam = map(list(string))
|
||||
labels = map(string)
|
||||
locations = list(string)
|
||||
rotation_period = string
|
||||
rotation_period = optional(string, "7776000s")
|
||||
labels = optional(map(string))
|
||||
locations = optional(list(string), ["europe", "europe-west1", "europe-west3", "global"])
|
||||
purpose = optional(string, "ENCRYPT_DECRYPT")
|
||||
skip_initial_version_creation = optional(bool, false)
|
||||
version_template = optional(object({
|
||||
algorithm = string
|
||||
protection_level = optional(string, "SOFTWARE")
|
||||
}))
|
||||
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings = optional(map(object({
|
||||
members = list(string)
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
iam_bindings_additive = optional(map(object({
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
}))
|
||||
default = {}
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "organization" {
|
||||
|
|
|
@ -116,13 +116,12 @@ module "kms" {
|
|||
location = var.region
|
||||
}
|
||||
keys = {
|
||||
key-sql = null
|
||||
}
|
||||
key_iam = {
|
||||
key-sql = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.sqladmin}"
|
||||
]
|
||||
iam = {
|
||||
"roles/cloudkms.cryptoKeyEncrypterDecrypter" = [
|
||||
"serviceAccount:${module.project.service_accounts.robots.sqladmin}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ module "kms" {
|
|||
}
|
||||
keyring = { location = "europe-west1", name = "test" }
|
||||
keyring_create = false
|
||||
keys = { key-a = null, key-b = null, key-c = null }
|
||||
keys = { key-a = {}, key-b = {}, key-c = {} }
|
||||
}
|
||||
# tftest skip (uses data sources)
|
||||
```
|
||||
|
@ -42,26 +42,34 @@ module "kms" {
|
|||
module "kms" {
|
||||
source = "./fabric/modules/kms"
|
||||
project_id = "my-project"
|
||||
key_iam = {
|
||||
key-a = {
|
||||
"roles/cloudkms.admin" = ["user:user3@example.com"]
|
||||
}
|
||||
keyring = {
|
||||
location = "europe-west1"
|
||||
name = "test"
|
||||
}
|
||||
key_iam_bindings_additive = {
|
||||
key-b-am1 = {
|
||||
key = "key-b"
|
||||
member = "user:am1@example.com"
|
||||
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
|
||||
}
|
||||
}
|
||||
keyring = { location = "europe-west1", name = "test" }
|
||||
keys = {
|
||||
key-a = null
|
||||
key-b = { rotation_period = "604800s", labels = null }
|
||||
key-c = { rotation_period = null, labels = { env = "test" } }
|
||||
key-a = {
|
||||
iam = {
|
||||
"roles/cloudkms.admin" = ["user:user3@example.com"]
|
||||
}
|
||||
}
|
||||
key-b = {
|
||||
rotation_period = "604800s"
|
||||
iam_bindings_additive = {
|
||||
key-b-iam1 = {
|
||||
key = "key-b"
|
||||
member = "user:am1@example.com"
|
||||
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
|
||||
}
|
||||
}
|
||||
}
|
||||
key-c = {
|
||||
labels = {
|
||||
env = "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=6
|
||||
# tftest modules=1 resources=6 inventory=basic.yaml
|
||||
```
|
||||
|
||||
### Crypto key purpose
|
||||
|
@ -70,38 +78,35 @@ module "kms" {
|
|||
module "kms" {
|
||||
source = "./fabric/modules/kms"
|
||||
project_id = "my-project"
|
||||
key_purpose = {
|
||||
key-c = {
|
||||
keyring = {
|
||||
location = "europe-west1"
|
||||
name = "test"
|
||||
}
|
||||
keys = {
|
||||
key-a = {
|
||||
purpose = "ASYMMETRIC_SIGN"
|
||||
version_template = {
|
||||
algorithm = "EC_SIGN_P384_SHA384"
|
||||
protection_level = null
|
||||
protection_level = "HSM"
|
||||
}
|
||||
}
|
||||
}
|
||||
keyring = { location = "europe-west1", name = "test" }
|
||||
keys = { key-a = null, key-b = null, key-c = null }
|
||||
}
|
||||
# tftest modules=1 resources=4
|
||||
# tftest modules=1 resources=2 inventory=purpose.yaml
|
||||
```
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [keyring](variables.tf#L119) | Keyring attributes. | <code title="object({ location = string name = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L142) | Project id where the keyring will be created. | <code>string</code> | ✓ | |
|
||||
| [keyring](variables.tf#L54) | Keyring attributes. | <code title="object({ location = string name = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L103) | Project id where the keyring will be created. | <code>string</code> | ✓ | |
|
||||
| [iam](variables.tf#L17) | Keyring IAM bindings in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [iam_bindings](variables.tf#L23) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [iam_bindings_additive](variables.tf#L38) | Keyring individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [key_iam](variables.tf#L53) | Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format. | <code>map(map(list(string)))</code> | | <code>{}</code> |
|
||||
| [key_iam_bindings](variables.tf#L59) | Key authoritative IAM bindings in {KEY => {BINDING_KEY => {role = ROLE, members = [], condition = {}}}}. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [key_iam_bindings_additive](variables.tf#L74) | Key individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ key = string member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [key_purpose](variables.tf#L90) | Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="map(object({ purpose = string version_template = object({ algorithm = string protection_level = string }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [key_purpose_defaults](variables.tf#L102) | Defaults used for key purpose when not defined at the key level. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="object({ purpose = string version_template = object({ algorithm = string protection_level = string }) })">object({…})</code> | | <code title="{ purpose = null version_template = null }">{…}</code> |
|
||||
| [keyring_create](variables.tf#L127) | Set to false to manage keys and IAM bindings in an existing keyring. | <code>bool</code> | | <code>true</code> |
|
||||
| [keys](variables.tf#L133) | Key names and base attributes. Set attributes to null if not needed. | <code title="map(object({ rotation_period = string labels = map(string) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [tag_bindings](variables.tf#L147) | Tag bindings for this keyring, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [iam_bindings](variables.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [iam_bindings_additive](variables.tf#L39) | Keyring individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [keyring_create](variables.tf#L62) | Set to false to manage keys and IAM bindings in an existing keyring. | <code>bool</code> | | <code>true</code> |
|
||||
| [keys](variables.tf#L68) | Key names and base attributes. Set attributes to null if not needed. | <code title="map(object({ rotation_period = optional(string) labels = optional(map(string)) purpose = optional(string, "ENCRYPT_DECRYPT") skip_initial_version_creation = optional(bool, false) version_template = optional(object({ algorithm = string protection_level = optional(string, "SOFTWARE") })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [tag_bindings](variables.tf#L108) | Tag bindings for this keyring, in key => tag value id format. | <code>map(string)</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
|
|
@ -16,25 +16,36 @@
|
|||
|
||||
locals {
|
||||
key_iam = flatten([
|
||||
for key, roles in var.key_iam : [
|
||||
for role, members in roles : {
|
||||
key = key
|
||||
for k, v in var.keys : [
|
||||
for role, members in v.iam : {
|
||||
key = k
|
||||
role = role
|
||||
members = members
|
||||
}
|
||||
]
|
||||
])
|
||||
key_iam_bindings = flatten([
|
||||
for key, bindings in var.key_iam_bindings : [
|
||||
for binding_key, binding_data in bindings : {
|
||||
key = key
|
||||
binding_key = "${key}.${binding_key}"
|
||||
role = binding_data.role
|
||||
members = binding_data.members
|
||||
condition = binding_data.condition
|
||||
key_iam_bindings = merge([
|
||||
for k, v in var.keys : {
|
||||
for binding_key, data in v.iam_bindings :
|
||||
binding_key => {
|
||||
key = k
|
||||
role = data.role
|
||||
members = data.members
|
||||
condition = data.condition
|
||||
}
|
||||
]
|
||||
])
|
||||
}
|
||||
]...)
|
||||
key_iam_bindings_additive = merge([
|
||||
for k, v in var.keys : {
|
||||
for binding_key, data in v.iam_bindings_additive :
|
||||
binding_key => {
|
||||
key = k
|
||||
role = data.role
|
||||
member = data.member
|
||||
condition = data.condition
|
||||
}
|
||||
}
|
||||
]...)
|
||||
}
|
||||
|
||||
resource "google_kms_key_ring_iam_binding" "authoritative" {
|
||||
|
@ -85,9 +96,7 @@ resource "google_kms_crypto_key_iam_binding" "authoritative" {
|
|||
}
|
||||
|
||||
resource "google_kms_crypto_key_iam_binding" "bindings" {
|
||||
for_each = {
|
||||
for binding in local.key_iam_bindings : binding.binding_key => binding
|
||||
}
|
||||
for_each = local.key_iam_bindings
|
||||
role = each.value.role
|
||||
crypto_key_id = google_kms_crypto_key.default[each.value.key].id
|
||||
members = each.value.members
|
||||
|
@ -102,7 +111,7 @@ resource "google_kms_crypto_key_iam_binding" "bindings" {
|
|||
}
|
||||
|
||||
resource "google_kms_crypto_key_iam_member" "members" {
|
||||
for_each = var.key_iam_bindings_additive
|
||||
for_each = local.key_iam_bindings_additive
|
||||
crypto_key_id = google_kms_crypto_key.default[each.value.key].id
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,11 +15,6 @@
|
|||
*/
|
||||
|
||||
locals {
|
||||
key_purpose = {
|
||||
for key, attrs in var.keys : key => try(
|
||||
var.key_purpose[key], var.key_purpose_defaults
|
||||
)
|
||||
}
|
||||
keyring = (
|
||||
var.keyring_create
|
||||
? google_kms_key_ring.default.0
|
||||
|
@ -42,17 +37,19 @@ resource "google_kms_key_ring" "default" {
|
|||
}
|
||||
|
||||
resource "google_kms_crypto_key" "default" {
|
||||
for_each = var.keys
|
||||
key_ring = local.keyring.id
|
||||
name = each.key
|
||||
rotation_period = try(each.value.rotation_period, null)
|
||||
labels = try(each.value.labels, null)
|
||||
purpose = try(local.key_purpose[each.key].purpose, null)
|
||||
for_each = var.keys
|
||||
key_ring = local.keyring.id
|
||||
name = each.key
|
||||
rotation_period = each.value.rotation_period
|
||||
labels = each.value.labels
|
||||
purpose = each.value.purpose
|
||||
skip_initial_version_creation = each.value.skip_initial_version_creation
|
||||
|
||||
dynamic "version_template" {
|
||||
for_each = local.key_purpose[each.key].version_template == null ? [] : [""]
|
||||
for_each = each.value.version_template == null ? [] : [""]
|
||||
content {
|
||||
algorithm = local.key_purpose[each.key].version_template.algorithm
|
||||
protection_level = local.key_purpose[each.key].version_template.protection_level
|
||||
algorithm = each.value.version_template.algorithm
|
||||
protection_level = each.value.version_template.protection_level
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
resource "google_tags_tag_binding" "binding" {
|
||||
for_each = coalesce(var.tag_bindings, {})
|
||||
for_each = var.tag_bindings
|
||||
parent = "//cloudresourcemanager.googleapis.com/${local.keyring.id}"
|
||||
tag_value = each.value
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,6 +18,7 @@ variable "iam" {
|
|||
description = "Keyring IAM bindings in {ROLE => [MEMBERS]} format."
|
||||
type = map(list(string))
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "iam_bindings" {
|
||||
|
@ -50,72 +51,6 @@ variable "iam_bindings_additive" {
|
|||
default = {}
|
||||
}
|
||||
|
||||
variable "key_iam" {
|
||||
description = "Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format."
|
||||
type = map(map(list(string)))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "key_iam_bindings" {
|
||||
description = "Key authoritative IAM bindings in {KEY => {BINDING_KEY => {role = ROLE, members = [], condition = {}}}}."
|
||||
type = map(object({
|
||||
members = list(string)
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "key_iam_bindings_additive" {
|
||||
description = "Key individual additive IAM bindings. Keys are arbitrary."
|
||||
type = map(object({
|
||||
key = string
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "key_purpose" {
|
||||
description = "Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required."
|
||||
type = map(object({
|
||||
purpose = string
|
||||
version_template = object({
|
||||
algorithm = string
|
||||
protection_level = string
|
||||
})
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "key_purpose_defaults" {
|
||||
description = "Defaults used for key purpose when not defined at the key level. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required."
|
||||
type = object({
|
||||
purpose = string
|
||||
version_template = object({
|
||||
algorithm = string
|
||||
protection_level = string
|
||||
})
|
||||
})
|
||||
default = {
|
||||
purpose = null
|
||||
version_template = null
|
||||
}
|
||||
}
|
||||
|
||||
# cf https://cloud.google.com/kms/docs/locations
|
||||
|
||||
variable "keyring" {
|
||||
description = "Keyring attributes."
|
||||
type = object({
|
||||
|
@ -133,10 +68,36 @@ variable "keyring_create" {
|
|||
variable "keys" {
|
||||
description = "Key names and base attributes. Set attributes to null if not needed."
|
||||
type = map(object({
|
||||
rotation_period = string
|
||||
labels = map(string)
|
||||
rotation_period = optional(string)
|
||||
labels = optional(map(string))
|
||||
purpose = optional(string, "ENCRYPT_DECRYPT")
|
||||
skip_initial_version_creation = optional(bool, false)
|
||||
version_template = optional(object({
|
||||
algorithm = string
|
||||
protection_level = optional(string, "SOFTWARE")
|
||||
}))
|
||||
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings = optional(map(object({
|
||||
members = list(string)
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
iam_bindings_additive = optional(map(object({
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
}))
|
||||
default = {}
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
|
@ -147,5 +108,6 @@ variable "project_id" {
|
|||
variable "tag_bindings" {
|
||||
description = "Tag bindings for this keyring, in key => tag value id format."
|
||||
type = map(string)
|
||||
default = null
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
|
|
@ -61,16 +61,10 @@ module "pubsub" {
|
|||
project_id = "my-project"
|
||||
name = "my-topic"
|
||||
subscriptions = {
|
||||
test-pull = null
|
||||
test-pull = {}
|
||||
test-pull-override = {
|
||||
labels = { test = "override" }
|
||||
options = {
|
||||
ack_deadline_seconds = null
|
||||
message_retention_duration = null
|
||||
retain_acked_messages = true
|
||||
expiration_policy_ttl = null
|
||||
filter = null
|
||||
}
|
||||
labels = { test = "override" }
|
||||
retain_acked_messages = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,13 +81,10 @@ module "pubsub" {
|
|||
project_id = "my-project"
|
||||
name = "my-topic"
|
||||
subscriptions = {
|
||||
test-push = null
|
||||
}
|
||||
push_configs = {
|
||||
test-push = {
|
||||
endpoint = "https://example.com/foo"
|
||||
attributes = null
|
||||
oidc_token = null
|
||||
push = {
|
||||
endpoint = "https://example.com/foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,14 +101,13 @@ module "pubsub" {
|
|||
project_id = "my-project"
|
||||
name = "my-topic"
|
||||
subscriptions = {
|
||||
test-bigquery = null
|
||||
}
|
||||
bigquery_subscription_configs = {
|
||||
test-bigquery = {
|
||||
table = "my_project_id:my_dataset.my_table"
|
||||
use_topic_schema = true
|
||||
write_metadata = false
|
||||
drop_unknown_fields = true
|
||||
bigquery = {
|
||||
table = "my_project_id:my_dataset.my_table"
|
||||
use_topic_schema = true
|
||||
write_metadata = false
|
||||
drop_unknown_fields = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,17 +124,16 @@ module "pubsub" {
|
|||
project_id = "my-project"
|
||||
name = "my-topic"
|
||||
subscriptions = {
|
||||
test-cloudstorage = null
|
||||
}
|
||||
cloud_storage_subscription_configs = {
|
||||
test-cloudstorage = {
|
||||
bucket = "my-bucket"
|
||||
filename_prefix = "test_prefix"
|
||||
filename_suffix = "test_suffix"
|
||||
max_duration = "100s"
|
||||
max_bytes = 1000
|
||||
avro_config = {
|
||||
write_metadata = true
|
||||
cloud_storage = {
|
||||
bucket = "my-bucket"
|
||||
filename_prefix = "test_prefix"
|
||||
filename_suffix = "test_suffix"
|
||||
max_duration = "100s"
|
||||
max_bytes = 1000
|
||||
avro_config = {
|
||||
write_metadata = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,12 +148,10 @@ module "pubsub" {
|
|||
project_id = "my-project"
|
||||
name = "my-topic"
|
||||
subscriptions = {
|
||||
test-1 = null
|
||||
test-1 = null
|
||||
}
|
||||
subscription_iam = {
|
||||
test-1 = {
|
||||
"roles/pubsub.subscriber" = ["user:user1@ludomagno.net"]
|
||||
iam = {
|
||||
"roles/pubsub.subscriber" = ["user:user1@example.com"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,30 +162,26 @@ module "pubsub" {
|
|||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [name](variables.tf#L94) | PubSub topic name. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L99) | Project used for resources. | <code>string</code> | ✓ | |
|
||||
| [bigquery_subscription_configs](variables.tf#L17) | Configuration parameters for BigQuery subscriptions. | <code title="map(object({ table = string use_topic_schema = bool write_metadata = bool drop_unknown_fields = bool }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [cloud_storage_subscription_configs](variables.tf#L28) | Configuration parameters for Cloud Storage subscriptions. | <code title="map(object({ bucket = string filename_prefix = string filename_suffix = string max_duration = string max_bytes = number avro_config = object({ write_metadata = bool }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [dead_letter_configs](variables.tf#L43) | Per-subscription dead letter policy configuration. | <code title="map(object({ topic = string max_delivery_attempts = number }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [defaults](variables.tf#L52) | Subscription defaults for options. | <code title="object({ ack_deadline_seconds = number message_retention_duration = string retain_acked_messages = bool expiration_policy_ttl = string filter = string })">object({…})</code> | | <code title="{ ack_deadline_seconds = null message_retention_duration = null retain_acked_messages = null expiration_policy_ttl = null filter = null }">{…}</code> |
|
||||
| [iam](variables.tf#L70) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [kms_key](variables.tf#L76) | KMS customer managed encryption key. | <code>string</code> | | <code>null</code> |
|
||||
| [labels](variables.tf#L82) | Labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [message_retention_duration](variables.tf#L88) | Minimum duration to retain a message after it is published to the topic. | <code>string</code> | | <code>null</code> |
|
||||
| [push_configs](variables.tf#L104) | Push subscription configurations. | <code title="map(object({ attributes = map(string) endpoint = string oidc_token = object({ audience = string service_account_email = string }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [regions](variables.tf#L117) | List of regions used to set persistence policy. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [schema](variables.tf#L123) | Topic schema. If set, all messages in this topic should follow this schema. | <code title="object({ definition = string msg_encoding = optional(string, "ENCODING_UNSPECIFIED") schema_type = string })">object({…})</code> | | <code>null</code> |
|
||||
| [subscription_iam](variables.tf#L133) | IAM bindings for subscriptions in {SUBSCRIPTION => {ROLE => [MEMBERS]}} format. | <code>map(map(list(string)))</code> | | <code>{}</code> |
|
||||
| [subscriptions](variables.tf#L139) | Topic subscriptions. Also define push configs for push subscriptions. If options is set to null subscription defaults will be used. Labels default to topic labels if set to null. | <code title="map(object({ labels = map(string) options = object({ ack_deadline_seconds = number message_retention_duration = string retain_acked_messages = bool expiration_policy_ttl = string filter = string }) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [name](variables.tf#L73) | PubSub topic name. | <code>string</code> | ✓ | |
|
||||
| [project_id](variables.tf#L78) | Project used for resources. | <code>string</code> | ✓ | |
|
||||
| [iam](variables.tf#L17) | IAM bindings for topic in {ROLE => [MEMBERS]} format. | <code>map(list(string))</code> | | <code>{}</code> |
|
||||
| [iam_bindings](variables.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | <code title="map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [iam_bindings_additive](variables.tf#L39) | Keyring individual additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
| [kms_key](variables.tf#L54) | KMS customer managed encryption key. | <code>string</code> | | <code>null</code> |
|
||||
| [labels](variables.tf#L60) | Labels. | <code>map(string)</code> | | <code>{}</code> |
|
||||
| [message_retention_duration](variables.tf#L67) | Minimum duration to retain a message after it is published to the topic. | <code>string</code> | | <code>null</code> |
|
||||
| [regions](variables.tf#L83) | List of regions used to set persistence policy. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [schema](variables.tf#L90) | Topic schema. If set, all messages in this topic should follow this schema. | <code title="object({ definition = string msg_encoding = optional(string, "ENCODING_UNSPECIFIED") schema_type = string })">object({…})</code> | | <code>null</code> |
|
||||
| [subscriptions](variables.tf#L100) | Topic subscriptions. Also define push configs for push subscriptions. If options is set to null subscription defaults will be used. Labels default to topic labels if set to null. | <code title="map(object({ labels = optional(map(string)) ack_deadline_seconds = optional(number) message_retention_duration = optional(string) retain_acked_messages = optional(bool, false) expiration_policy_ttl = optional(string) filter = optional(string) enable_message_ordering = optional(bool, false) enable_exactly_once_delivery = optional(bool, false) dead_letter_policy = optional(object({ topic = string max_delivery_attempts = optional(number) })) retry_policy = optional(object({ minimum_backoff = optional(number) maximum_backoff = optional(number) })) bigquery = optional(object({ table = string use_topic_schema = optional(bool, false) write_metadata = optional(bool, false) drop_unknown_fields = optional(bool, false) })) cloud_storage = optional(object({ bucket = string filename_prefix = optional(string) filename_suffix = optional(string) max_duration = optional(string) max_bytes = optional(number) avro_config = optional(object({ write_metadata = optional(bool, false) })) })) push = optional(object({ endpoint = string attributes = optional(map(string)) no_wrapper = optional(bool, false) oidc_token = optional(object({ audience = optional(string) service_account_email = string })) })) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) }))">map(object({…}))</code> | | <code>{}</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
| name | description | sensitive |
|
||||
|---|---|:---:|
|
||||
| [id](outputs.tf#L17) | Fully qualified topic id. | |
|
||||
| [schema](outputs.tf#L26) | Schema resource. | |
|
||||
| [schema_id](outputs.tf#L31) | Schema resource id. | |
|
||||
| [subscription_id](outputs.tf#L36) | Subscription ids. | |
|
||||
| [subscriptions](outputs.tf#L46) | Subscription resources. | |
|
||||
| [topic](outputs.tf#L54) | Topic resource. | |
|
||||
| [schema](outputs.tf#L27) | Schema resource. | |
|
||||
| [schema_id](outputs.tf#L32) | Schema resource id. | |
|
||||
| [subscription_id](outputs.tf#L37) | Subscription ids. | |
|
||||
| [subscriptions](outputs.tf#L48) | Subscription resources. | |
|
||||
| [topic](outputs.tf#L57) | Topic resource. | |
|
||||
<!-- END TFDOC -->
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the authoritative.
|
||||
* 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 {
|
||||
subscription_iam = flatten([
|
||||
for k, v in var.subscriptions : [
|
||||
for role, members in v.iam : {
|
||||
subscription = k
|
||||
role = role
|
||||
members = members
|
||||
}
|
||||
]
|
||||
])
|
||||
subscription_iam_bindings = merge([
|
||||
for k, v in var.subscriptions : {
|
||||
for binding_key, data in v.iam_bindings :
|
||||
binding_key => {
|
||||
subscription = k
|
||||
role = data.role
|
||||
members = data.members
|
||||
condition = data.condition
|
||||
}
|
||||
}
|
||||
]...)
|
||||
subscription_iam_bindings_additive = merge([
|
||||
for k, v in var.subscriptions : {
|
||||
for binding_key, data in v.iam_bindings_additive :
|
||||
binding_key => {
|
||||
subscription = k
|
||||
role = data.role
|
||||
member = data.member
|
||||
condition = data.condition
|
||||
}
|
||||
}
|
||||
]...)
|
||||
}
|
||||
|
||||
moved {
|
||||
from = google_pubsub_topic_iam_binding.default
|
||||
to = google_pubsub_topic_iam_binding.authoritative
|
||||
}
|
||||
|
||||
resource "google_pubsub_topic_iam_binding" "authoritative" {
|
||||
for_each = var.iam
|
||||
project = var.project_id
|
||||
topic = google_pubsub_topic.default.name
|
||||
role = each.key
|
||||
members = each.value
|
||||
}
|
||||
|
||||
resource "google_pubsub_topic_iam_binding" "bindings" {
|
||||
for_each = var.iam_bindings
|
||||
topic = google_pubsub_topic.default.name
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
dynamic "condition" {
|
||||
for_each = each.value.condition == null ? [] : [""]
|
||||
content {
|
||||
expression = each.value.condition.expression
|
||||
title = each.value.condition.title
|
||||
description = each.value.condition.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_pubsub_topic_iam_member" "bindings" {
|
||||
for_each = var.iam_bindings_additive
|
||||
topic = google_pubsub_topic.default.name
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
dynamic "condition" {
|
||||
for_each = each.value.condition == null ? [] : [""]
|
||||
content {
|
||||
expression = each.value.condition.expression
|
||||
title = each.value.condition.title
|
||||
description = each.value.condition.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
moved {
|
||||
from = google_pubsub_subscription_iam_binding.default
|
||||
to = google_pubsub_subscription_iam_binding.authoritative
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription_iam_binding" "authoritative" {
|
||||
for_each = {
|
||||
for binding in local.subscription_iam :
|
||||
"${binding.subscription}.${binding.role}" => binding
|
||||
}
|
||||
project = var.project_id
|
||||
subscription = google_pubsub_subscription.default[each.value.subscription].name
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription_iam_binding" "bindings" {
|
||||
for_each = local.subscription_iam_bindings
|
||||
project = var.project_id
|
||||
subscription = google_pubsub_subscription.default[each.value.subscription].name
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
dynamic "condition" {
|
||||
for_each = each.value.condition == null ? [] : [""]
|
||||
content {
|
||||
expression = each.value.condition.expression
|
||||
title = each.value.condition.title
|
||||
description = each.value.condition.description
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription_iam_member" "members" {
|
||||
for_each = local.subscription_iam_bindings_additive
|
||||
project = var.project_id
|
||||
subscription = google_pubsub_subscription.default[each.value.subscription].name
|
||||
role = each.value.role
|
||||
member = each.value.member
|
||||
dynamic "condition" {
|
||||
for_each = each.value.condition == null ? [] : [""]
|
||||
content {
|
||||
expression = each.value.condition.expression
|
||||
title = each.value.condition.title
|
||||
description = each.value.condition.description
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -15,27 +15,6 @@
|
|||
*/
|
||||
|
||||
locals {
|
||||
sub_iam_members = flatten([
|
||||
for sub, roles in var.subscription_iam : [
|
||||
for role, members in roles : {
|
||||
sub = sub
|
||||
role = role
|
||||
members = members
|
||||
}
|
||||
]
|
||||
])
|
||||
metadata_config = {
|
||||
for k, v in var.cloud_storage_subscription_configs : k => v.avro_config
|
||||
}
|
||||
oidc_config = {
|
||||
for k, v in var.push_configs : k => v.oidc_token
|
||||
}
|
||||
subscriptions = {
|
||||
for k, v in var.subscriptions : k => {
|
||||
labels = try(v.labels, v, null) == null ? var.labels : v.labels
|
||||
options = try(v.options, v, null) == null ? var.defaults : v.options
|
||||
}
|
||||
}
|
||||
topic_id_static = "projects/${var.project_id}/topics/${var.name}"
|
||||
}
|
||||
|
||||
|
@ -70,94 +49,73 @@ resource "google_pubsub_topic" "default" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "google_pubsub_topic_iam_binding" "default" {
|
||||
for_each = var.iam
|
||||
project = var.project_id
|
||||
topic = google_pubsub_topic.default.name
|
||||
role = each.key
|
||||
members = each.value
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription" "default" {
|
||||
for_each = local.subscriptions
|
||||
project = var.project_id
|
||||
name = each.key
|
||||
topic = google_pubsub_topic.default.name
|
||||
labels = each.value.labels
|
||||
ack_deadline_seconds = each.value.options.ack_deadline_seconds
|
||||
message_retention_duration = each.value.options.message_retention_duration
|
||||
retain_acked_messages = each.value.options.retain_acked_messages
|
||||
filter = each.value.options.filter
|
||||
for_each = var.subscriptions
|
||||
project = var.project_id
|
||||
name = each.key
|
||||
topic = google_pubsub_topic.default.name
|
||||
labels = each.value.labels
|
||||
ack_deadline_seconds = each.value.ack_deadline_seconds
|
||||
message_retention_duration = each.value.message_retention_duration
|
||||
retain_acked_messages = each.value.retain_acked_messages
|
||||
filter = each.value.filter
|
||||
enable_message_ordering = each.value.enable_message_ordering
|
||||
enable_exactly_once_delivery = each.value.enable_exactly_once_delivery
|
||||
|
||||
dynamic "expiration_policy" {
|
||||
for_each = each.value.options.expiration_policy_ttl == null ? [] : [""]
|
||||
for_each = each.value.expiration_policy_ttl == null ? [] : [""]
|
||||
content {
|
||||
ttl = each.value.options.expiration_policy_ttl
|
||||
ttl = each.value.expiration_policy_ttl
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "dead_letter_policy" {
|
||||
for_each = try(var.dead_letter_configs[each.key], null) == null ? [] : [""]
|
||||
for_each = each.value.dead_letter_policy == null ? [] : [""]
|
||||
content {
|
||||
dead_letter_topic = var.dead_letter_configs[each.key].topic
|
||||
max_delivery_attempts = var.dead_letter_configs[each.key].max_delivery_attempts
|
||||
dead_letter_topic = each.value.dead_letter_policy.topic
|
||||
max_delivery_attempts = each.value.dead_letter_policy.max_delivery_attempts
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "push_config" {
|
||||
for_each = try(var.push_configs[each.key], null) == null ? [] : [""]
|
||||
for_each = each.value.push == null ? [] : [""]
|
||||
content {
|
||||
push_endpoint = var.push_configs[each.key].endpoint
|
||||
attributes = var.push_configs[each.key].attributes
|
||||
push_endpoint = each.value.push.endpoint
|
||||
attributes = each.value.push.attributes
|
||||
dynamic "oidc_token" {
|
||||
for_each = (
|
||||
local.oidc_config[each.key] == null ? [] : [""]
|
||||
)
|
||||
for_each = each.value.push.oidc_token == null ? [] : [""]
|
||||
content {
|
||||
service_account_email = local.oidc_config[each.key].service_account_email
|
||||
audience = local.oidc_config[each.key].audience
|
||||
service_account_email = each.value.push.oidc_token.service_account_email
|
||||
audience = each.value.push.oidc_token.audience
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "bigquery_config" {
|
||||
for_each = try(var.bigquery_subscription_configs[each.key], null) == null ? [] : [""]
|
||||
for_each = each.value.bigquery == null ? [] : [""]
|
||||
content {
|
||||
table = var.bigquery_subscription_configs[each.key].table
|
||||
use_topic_schema = var.bigquery_subscription_configs[each.key].use_topic_schema
|
||||
write_metadata = var.bigquery_subscription_configs[each.key].write_metadata
|
||||
drop_unknown_fields = var.bigquery_subscription_configs[each.key].drop_unknown_fields
|
||||
table = each.value.bigquery.table
|
||||
use_topic_schema = each.value.bigquery.use_topic_schema
|
||||
write_metadata = each.value.bigquery.write_metadata
|
||||
drop_unknown_fields = each.value.bigquery.drop_unknown_fields
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "cloud_storage_config" {
|
||||
for_each = try(var.cloud_storage_subscription_configs[each.key], null) == null ? [] : [""]
|
||||
for_each = each.value.cloud_storage == null ? [] : [""]
|
||||
content {
|
||||
bucket = var.cloud_storage_subscription_configs[each.key].bucket
|
||||
filename_prefix = var.cloud_storage_subscription_configs[each.key].filename_prefix
|
||||
filename_suffix = var.cloud_storage_subscription_configs[each.key].filename_suffix
|
||||
max_duration = var.cloud_storage_subscription_configs[each.key].max_duration
|
||||
max_bytes = var.cloud_storage_subscription_configs[each.key].max_bytes
|
||||
bucket = each.value.cloud_storage.bucket
|
||||
filename_prefix = each.value.cloud_storage.filename_prefix
|
||||
filename_suffix = each.value.cloud_storage.filename_suffix
|
||||
max_duration = each.value.cloud_storage.max_duration
|
||||
max_bytes = each.value.cloud_storage.max_bytes
|
||||
dynamic "avro_config" {
|
||||
for_each = (
|
||||
local.metadata_config[each.key] == null ? [] : [""]
|
||||
)
|
||||
for_each = each.value.cloud_storage.avro_config == null ? [] : [""]
|
||||
content {
|
||||
write_metadata = local.metadata_config[each.key].write_metadata
|
||||
write_metadata = each.value.cloud_storage.avro_config.write_metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_pubsub_subscription_iam_binding" "default" {
|
||||
for_each = {
|
||||
for binding in local.sub_iam_members :
|
||||
"${binding.sub}.${binding.role}" => binding
|
||||
}
|
||||
project = var.project_id
|
||||
subscription = google_pubsub_subscription.default[each.value.sub].name
|
||||
role = each.value.role
|
||||
members = each.value.members
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,7 +19,8 @@ output "id" {
|
|||
value = local.topic_id_static
|
||||
depends_on = [
|
||||
google_pubsub_topic.default,
|
||||
google_pubsub_topic_iam_binding.default
|
||||
google_pubsub_topic_iam_binding.authoritative,
|
||||
google_pubsub_topic_iam_binding.bindings
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -39,7 +40,8 @@ output "subscription_id" {
|
|||
for k, v in google_pubsub_subscription.default : k => v.id
|
||||
}
|
||||
depends_on = [
|
||||
google_pubsub_subscription_iam_binding.default
|
||||
google_pubsub_subscription_iam_binding.authoritative,
|
||||
google_pubsub_subscription_iam_binding.bindings
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -47,7 +49,8 @@ output "subscriptions" {
|
|||
description = "Subscription resources."
|
||||
value = google_pubsub_subscription.default
|
||||
depends_on = [
|
||||
google_pubsub_subscription_iam_binding.default
|
||||
google_pubsub_subscription_iam_binding.authoritative,
|
||||
google_pubsub_subscription_iam_binding.bindings
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -55,6 +58,7 @@ output "topic" {
|
|||
description = "Topic resource."
|
||||
value = google_pubsub_topic.default
|
||||
depends_on = [
|
||||
google_pubsub_topic_iam_binding.default
|
||||
google_pubsub_topic_iam_binding.authoritative,
|
||||
google_pubsub_topic_iam_binding.bindings
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2022 Google LLC
|
||||
* Copyright 2023 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,63 +14,41 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
variable "bigquery_subscription_configs" {
|
||||
description = "Configuration parameters for BigQuery subscriptions."
|
||||
type = map(object({
|
||||
table = string
|
||||
use_topic_schema = bool
|
||||
write_metadata = bool
|
||||
drop_unknown_fields = bool
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "cloud_storage_subscription_configs" {
|
||||
description = "Configuration parameters for Cloud Storage subscriptions."
|
||||
type = map(object({
|
||||
bucket = string
|
||||
filename_prefix = string
|
||||
filename_suffix = string
|
||||
max_duration = string
|
||||
max_bytes = number
|
||||
avro_config = object({
|
||||
write_metadata = bool
|
||||
})
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "dead_letter_configs" {
|
||||
description = "Per-subscription dead letter policy configuration."
|
||||
type = map(object({
|
||||
topic = string
|
||||
max_delivery_attempts = number
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "defaults" {
|
||||
description = "Subscription defaults for options."
|
||||
type = object({
|
||||
ack_deadline_seconds = number
|
||||
message_retention_duration = string
|
||||
retain_acked_messages = bool
|
||||
expiration_policy_ttl = string
|
||||
filter = string
|
||||
})
|
||||
default = {
|
||||
ack_deadline_seconds = null
|
||||
message_retention_duration = null
|
||||
retain_acked_messages = null
|
||||
expiration_policy_ttl = null
|
||||
filter = null
|
||||
}
|
||||
}
|
||||
|
||||
variable "iam" {
|
||||
description = "IAM bindings for topic in {ROLE => [MEMBERS]} format."
|
||||
type = map(list(string))
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "iam_bindings" {
|
||||
description = "Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary."
|
||||
type = map(object({
|
||||
members = list(string)
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "iam_bindings_additive" {
|
||||
description = "Keyring individual additive IAM bindings. Keys are arbitrary."
|
||||
type = map(object({
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "kms_key" {
|
||||
|
@ -83,6 +61,7 @@ variable "labels" {
|
|||
description = "Labels."
|
||||
type = map(string)
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "message_retention_duration" {
|
||||
|
@ -101,23 +80,11 @@ variable "project_id" {
|
|||
type = string
|
||||
}
|
||||
|
||||
variable "push_configs" {
|
||||
description = "Push subscription configurations."
|
||||
type = map(object({
|
||||
attributes = map(string)
|
||||
endpoint = string
|
||||
oidc_token = object({
|
||||
audience = string
|
||||
service_account_email = string
|
||||
})
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "regions" {
|
||||
description = "List of regions used to set persistence policy."
|
||||
type = list(string)
|
||||
default = []
|
||||
nullable = false
|
||||
}
|
||||
|
||||
variable "schema" {
|
||||
|
@ -130,23 +97,72 @@ variable "schema" {
|
|||
default = null
|
||||
}
|
||||
|
||||
variable "subscription_iam" {
|
||||
description = "IAM bindings for subscriptions in {SUBSCRIPTION => {ROLE => [MEMBERS]}} format."
|
||||
type = map(map(list(string)))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "subscriptions" {
|
||||
description = "Topic subscriptions. Also define push configs for push subscriptions. If options is set to null subscription defaults will be used. Labels default to topic labels if set to null."
|
||||
type = map(object({
|
||||
labels = map(string)
|
||||
options = object({
|
||||
ack_deadline_seconds = number
|
||||
message_retention_duration = string
|
||||
retain_acked_messages = bool
|
||||
expiration_policy_ttl = string
|
||||
filter = string
|
||||
})
|
||||
labels = optional(map(string))
|
||||
ack_deadline_seconds = optional(number)
|
||||
message_retention_duration = optional(string)
|
||||
retain_acked_messages = optional(bool, false)
|
||||
expiration_policy_ttl = optional(string)
|
||||
filter = optional(string)
|
||||
enable_message_ordering = optional(bool, false)
|
||||
enable_exactly_once_delivery = optional(bool, false)
|
||||
dead_letter_policy = optional(object({
|
||||
topic = string
|
||||
max_delivery_attempts = optional(number)
|
||||
}))
|
||||
retry_policy = optional(object({
|
||||
minimum_backoff = optional(number)
|
||||
maximum_backoff = optional(number)
|
||||
}))
|
||||
|
||||
bigquery = optional(object({
|
||||
table = string
|
||||
use_topic_schema = optional(bool, false)
|
||||
write_metadata = optional(bool, false)
|
||||
drop_unknown_fields = optional(bool, false)
|
||||
}))
|
||||
cloud_storage = optional(object({
|
||||
bucket = string
|
||||
filename_prefix = optional(string)
|
||||
filename_suffix = optional(string)
|
||||
max_duration = optional(string)
|
||||
max_bytes = optional(number)
|
||||
avro_config = optional(object({
|
||||
write_metadata = optional(bool, false)
|
||||
}))
|
||||
}))
|
||||
push = optional(object({
|
||||
endpoint = string
|
||||
attributes = optional(map(string))
|
||||
no_wrapper = optional(bool, false)
|
||||
oidc_token = optional(object({
|
||||
audience = optional(string)
|
||||
service_account_email = string
|
||||
}))
|
||||
}))
|
||||
|
||||
iam = optional(map(list(string)), {})
|
||||
iam_bindings = optional(map(object({
|
||||
members = list(string)
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
iam_bindings_additive = optional(map(object({
|
||||
member = string
|
||||
role = string
|
||||
condition = optional(object({
|
||||
expression = string
|
||||
title = string
|
||||
description = optional(string)
|
||||
}))
|
||||
})), {})
|
||||
}))
|
||||
default = {}
|
||||
default = {}
|
||||
nullable = false
|
||||
}
|
||||
|
|
|
@ -18,37 +18,26 @@ values:
|
|||
name: key-a
|
||||
purpose: ENCRYPT_DECRYPT
|
||||
rotation_period: null
|
||||
skip_initial_version_creation: null
|
||||
timeouts: null
|
||||
skip_initial_version_creation: false
|
||||
module.kms.google_kms_crypto_key.default["key-b"]:
|
||||
labels: null
|
||||
name: key-b
|
||||
purpose: ENCRYPT_DECRYPT
|
||||
rotation_period: 604800s
|
||||
skip_initial_version_creation: null
|
||||
timeouts: null
|
||||
skip_initial_version_creation: false
|
||||
module.kms.google_kms_crypto_key.default["key-c"]:
|
||||
labels:
|
||||
env: test
|
||||
name: key-c
|
||||
purpose: ENCRYPT_DECRYPT
|
||||
rotation_period: null
|
||||
skip_initial_version_creation: null
|
||||
timeouts: null
|
||||
module.kms.google_kms_crypto_key_iam_binding.default["key-a.roles/cloudkms.admin"]:
|
||||
skip_initial_version_creation: false
|
||||
module.kms.google_kms_crypto_key_iam_binding.authoritative["key-a.roles/cloudkms.admin"]:
|
||||
condition: []
|
||||
members:
|
||||
- user:user3@example.com
|
||||
role: roles/cloudkms.admin
|
||||
? module.kms.google_kms_crypto_key_iam_member.default["key-b.roles/cloudkms.cryptoKeyEncrypterDecrypteruser:user4@example.com"]
|
||||
: condition: []
|
||||
member: user:user4@example.com
|
||||
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||||
? module.kms.google_kms_crypto_key_iam_member.default["key-b.roles/cloudkms.cryptoKeyEncrypterDecrypteruser:user5@example.com"]
|
||||
: condition: []
|
||||
member: user:user5@example.com
|
||||
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||||
module.kms.google_kms_crypto_key_iam_member.members["key-b-am1"]:
|
||||
module.kms.google_kms_crypto_key_iam_member.members["key-b-iam1"]:
|
||||
condition: []
|
||||
member: user:am1@example.com
|
||||
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||||
|
@ -56,23 +45,9 @@ values:
|
|||
location: europe-west1
|
||||
name: test
|
||||
project: my-project
|
||||
timeouts: null
|
||||
module.kms.google_kms_key_ring_iam_member.default["roles/cloudkms.cryptoKeyEncrypterDecrypteruser:user1@example.com"]:
|
||||
condition: []
|
||||
member: user:user1@example.com
|
||||
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||||
module.kms.google_kms_key_ring_iam_member.default["roles/cloudkms.cryptoKeyEncrypterDecrypteruser:user2@example.com"]:
|
||||
condition: []
|
||||
member: user:user2@example.com
|
||||
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
|
||||
|
||||
counts:
|
||||
google_kms_crypto_key: 3
|
||||
google_kms_crypto_key_iam_binding: 1
|
||||
google_kms_crypto_key_iam_member: 3
|
||||
google_kms_crypto_key_iam_member: 1
|
||||
google_kms_key_ring: 1
|
||||
google_kms_key_ring_iam_member: 2
|
||||
modules: 1
|
||||
resources: 10
|
||||
|
||||
outputs: {}
|
||||
|
|
|
@ -15,25 +15,19 @@
|
|||
values:
|
||||
module.kms.google_kms_crypto_key.default["key-a"]:
|
||||
name: key-a
|
||||
purpose: ENCRYPT_DECRYPT
|
||||
module.kms.google_kms_crypto_key.default["key-b"]:
|
||||
name: key-b
|
||||
purpose: ENCRYPT_DECRYPT
|
||||
module.kms.google_kms_crypto_key.default["key-c"]:
|
||||
name: key-c
|
||||
purpose: ASYMMETRIC_SIGN
|
||||
version_template:
|
||||
- algorithm: EC_SIGN_P384_SHA384
|
||||
protection_level: SOFTWARE
|
||||
protection_level: HSM
|
||||
module.kms.google_kms_key_ring.default[0]:
|
||||
location: europe-west1
|
||||
name: test
|
||||
project: my-project
|
||||
|
||||
counts:
|
||||
google_kms_crypto_key: 3
|
||||
google_kms_crypto_key: 1
|
||||
google_kms_key_ring: 1
|
||||
modules: 1
|
||||
resources: 4
|
||||
resources: 2
|
||||
|
||||
outputs: {}
|
||||
|
|
|
@ -16,14 +16,14 @@ values:
|
|||
module.pubsub.google_pubsub_topic.default:
|
||||
name: my-topic
|
||||
project: my-project
|
||||
module.pubsub.google_pubsub_topic_iam_binding.default["roles/pubsub.subscriber"]:
|
||||
module.pubsub.google_pubsub_topic_iam_binding.authoritative["roles/pubsub.subscriber"]:
|
||||
condition: []
|
||||
members:
|
||||
- user:user1@example.com
|
||||
project: my-project
|
||||
role: roles/pubsub.subscriber
|
||||
topic: my-topic
|
||||
module.pubsub.google_pubsub_topic_iam_binding.default["roles/pubsub.viewer"]:
|
||||
module.pubsub.google_pubsub_topic_iam_binding.authoritative["roles/pubsub.viewer"]:
|
||||
condition: []
|
||||
members:
|
||||
- group:foo@example.com
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
# limitations under the License.
|
||||
|
||||
values:
|
||||
module.pubsub.google_pubsub_subscription_iam_binding.default["test-1.roles/pubsub.subscriber"]:
|
||||
module.pubsub.google_pubsub_subscription_iam_binding.authoritative["test-1.roles/pubsub.subscriber"]:
|
||||
condition: []
|
||||
members:
|
||||
- user:user1@ludomagno.net
|
||||
- user:user1@example.com
|
||||
project: my-project
|
||||
role: roles/pubsub.subscriber
|
||||
subscription: test-1
|
||||
|
|
|
@ -16,22 +16,22 @@ values:
|
|||
module.pubsub.google_pubsub_subscription.default["test-pull"]:
|
||||
bigquery_config: []
|
||||
dead_letter_policy: []
|
||||
enable_exactly_once_delivery: null
|
||||
enable_message_ordering: null
|
||||
enable_exactly_once_delivery: False
|
||||
enable_message_ordering: False
|
||||
filter: null
|
||||
labels: null
|
||||
message_retention_duration: 604800s
|
||||
name: test-pull
|
||||
project: my-project
|
||||
push_config: []
|
||||
retain_acked_messages: null
|
||||
retain_acked_messages: False
|
||||
retry_policy: []
|
||||
topic: my-topic
|
||||
module.pubsub.google_pubsub_subscription.default["test-pull-override"]:
|
||||
bigquery_config: []
|
||||
dead_letter_policy: []
|
||||
enable_exactly_once_delivery: null
|
||||
enable_message_ordering: null
|
||||
enable_exactly_once_delivery: False
|
||||
enable_message_ordering: False
|
||||
filter: null
|
||||
labels:
|
||||
test: override
|
||||
|
@ -39,7 +39,7 @@ values:
|
|||
name: test-pull-override
|
||||
project: my-project
|
||||
push_config: []
|
||||
retain_acked_messages: true
|
||||
retain_acked_messages: True
|
||||
retry_policy: []
|
||||
topic: my-topic
|
||||
module.pubsub.google_pubsub_topic.default:
|
||||
|
|
Loading…
Reference in New Issue