Update kms module key-level IAM
This commit is contained in:
parent
1c5aabbd08
commit
da883bab8c
|
@ -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 = {}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
|
|
|
@ -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#L53) | Keyring attributes. | <code title="object({ location = string name = string })">object({…})</code> | ✓ | |
|
||||
| [project_id](variables.tf#L102) | 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> |
|
||||
| [keyring_create](variables.tf#L61) | Set to false to manage keys and IAM bindings in an existing keyring. | <code>bool</code> | | <code>true</code> |
|
||||
| [keys](variables.tf#L67) | 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#L107) | 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.
|
||||
|
@ -50,72 +50,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 +67,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 +107,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
|
||||
}
|
||||
|
|
|
@ -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: {}
|
||||
|
|
Loading…
Reference in New Issue