Skip to content

Commit

Permalink
fix!: fix count invalid argument on simple bucket (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-cit authored Oct 16, 2024
1 parent 81e870a commit 8fe9a7e
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 21 deletions.
78 changes: 78 additions & 0 deletions docs/upgrading_to_v8.0.md
Original file line number Diff line number Diff line change
@@ -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.
```
5 changes: 2 additions & 3 deletions examples/simple_bucket/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -42,6 +42,5 @@ module "bucket" {
member = "group:[email protected]"
}]

autoclass = true
encryption = { default_kms_key_name = null }
autoclass = true
}
6 changes: 4 additions & 2 deletions modules/simple_bucket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. | <pre>object({<br> data_locations = list(string)<br> })</pre> | `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. | <pre>object({<br> default_kms_key_name = string<br> })</pre> | `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`. | <pre>object({<br> default_kms_key_name = string<br> })</pre> | `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. | <pre>list(object({<br> role = string<br> member = string<br> }))</pre> | `[]` | 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<br> instead of creating one in advance and providing the key in the variable `encryption.default_kms_key_name`.<br> create\_encryption\_key: If `true` a Google Cloud Key Management Service (KMS) KeyRing and a Key will be created<br> prevent\_destroy: Set the prevent\_destroy lifecycle attribute on keys.<br> key\_destroy\_scheduled\_duration: Set the period of time that versions of keys spend in the `DESTROY_SCHEDULED` state before transitioning to `DESTROYED`.<br> key\_rotation\_period: Generate a new key every time this period passes. | <pre>object({<br> create_encryption_key = optional(bool, false)<br> prevent_destroy = optional(bool, false)<br> key_destroy_scheduled_duration = optional(string, null)<br> key_rotation_period = optional(string, "7776000s")<br> })</pre> | `{}` | 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. | <pre>list(object({<br> # Object with keys:<br> # - type - The type of the action of this Lifecycle Rule. Supported values: Delete and SetStorageClass.<br> # - storage_class - (Required if action type is SetStorageClass) The target Storage Class of objects affected by this Lifecycle Rule.<br> action = any<br><br> # Object with keys:<br> # - age - (Optional) Minimum age of an object in days to satisfy this condition.<br> # - created_before - (Optional) Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.<br> # - with_state - (Optional) Match to live and/or archived objects. Supported values include: "LIVE", "ARCHIVED", "ANY".<br> # - matches_storage_class - (Optional) Storage Class of objects to satisfy this condition. Supported values include: MULTI_REGIONAL, REGIONAL, NEARLINE, COLDLINE, STANDARD, DURABLE_REDUCED_AVAILABILITY.<br> # - matches_prefix - (Optional) One or more matching name prefixes to satisfy this condition.<br> # - matches_suffix - (Optional) One or more matching name suffixes to satisfy this condition<br> # - num_newer_versions - (Optional) Relevant only for versioned objects. The number of newer versions of an object to satisfy this condition.<br> condition = any<br> }))</pre> | `[]` | 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 |
Expand All @@ -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. |

Expand Down
36 changes: 22 additions & 14 deletions modules/simple_bucket/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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}"]
}
5 changes: 5 additions & 0 deletions modules/simple_bucket/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
22 changes: 20 additions & 2 deletions modules/simple_bucket/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
})
Expand Down Expand Up @@ -158,3 +158,21 @@ variable "soft_delete_policy" {
})
default = {}
}

variable "internal_encryption_config" {
description = <<EOT
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.
EOT
type = 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")
})
default = {}
}

0 comments on commit 8fe9a7e

Please sign in to comment.