From 787da35afeb5c4fa51a73001a2c0de59bb366ba8 Mon Sep 17 00:00:00 2001 From: jinyangtang <147192056+jinyangtang@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:00:27 -0800 Subject: [PATCH] feat: Add CMEK support for Firestore database in Beta provider (#10044) * Modify database.yaml to add cmek related fields * Add two examples for firestore CMEK databases for testing * Resolve trailing space * Update documentation for kmsKeyName field * Resolve trailing space * Make field immutable * Update field documentation * Update field description --- mmv1/products/firestore/Database.yaml | 72 +++++++++++++++++++ .../examples/firestore_cmek_database.tf.erb | 50 +++++++++++++ ...ore_cmek_database_in_datastore_mode.tf.erb | 50 +++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb create mode 100644 mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb diff --git a/mmv1/products/firestore/Database.yaml b/mmv1/products/firestore/Database.yaml index 051872d7bc1a..d294f94c147a 100644 --- a/mmv1/products/firestore/Database.yaml +++ b/mmv1/products/firestore/Database.yaml @@ -78,6 +78,23 @@ examples: - project - etag - deletion_policy + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_cmek_database' + min_version: beta + primary_resource_id: 'database' + vars: + database_id: "cmek-database-id" + delete_protection_state: "DELETE_PROTECTION_ENABLED" + kms_key_ring_name: "kms-key-ring" + kms_key_name: "kms-key" + test_env_vars: + project_id: :PROJECT_NAME + test_vars_overrides: + delete_protection_state: '"DELETE_PROTECTION_DISABLED"' + ignore_read_extra: + - project + - etag + - deletion_policy - !ruby/object:Provider::Terraform::Examples name: 'firestore_default_database_in_datastore_mode' primary_resource_id: 'datastore_mode_database' @@ -102,6 +119,23 @@ examples: - project - etag - deletion_policy + - !ruby/object:Provider::Terraform::Examples + name: 'firestore_cmek_database_in_datastore_mode' + min_version: beta + primary_resource_id: 'database' + vars: + database_id: "cmek-database-id" + delete_protection_state: "DELETE_PROTECTION_ENABLED" + kms_key_ring_name: "kms-key-ring" + kms_key_name: "kms-key" + test_env_vars: + project_id: :PROJECT_NAME + test_vars_overrides: + delete_protection_state: '"DELETE_PROTECTION_DISABLED"' + ignore_read_extra: + - project + - etag + - deletion_policy virtual_fields: - !ruby/object:Api::Type::Enum name: 'deletion_policy' @@ -234,3 +268,41 @@ properties: This value is continuously updated, and becomes stale the moment it is queried. If you are using this value to recover data, make sure to account for the time from the moment when the value is queried to the moment when you initiate the recovery. A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". output: true + - !ruby/object:Api::Type::NestedObject + name: cmekConfig + min_version: beta + immutable: true + description: | + The CMEK (Customer Managed Encryption Key) configuration for a Firestore + database. If not present, the database is secured by the default Google + encryption key. + properties: + - !ruby/object:Api::Type::String + name: kmsKeyName + required: true + immutable: true + description: | + The resource ID of a Cloud KMS key. If set, the database created will + be a Customer-managed Encryption Key (CMEK) database encrypted with + this key. This feature is allowlist only in initial launch. + + Only keys in the same location as this database are allowed to be used + for encryption. For Firestore's nam5 multi-region, this corresponds to Cloud KMS + multi-region us. For Firestore's eur3 multi-region, this corresponds to + Cloud KMS multi-region europe. See https://cloud.google.com/kms/docs/locations. + + This value should be the KMS key resource ID in the format of + `projects/{project_id}/locations/{kms_location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}`. + How to retrive this resource ID is listed at + https://cloud.google.com/kms/docs/getting-resource-ids#getting_the_id_for_a_key_and_version. + - !ruby/object:Api::Type::Array + name: activeKeyVersion + output: true + description: | + Currently in-use KMS key versions (https://cloud.google.com/kms/docs/resource-hierarchy#key_versions). + During key rotation (https://cloud.google.com/kms/docs/key-rotation), there can be + multiple in-use key versions. + + The expected format is + `projects/{project_id}/locations/{kms_location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}/cryptoKeyVersions/{key_version}`. + item_type: Api::Type::String diff --git a/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb b/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb new file mode 100644 index 000000000000..330b16d32eab --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_cmek_database.tf.erb @@ -0,0 +1,50 @@ +data "google_project" "project" { + provider = google-beta +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + name = "<%= ctx[:vars]['database_id']%>" + location_id = "nam5" + type = "FIRESTORE_NATIVE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + point_in_time_recovery_enablement = "POINT_IN_TIME_RECOVERY_ENABLED" + delete_protection_state = "<%= ctx[:vars]['delete_protection_state'] %>" + deletion_policy = "DELETE" + cmek_config { + kms_key_name = google_kms_crypto_key.crypto_key.id + } + + depends_on = [ + google_kms_crypto_key_iam_binding.firestore_cmek_keyuser + ] +} + +resource "google_kms_crypto_key" "crypto_key" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_name'] %>" + key_ring = google_kms_key_ring.key_ring.id + purpose = "ENCRYPT_DECRYPT" +} + +resource "google_kms_key_ring" "key_ring" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_ring_name'] %>" + location = "us" +} + +resource "google_kms_crypto_key_iam_binding" "firestore_cmek_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.crypto_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-firestore.iam.gserviceaccount.com", + ] +} diff --git a/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb b/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb new file mode 100644 index 000000000000..ac2a33a8ce06 --- /dev/null +++ b/mmv1/templates/terraform/examples/firestore_cmek_database_in_datastore_mode.tf.erb @@ -0,0 +1,50 @@ +data "google_project" "project" { + provider = google-beta +} + +resource "google_firestore_database" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + project = "<%= ctx[:test_env_vars]['project_id'] %>" + name = "<%= ctx[:vars]['database_id']%>" + location_id = "nam5" + type = "DATASTORE_MODE" + concurrency_mode = "OPTIMISTIC" + app_engine_integration_mode = "DISABLED" + point_in_time_recovery_enablement = "POINT_IN_TIME_RECOVERY_ENABLED" + delete_protection_state = "<%= ctx[:vars]['delete_protection_state'] %>" + deletion_policy = "DELETE" + cmek_config { + kms_key_name = google_kms_crypto_key.crypto_key.id + } + + depends_on = [ + google_kms_crypto_key_iam_binding.firestore_cmek_keyuser + ] +} + +resource "google_kms_crypto_key" "crypto_key" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_name'] %>" + key_ring = google_kms_key_ring.key_ring.id + purpose = "ENCRYPT_DECRYPT" +} + +resource "google_kms_key_ring" "key_ring" { + provider = google-beta + + name = "<%= ctx[:vars]['kms_key_ring_name'] %>" + location = "us" +} + +resource "google_kms_crypto_key_iam_binding" "firestore_cmek_keyuser" { + provider = google-beta + + crypto_key_id = google_kms_crypto_key.crypto_key.id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + + members = [ + "serviceAccount:service-${data.google_project.project.number}@gcp-sa-firestore.iam.gserviceaccount.com", + ] +}