diff --git a/modules/gcs/README.md b/modules/gcs/README.md index 7200f950..d94a40db 100644 --- a/modules/gcs/README.md +++ b/modules/gcs/README.md @@ -1,6 +1,19 @@ # Google Cloud Storage Module -## Example + +- [Simple bucket example](#simple-bucket-example) +- [Cloud KMS](#cloud-kms) +- [Retention policy, soft delete policy and logging](#retention-policy-soft-delete-policy-and-logging) +- [Lifecycle rule](#lifecycle-rule) +- [GCS notifications](#gcs-notifications) +- [Object upload](#object-upload) +- [IAM](#iam) +- [Tags](#tags) +- [Variables](#variables) +- [Outputs](#outputs) + + +## Simple bucket example ```hcl module "bucket" { @@ -16,7 +29,7 @@ module "bucket" { # tftest modules=1 resources=1 inventory=simple.yaml e2e ``` -### Example with Cloud KMS +## Cloud KMS ```hcl module "project" { @@ -56,7 +69,7 @@ module "bucket" { # tftest modules=3 skip e2e ``` -### Example with retention policy, soft delete policy and logging +## Retention policy, soft delete policy and logging ```hcl module "bucket" { @@ -77,7 +90,7 @@ module "bucket" { # tftest modules=1 resources=1 inventory=retention-logging.yaml ``` -### Example with lifecycle rule +## Lifecycle rule ```hcl module "bucket" { @@ -100,7 +113,7 @@ module "bucket" { # tftest modules=1 resources=1 inventory=lifecycle.yaml e2e ``` -### Minimal example with GCS notifications +## GCS notifications ```hcl module "project" { @@ -126,7 +139,7 @@ module "bucket-gcs-notification" { # tftest skip e2e ``` -### Example with object upload +## Object upload ```hcl module "bucket" { @@ -145,7 +158,17 @@ module "bucket" { # tftest modules=1 resources=2 inventory=object-upload.yaml e2e ``` -### Examples of IAM +## IAM + +IAM is managed via several variables that implement different features and levels of control: + +- `iam` and `iam_by_principals` configure authoritative bindings that manage individual roles exclusively, and are internally merged +- `iam_bindings` configure authoritative bindings with optional support for conditions, and are not internally merged with the previous two variables +- `iam_bindings_additive` configure additive bindings via individual role/member pairs with optional support conditions + +The authoritative and additive approaches can be used together, provided different roles are managed by each. Some care must also be taken with the `iam_by_principals` variable to ensure that variable keys are static values, so that Terraform is able to compute the dependency graph. + +Refer to the [project module](../project/README.md#iam) for examples of the IAM interface. ```hcl module "bucket" { @@ -215,6 +238,38 @@ module "bucket" { } # tftest modules=1 resources=2 inventory=iam-bindings-additive.yaml e2e ``` + +## Tags + +Refer to the [Creating and managing tags](https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing) documentation for details on usage. + +```hcl +module "org" { + source = "./fabric/modules/organization" + organization_id = var.organization_id + tags = { + environment = { + description = "Environment specification." + values = { + dev = {} + prod = {} + sandbox = {} + } + } + } +} + +module "bucket" { + source = "./fabric/modules/gcs" + project_id = var.project_id + prefix = var.prefix + name = "my-bucket" + tag_bindings = { + env-sandbox = module.org.tag_values["environment/sandbox"].id + } +} +# tftest modules=2 resources=6 +``` ## Variables @@ -243,9 +298,10 @@ module "bucket" { | [retention_policy](variables.tf#L236) | Bucket retention policy. | object({…}) | | null | | [soft_delete_retention](variables.tf#L245) | The duration in seconds that soft-deleted objects in the bucket will be retained and cannot be permanently deleted. Set to 0 to override the default and disable. | number | | null | | [storage_class](variables.tf#L251) | Bucket storage class. | string | | "MULTI_REGIONAL" | -| [uniform_bucket_level_access](variables.tf#L261) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | -| [versioning](variables.tf#L267) | Enable versioning, defaults to false. | bool | | false | -| [website](variables.tf#L273) | Bucket website. | object({…}) | | null | +| [tag_bindings](variables.tf#L261) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | +| [uniform_bucket_level_access](variables.tf#L267) | Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API). | bool | | true | +| [versioning](variables.tf#L273) | Enable versioning, defaults to false. | bool | | false | +| [website](variables.tf#L279) | Bucket website. | object({…}) | | null | ## Outputs diff --git a/modules/gcs/tags.tf b/modules/gcs/tags.tf new file mode 100644 index 00000000..b666d2f3 --- /dev/null +++ b/modules/gcs/tags.tf @@ -0,0 +1,26 @@ +/** + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +resource "google_tags_location_tag_binding" "binding" { + for_each = coalesce(var.tag_bindings, {}) + parent = "//storage.googleapis.com/projects/_/buckets/${local.prefix}${lower(var.name)}" + tag_value = each.value + location = var.location + depends_on = [ + google_storage_bucket.bucket, + google_storage_bucket_iam_binding.bindings + ] +} diff --git a/modules/gcs/variables.tf b/modules/gcs/variables.tf index 0dbb937d..993a855f 100644 --- a/modules/gcs/variables.tf +++ b/modules/gcs/variables.tf @@ -258,6 +258,12 @@ variable "storage_class" { } } +variable "tag_bindings" { + description = "Tag bindings for this folder, in key => tag value id format." + type = map(string) + default = null +} + variable "uniform_bucket_level_access" { description = "Allow using object ACLs (false) or not (true, this is the recommended behavior) , defaults to true (which is the recommended practice, but not the behavior of storage API)." type = bool diff --git a/tests/modules/gcs/examples/tags.yaml b/tests/modules/gcs/examples/tags.yaml new file mode 100644 index 00000000..bf5123fd --- /dev/null +++ b/tests/modules/gcs/examples/tags.yaml @@ -0,0 +1,69 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.bucket.google_storage_bucket.bucket: + autoclass: + - enabled: false + cors: [] + custom_placement_config: [] + default_event_based_hold: null + enable_object_retention: null + encryption: [] + force_destroy: false + labels: null + lifecycle_rule: [] + location: EU + logging: [] + name: test-my-bucket + project: project-id + requester_pays: null + retention_policy: [] + storage_class: MULTI_REGIONAL + timeouts: null + uniform_bucket_level_access: true + versioning: + - enabled: false + module.bucket.google_tags_tag_binding.binding["env-sandbox"]: + parent: //storage.googleapis.com/projects/_/buckets/test-my-bucket + timeouts: null + module.org.google_tags_tag_key.default["environment"]: + description: Environment specification. + parent: organizations/1122334455 + purpose: null + purpose_data: null + short_name: environment + timeouts: null + module.org.google_tags_tag_value.default["environment/dev"]: + description: Managed by the Terraform organization module. + short_name: dev + timeouts: null + module.org.google_tags_tag_value.default["environment/prod"]: + description: Managed by the Terraform organization module. + short_name: prod + timeouts: null + module.org.google_tags_tag_value.default["environment/sandbox"]: + description: Managed by the Terraform organization module. + short_name: sandbox + timeouts: null + +counts: + google_storage_bucket: 1 + google_tags_tag_binding: 1 + google_tags_tag_key: 1 + google_tags_tag_value: 3 + modules: 2 + resources: 6 + +outputs: {}