From d07f8fd33d0a5fc8eb9118a0258e3158949d95f9 Mon Sep 17 00:00:00 2001 From: luigi-bitonti <93377317+luigi-bitonti@users.noreply.github.com> Date: Fri, 10 Nov 2023 16:45:47 +0100 Subject: [PATCH] Added CMEK for Secret auto managed (#1739) Allow to specify custom KMS keys for Secret Manager secrets --- .../sqlserver-alwayson/secrets.tf | 4 +- .../data-solutions/vertex-mlops/ci-cd.tf | 10 ++-- modules/secret-manager/README.md | 53 +++++++++++-------- modules/secret-manager/main.tf | 23 ++++---- modules/secret-manager/variables.tf | 19 +++---- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/blueprints/data-solutions/sqlserver-alwayson/secrets.tf b/blueprints/data-solutions/sqlserver-alwayson/secrets.tf index 2a0bba8d..f25871de 100644 --- a/blueprints/data-solutions/sqlserver-alwayson/secrets.tf +++ b/blueprints/data-solutions/sqlserver-alwayson/secrets.tf @@ -19,7 +19,9 @@ module "secret-manager" { source = "../../../modules/secret-manager" project_id = var.project_id secrets = { - (local.ad_user_password_secret) = null + (local.ad_user_password_secret) = { + locations = null + } } versions = { (local.ad_user_password_secret) = { diff --git a/blueprints/data-solutions/vertex-mlops/ci-cd.tf b/blueprints/data-solutions/vertex-mlops/ci-cd.tf index 3c7c8631..28fb320b 100644 --- a/blueprints/data-solutions/vertex-mlops/ci-cd.tf +++ b/blueprints/data-solutions/vertex-mlops/ci-cd.tf @@ -57,10 +57,12 @@ module "secret-manager" { project_id = module.project.project_id source = "../../../modules/secret-manager" secrets = { - github-key = [var.region] - } - encryption_key = { - "${var.region}" = var.service_encryption_keys.secretmanager + github-key = { + locations = [var.region] + keys = { + "${var.region}" = var.service_encryption_keys.secretmanager + } + } } iam = { github-key = { diff --git a/modules/secret-manager/README.md b/modules/secret-manager/README.md index dc092983..8d1d8b11 100644 --- a/modules/secret-manager/README.md +++ b/modules/secret-manager/README.md @@ -17,8 +17,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } } # tftest modules=1 resources=2 @@ -33,8 +35,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } iam = { test-auto = { @@ -57,8 +61,10 @@ module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-auto = null - test-manual = ["europe-west1", "europe-west4"] + test-auto = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + } } versions = { test-auto = { @@ -75,34 +81,40 @@ module "secret-manager" { ### Secret with customer managed encryption key -Secrets will be used if an encryption key is set in the `encryption_key` variable for the secret region. +CMEK will be used if an encryption key is set in the `keys` field of `secrets` object for the secret region. For secrets with auto-replication, a global key must be specified. ```hcl module "secret-manager" { source = "./fabric/modules/secret-manager" project_id = "my-project" secrets = { - test-encryption = ["europe-west1", "europe-west4"] - } - encryption_key = { - europe-west1 = "projects/PROJECT_ID/locations/europe-west1/keyRings/KEYRING/cryptoKeys/KEY" - europe-west4 = "projects/PROJECT_ID/locations/europe-west4/keyRings/KEYRING/cryptoKeys/KEY" + test-auto = { + keys = { + global = "projects/PROJECT_ID/locations/global/keyRings/KEYRING/cryptoKeys/KEY" + } + } + test-auto-nokeys = {} + test-manual = { + locations = ["europe-west1", "europe-west4"] + keys = { + europe-west1 = "projects/PROJECT_ID/locations/europe-west1/keyRings/KEYRING/cryptoKeys/KEY" + europe-west4 = "projects/PROJECT_ID/locations/europe-west4/keyRings/KEYRING/cryptoKeys/KEY" + } + } } } -# tftest modules=1 resources=1 +# tftest modules=1 resources=3 ``` - ## Variables | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [project_id](variables.tf#L35) | Project id where the keyring will be created. | string | ✓ | | -| [encryption_key](variables.tf#L17) | Self link of the KMS keys in {LOCATION => KEY} format. A key must be provided for all replica locations. | map(string) | | null | -| [iam](variables.tf#L23) | IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | -| [labels](variables.tf#L29) | Optional labels for each secret. | map(map(string)) | | {} | -| [secrets](variables.tf#L40) | Map of secrets to manage and their locations. If locations is null, automatic management will be set. | map(list(string)) | | {} | -| [versions](variables.tf#L46) | Optional versions to manage for each secret. Version names are only used internally to track individual versions. | map(map(object({…}))) | | {} | +| [project_id](variables.tf#L29) | Project id where the keyring will be created. | string | ✓ | | +| [iam](variables.tf#L17) | IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | +| [labels](variables.tf#L23) | Optional labels for each secret. | map(map(string)) | | {} | +| [secrets](variables.tf#L34) | Map of secrets to manage, their locations and KMS keys in {LOCATION => KEY} format. {GLOBAL => KEY} format enables CMEK for automatic managed secrets. If locations is null, automatic management will be set. | map(object({…})) | | {} | +| [versions](variables.tf#L43) | Optional versions to manage for each secret. Version names are only used internally to track individual versions. | map(map(object({…}))) | | {} | ## Outputs @@ -112,7 +124,6 @@ module "secret-manager" { | [secrets](outputs.tf#L24) | Secret resources. | | | [version_ids](outputs.tf#L29) | Version ids keyed by secret name : version name. | | | [versions](outputs.tf#L36) | Secret versions. | ✓ | - ## Requirements diff --git a/modules/secret-manager/main.tf b/modules/secret-manager/main.tf index 1a17ac21..61f4d5ef 100644 --- a/modules/secret-manager/main.tf +++ b/modules/secret-manager/main.tf @@ -42,27 +42,32 @@ resource "google_secret_manager_secret" "default" { labels = lookup(var.labels, each.key, null) dynamic "replication" { - for_each = each.value == null ? [""] : [] + for_each = each.value.locations == null ? [""] : [] content { - # TODO(jccb): support custom keys inside auto - auto {} + auto { + dynamic "customer_managed_encryption" { + for_each = try(lookup(each.value.keys, "global", null) == null ? [] : [""], []) + content { + kms_key_name = each.value.keys["global"] + } + } + } } } dynamic "replication" { - for_each = each.value == null ? [] : [each.value] - iterator = locations + for_each = each.value.locations == null ? [] : [""] content { user_managed { dynamic "replicas" { - for_each = locations.value + for_each = each.value.locations iterator = location content { location = location.value dynamic "customer_managed_encryption" { - for_each = try(var.encryption_key[location.value] != null ? [""] : [], []) + for_each = try(lookup(each.value.keys, location.value, null) == null ? [] : [""], []) content { - kms_key_name = var.encryption_key[location.value] + kms_key_name = each.value.keys[location.value] } } } @@ -88,4 +93,4 @@ resource "google_secret_manager_secret_iam_binding" "default" { role = each.value.role secret_id = google_secret_manager_secret.default[each.value.secret].id members = each.value.members -} +} \ No newline at end of file diff --git a/modules/secret-manager/variables.tf b/modules/secret-manager/variables.tf index 7d7b5284..089f2a69 100644 --- a/modules/secret-manager/variables.tf +++ b/modules/secret-manager/variables.tf @@ -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,12 +14,6 @@ * limitations under the License. */ -variable "encryption_key" { - description = "Self link of the KMS keys in {LOCATION => KEY} format. A key must be provided for all replica locations." - type = map(string) - default = null -} - variable "iam" { description = "IAM bindings in {SECRET => {ROLE => [MEMBERS]}} format." type = map(map(list(string))) @@ -38,9 +32,12 @@ variable "project_id" { } variable "secrets" { - description = "Map of secrets to manage and their locations. If locations is null, automatic management will be set." - type = map(list(string)) - default = {} + description = "Map of secrets to manage, their locations and KMS keys in {LOCATION => KEY} format. {GLOBAL => KEY} format enables CMEK for automatic managed secrets. If locations is null, automatic management will be set." + type = map(object({ + locations = optional(list(string), null) + keys = optional(map(string), null) + })) + default = {} } variable "versions" { @@ -50,4 +47,4 @@ variable "versions" { data = string }))) default = {} -} +} \ No newline at end of file