diff --git a/docs/upgrading_to_v8.0.md b/docs/upgrading_to_v8.0.md new file mode 100644 index 00000000..830f7ab6 --- /dev/null +++ b/docs/upgrading_to_v8.0.md @@ -0,0 +1,78 @@ +# Upgrading to v8.0 + +The v8.0 release of the terraform-google-cloud-storage module is a backwards incompatible release, due to the following breaking change: + +- The fix for the issue [Error when using simple bucket with kms created in the same configuration](https://github.com/terraform-google-modules/terraform-google-cloud-storage/issues/339) in the [Simple Bucket](../modules/simple_bucket/README.md) module replaced the creation of an internal KMS key based in the variable `encryption.default_kms_key_name` having a `null` value with an explicit control flag `internal_encryption_config.create_encryption_key`. + +## Migration Instructions + +To migrate from 5.x or 6.0.0 no change is necessary for the Simple Bucket module. + +To migrate from 6.1.0 or 7.x: + +- If the feature to auto create KMS keys was not used no change is necessary for the Simple Bucket module +- If the feature to auto create KMS keys was used, a migration from 7.x to 8.x for the Simple Bucket module as showcased below + +```diff +module "simple_bucket" { + source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" +- version = "~> 7.0" ++ version = "~> 8.0" +``` + +will produce the following output during a `terraform plan`: + +``` + +Error: Missing required argument + + with module.simple_bucket.google_storage_bucket.bucket, + on .terraform/modules/simple_bucket/main.tf line 22, in resource "google_storage_bucket" "bucket": + 22: resource "google_storage_bucket" "bucket" { + +The argument "encryption.0.default_kms_key_name" is required, but no definition was found. +``` + +Removing the `null` valued `encryption.default_kms_key_name` + +```diff +- -encryption = { +- default_kms_key_name = null +- } +``` + +will produce the following output during a `terraform plan`: + +``` + # module.simple_bucket.google_storage_bucket.bucket will be updated in-place + + # module.simple_bucket.module.encryption_key[0].google_kms_crypto_key.key_ephemeral[0] will be destroyed + # (because module.simple_bucket.module.encryption_key[0] is not in configuration) + + # module.simple_bucket.module.encryption_key[0].google_kms_crypto_key_iam_binding.decrypters[0] will be destroyed + # (because module.simple_bucket.module.encryption_key[0] is not in configuration) + + # module.simple_bucket.module.encryption_key[0].google_kms_crypto_key_iam_binding.encrypters[0] will be destroyed + # (because module.simple_bucket.module.encryption_key[0] is not in configuration) + + # module.simple_bucket.module.encryption_key[0].google_kms_key_ring.key_ring will be destroyed + # (because module.simple_bucket.module.encryption_key[0] is not in configuration) + +Plan: 0 to add, 1 to change, 4 to destroy. +``` + +To preserve the existing KMS Key, add the following section to your configuration + +```diff ++ internal_encryption_config = { ++ create_encryption_key = true ++ } +``` + +Re-running the plan should show that the Simple Bucket resource is no longer showing a diff. + +``` +No changes. Your infrastructure matches the configuration. + +Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. +``` diff --git a/examples/simple_bucket/main.tf b/examples/simple_bucket/main.tf index 711965e5..384357a9 100644 --- a/examples/simple_bucket/main.tf +++ b/examples/simple_bucket/main.tf @@ -16,7 +16,7 @@ module "bucket" { source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" - version = "~> 6.0" + version = "~> 7.0" name = "${var.project_id}-bucket" project_id = var.project_id @@ -42,6 +42,5 @@ module "bucket" { member = "group:test-gcp-ops@test.blueprints.joonix.net" }] - autoclass = true - encryption = { default_kms_key_name = null } + autoclass = true } diff --git a/modules/simple_bucket/README.md b/modules/simple_bucket/README.md index 57b734c2..298ffc74 100644 --- a/modules/simple_bucket/README.md +++ b/modules/simple_bucket/README.md @@ -42,12 +42,13 @@ Functional examples are included in the | bucket\_policy\_only | Enables Bucket Policy Only access to a bucket. | `bool` | `true` | no | | cors | Configuration of CORS for bucket with structure as defined in https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#cors. | `any` | `[]` | no | | custom\_placement\_config | Configuration of the bucket's custom location in a dual-region bucket setup. If the bucket is designated a single or multi-region, the variable are null. |
object({
data_locations = list(string)
})
| `null` | no | -| encryption | A Cloud KMS key that will be used to encrypt objects inserted into this bucket. If default\_kms\_key\_name is set to 'null' a new keyring and key pair will be created and used to encrypt bucket using CMEK. |
object({
default_kms_key_name = string
})
| `null` | no | +| encryption | A Cloud KMS key that will be used to encrypt objects inserted into this bucket. To use a Cloud KMS key automatically created by the module use `internal_encryption_config`. |
object({
default_kms_key_name = string
})
| `null` | no | | force\_destroy | When deleting a bucket, this boolean option will delete all contained objects. If false, Terraform will fail to delete buckets which contain objects. | `bool` | `false` | no | | iam\_members | The list of IAM members to grant permissions on the bucket. |
list(object({
role = string
member = string
}))
| `[]` | no | +| internal\_encryption\_config | Configuration for the creation of an internal Google Cloud Key Management Service (KMS) Key for use as Customer-managed encryption key (CMEK) for the GCS Bucket
instead of creating one in advance and providing the key in the variable `encryption.default_kms_key_name`.
create\_encryption\_key: If `true` a Google Cloud Key Management Service (KMS) KeyRing and a Key will be created
prevent\_destroy: Set the prevent\_destroy lifecycle attribute on keys.
key\_destroy\_scheduled\_duration: Set the period of time that versions of keys spend in the `DESTROY_SCHEDULED` state before transitioning to `DESTROYED`.
key\_rotation\_period: Generate a new key every time this period passes. |
object({
create_encryption_key = optional(bool, false)
prevent_destroy = optional(bool, false)
key_destroy_scheduled_duration = optional(string, null)
key_rotation_period = optional(string, "7776000s")
})
| `{}` | no | | labels | A set of key/value label pairs to assign to the bucket. | `map(string)` | `null` | no | | lifecycle\_rules | The bucket's Lifecycle Rules configuration. |
list(object({
# Object with keys:
# - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.
# - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.
action = any

# Object with keys:
# - age - (Optional) Minimum age of an object in days to satisfy this condition.
# - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.
# - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".
# - matches_storage_class - (Optional) Storage Class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.
# - matches_prefix - (Optional) One or more matching name prefixes to satisfy this condition.
# - matches_suffix - (Optional) One or more matching name suffixes to satisfy this condition
# - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.
condition = any
}))
| `[]` | no | -| location | The location of the bucket. | `string` | n/a | yes | +| location | The location of the bucket. See https://cloud.google.com/storage/docs/locations. | `string` | n/a | yes | | log\_bucket | The bucket that will receive log objects. | `string` | `null` | no | | log\_object\_prefix | The object prefix for log objects. If it's not provided, by default GCS sets this to this bucket's name | `string` | `null` | no | | name | The name of the bucket. | `string` | n/a | yes | @@ -64,6 +65,7 @@ Functional examples are included in the | Name | Description | |------|-------------| | bucket | The created storage bucket | +| internal\_kms\_configuration | The intenal KMS Resource. | | name | Bucket name. | | url | Bucket URL. | diff --git a/modules/simple_bucket/main.tf b/modules/simple_bucket/main.tf index 3cf64d0b..1498231e 100644 --- a/modules/simple_bucket/main.tf +++ b/modules/simple_bucket/main.tf @@ -14,6 +14,11 @@ * limitations under the License. */ +locals { + internal_encryption = var.internal_encryption_config.create_encryption_key ? { default_kms_key_name = module.encryption_key[0].keys[var.name] } : null + encryption = var.internal_encryption_config.create_encryption_key ? local.internal_encryption : var.encryption +} + resource "google_storage_bucket" "bucket" { name = var.name project = var.project_id @@ -41,9 +46,9 @@ resource "google_storage_bucket" "bucket" { } dynamic "encryption" { - for_each = var.encryption == null ? [] : [var.encryption] + for_each = local.encryption == null ? [] : [local.encryption] content { - default_kms_key_name = var.encryption.default_kms_key_name != null ? var.encryption.default_kms_key_name : module.encryption_key[0].keys[var.name] + default_kms_key_name = local.encryption.default_kms_key_name } } @@ -126,16 +131,19 @@ data "google_storage_project_service_account" "gcs_account" { } module "encryption_key" { - count = var.encryption == null ? 0 : (var.encryption.default_kms_key_name == null ? 1 : 0) - source = "terraform-google-modules/kms/google" - version = "~> 3.0" - project_id = var.project_id - location = var.location - keyring = var.name - prevent_destroy = false - keys = [var.name] - set_decrypters_for = [var.name] - set_encrypters_for = [var.name] - decrypters = ["serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}"] - encrypters = ["serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}"] + source = "terraform-google-modules/kms/google" + version = "~> 3.0" + count = var.internal_encryption_config.create_encryption_key ? 1 : 0 + + project_id = var.project_id + location = lower(var.location) + keyring = var.name + prevent_destroy = var.internal_encryption_config.prevent_destroy + key_destroy_scheduled_duration = var.internal_encryption_config.key_destroy_scheduled_duration + key_rotation_period = var.internal_encryption_config.key_rotation_period + keys = [var.name] + set_decrypters_for = [var.name] + set_encrypters_for = [var.name] + decrypters = ["serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}"] + encrypters = ["serviceAccount:${data.google_storage_project_service_account.gcs_account.email_address}"] } diff --git a/modules/simple_bucket/outputs.tf b/modules/simple_bucket/outputs.tf index 6a9f5483..aa0bd4c3 100644 --- a/modules/simple_bucket/outputs.tf +++ b/modules/simple_bucket/outputs.tf @@ -28,3 +28,8 @@ output "url" { description = "Bucket URL." value = google_storage_bucket.bucket.url } + +output "internal_kms_configuration" { + description = "The intenal KMS Resource." + value = var.internal_encryption_config.create_encryption_key ? module.encryption_key[0] : null +} diff --git a/modules/simple_bucket/variables.tf b/modules/simple_bucket/variables.tf index 0c8f9fa4..58fdf10e 100644 --- a/modules/simple_bucket/variables.tf +++ b/modules/simple_bucket/variables.tf @@ -25,7 +25,7 @@ variable "project_id" { } variable "location" { - description = "The location of the bucket." + description = "The location of the bucket. See https://cloud.google.com/storage/docs/locations." type = string } @@ -99,7 +99,7 @@ variable "cors" { } variable "encryption" { - description = "A Cloud KMS key that will be used to encrypt objects inserted into this bucket. If default_kms_key_name is set to 'null' a new keyring and key pair will be created and used to encrypt bucket using CMEK." + description = "A Cloud KMS key that will be used to encrypt objects inserted into this bucket. To use a Cloud KMS key automatically created by the module use `internal_encryption_config`." type = object({ default_kms_key_name = string }) @@ -158,3 +158,21 @@ variable "soft_delete_policy" { }) default = {} } + +variable "internal_encryption_config" { + description = <