From 4b500c23666b1b98d5bc8849ebb10276cd2ad56d Mon Sep 17 00:00:00 2001 From: Ludovico Magnocavallo Date: Mon, 10 Jan 2022 16:35:02 +0100 Subject: [PATCH] add support for additive IAM roles to KMS (#417) --- modules/kms/README.md | 27 ++++++++++++++++++++++----- modules/kms/main.tf | 39 +++++++++++++++++++++++++++++++++++++++ modules/kms/variables.tf | 16 ++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/modules/kms/README.md b/modules/kms/README.md index e17a3425..c58e8c56 100644 --- a/modules/kms/README.md +++ b/modules/kms/README.md @@ -17,7 +17,7 @@ module "kms" { source = "./modules/kms" project_id = "my-project" iam = { - "roles/owner" = ["user:user1@example.com"] + "roles/cloudkms.admin" = ["user:user1@example.com"] } keyring = { location = "europe-west1", name = "test" } keyring_create = false @@ -32,9 +32,21 @@ module "kms" { module "kms" { source = "./modules/kms" project_id = "my-project" + iam_additive = { + "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ + "user:user1@example.com", "user:user2@example.com" + ] + } key_iam = { key-a = { - "roles/owner" = ["user:user1@example.com"] + "roles/cloudkms.admin" = ["user:user3@example.com"] + } + } + key_iam_additive = { + key-b = { + "roles/cloudkms.cryptoKeyEncrypterDecrypter" = [ + "user:user4@example.com", "user:user5@example.com" + ] } } keyring = { location = "europe-west1", name = "test" } @@ -44,7 +56,7 @@ module "kms" { key-c = { rotation_period = null, labels = { env = "test" } } } } -# tftest:modules=1:resources=5 +# tftest:modules=1:resources=9 ``` ### Crypto key purpose @@ -77,8 +89,10 @@ module "kms" { |---|---|:---:|:---:|:---:| | keyring | Keyring attributes. | object({…}) | ✓ | | | project_id | Project id where the keyring will be created. | string | ✓ | | -| iam | Keyring IAM bindings for topic in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| key_iam | Key IAM bindings for topic in {KEY => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | +| iam | Keyring IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| iam_additive | Keyring IAM additive bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| key_iam | Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format. | map(map(list(string))) | | {} | +| key_iam_additive | Key IAM additive bindings in {ROLE => [MEMBERS]} format. | map(map(list(string))) | | {} | | key_purpose | Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | map(object({…})) | | {} | | key_purpose_defaults | 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. | object({…}) | | {…} | | keyring_create | Set to false to manage keys and IAM bindings in an existing keyring. | bool | | true | @@ -97,3 +111,6 @@ module "kms" { + + + diff --git a/modules/kms/main.tf b/modules/kms/main.tf index 59cbcf65..88ac158e 100644 --- a/modules/kms/main.tf +++ b/modules/kms/main.tf @@ -15,6 +15,25 @@ */ locals { + iam_additive_members = flatten([ + for role, members in var.iam_additive : [ + for member in members : { + member = member + role = role + } + ] + ]) + key_iam_additive_members = flatten([ + for key, roles in var.key_iam_additive : [ + for role, members in roles : [ + for member in members : { + key = key + member = member + role = role + } + ] + ] + ]) key_iam_members = flatten([ for key, roles in var.key_iam : [ for role, members in roles : { @@ -57,6 +76,16 @@ resource "google_kms_key_ring_iam_binding" "default" { members = each.value } +resource "google_kms_key_ring_iam_member" "default" { + for_each = { + for binding in local.iam_additive_members : + "${binding.role}${binding.member}" => binding + } + key_ring_id = local.keyring.id + role = each.value.role + member = each.value.member +} + resource "google_kms_crypto_key" "default" { for_each = var.keys key_ring = local.keyring.id @@ -82,3 +111,13 @@ resource "google_kms_crypto_key_iam_binding" "default" { crypto_key_id = google_kms_crypto_key.default[each.value.key].id members = each.value.members } + +resource "google_kms_crypto_key_iam_member" "default" { + for_each = { + for binding in local.key_iam_additive_members : + "${binding.key}.${binding.role}${binding.member}" => binding + } + role = each.value.role + crypto_key_id = google_kms_crypto_key.default[each.value.key].id + member = each.value.member +} diff --git a/modules/kms/variables.tf b/modules/kms/variables.tf index d2c425ba..191f3846 100644 --- a/modules/kms/variables.tf +++ b/modules/kms/variables.tf @@ -15,13 +15,25 @@ */ variable "iam" { - description = "Keyring IAM bindings for topic in {ROLE => [MEMBERS]} format." + description = "Keyring IAM bindings in {ROLE => [MEMBERS]} format." + type = map(list(string)) + default = {} +} + +variable "iam_additive" { + description = "Keyring IAM additive bindings in {ROLE => [MEMBERS]} format." type = map(list(string)) default = {} } variable "key_iam" { - description = "Key IAM bindings for topic in {KEY => {ROLE => [MEMBERS]}} format." + description = "Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format." + type = map(map(list(string))) + default = {} +} + +variable "key_iam_additive" { + description = "Key IAM additive bindings in {ROLE => [MEMBERS]} format." type = map(map(list(string))) default = {} }