From 5efd84849f347188a2400568b493ca3277aeca9d Mon Sep 17 00:00:00 2001 From: The Magician Date: Fri, 30 Apr 2021 12:36:14 -0700 Subject: [PATCH] add secret manager cmek (#4752) (#3212) Co-authored-by: Sarath Kaul Co-authored-by: Cameron Thornton Co-authored-by: Sarath Kaul Signed-off-by: Modular Magician Co-authored-by: Sarath Kaul --- .changelog/4752.txt | 3 + ...esource_dataflow_flex_template_job_test.go | 2 +- google-beta/resource_secret_manager_secret.go | 65 +++++++++++++++++- .../resource_secret_manager_secret_test.go | 66 +++++++++++++++++++ .../r/secret_manager_secret.html.markdown | 12 ++++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 .changelog/4752.txt diff --git a/.changelog/4752.txt b/.changelog/4752.txt new file mode 100644 index 0000000000..1a79cb96c7 --- /dev/null +++ b/.changelog/4752.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +secretmanager: added support for setting a CMEK on `google_secret_manager_secret` +``` diff --git a/google-beta/resource_dataflow_flex_template_job_test.go b/google-beta/resource_dataflow_flex_template_job_test.go index 0d037482e0..df04d28bb0 100644 --- a/google-beta/resource_dataflow_flex_template_job_test.go +++ b/google-beta/resource_dataflow_flex_template_job_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" - compute "google.golang.org/api/compute/v1" + "google.golang.org/api/compute/v1" ) func TestAccDataflowFlexTemplateJob_basic(t *testing.T) { diff --git a/google-beta/resource_secret_manager_secret.go b/google-beta/resource_secret_manager_secret.go index 98f09a7a28..3d37e29e52 100644 --- a/google-beta/resource_secret_manager_secret.go +++ b/google-beta/resource_secret_manager_secret.go @@ -76,6 +76,21 @@ after the Secret has been created.`, Required: true, Description: `The canonical IDs of the location to replicate data. For example: "us-east1".`, }, + "customer_managed_encryption": { + Type: schema.TypeList, + Optional: true, + Description: `Customer Managed Encryption for the secret.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "kms_key_name": { + Type: schema.TypeString, + Required: true, + Description: `Describes the Cloud KMS encryption key that will be used to protect destination secret.`, + }, + }, + }, + }, }, }, }, @@ -412,7 +427,8 @@ func flattenSecretManagerSecretReplicationUserManagedReplicas(v interface{}, d * continue } transformed = append(transformed, map[string]interface{}{ - "location": flattenSecretManagerSecretReplicationUserManagedReplicasLocation(original["location"], d, config), + "location": flattenSecretManagerSecretReplicationUserManagedReplicasLocation(original["location"], d, config), + "customer_managed_encryption": flattenSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryption(original["customerManagedEncryption"], d, config), }) } return transformed @@ -421,6 +437,23 @@ func flattenSecretManagerSecretReplicationUserManagedReplicasLocation(v interfac return v } +func flattenSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryption(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["kms_key_name"] = + flattenSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryptionKmsKeyName(original["kmsKeyName"], d, config) + return []interface{}{transformed} +} +func flattenSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryptionKmsKeyName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandSecretManagerSecretLabels(v interface{}, d TerraformResourceData, config *Config) (map[string]string, error) { if v == nil { return map[string]string{}, nil @@ -502,6 +535,13 @@ func expandSecretManagerSecretReplicationUserManagedReplicas(v interface{}, d Te transformed["location"] = transformedLocation } + transformedCustomerManagedEncryption, err := expandSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryption(original["customer_managed_encryption"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCustomerManagedEncryption); val.IsValid() && !isEmptyValue(val) { + transformed["customerManagedEncryption"] = transformedCustomerManagedEncryption + } + req = append(req, transformed) } return req, nil @@ -510,3 +550,26 @@ func expandSecretManagerSecretReplicationUserManagedReplicas(v interface{}, d Te func expandSecretManagerSecretReplicationUserManagedReplicasLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } + +func expandSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryption(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedKmsKeyName, err := expandSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryptionKmsKeyName(original["kms_key_name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKmsKeyName); val.IsValid() && !isEmptyValue(val) { + transformed["kmsKeyName"] = transformedKmsKeyName + } + + return transformed, nil +} + +func expandSecretManagerSecretReplicationUserManagedReplicasCustomerManagedEncryptionKmsKeyName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} diff --git a/google-beta/resource_secret_manager_secret_test.go b/google-beta/resource_secret_manager_secret_test.go index fcfdb635ca..f62f50dfa9 100644 --- a/google-beta/resource_secret_manager_secret_test.go +++ b/google-beta/resource_secret_manager_secret_test.go @@ -30,6 +30,34 @@ func TestAccSecretManagerSecret_import(t *testing.T) { }) } +func TestAccSecretManagerSecret_cmek(t *testing.T) { + t.Parallel() + + kmscentral := BootstrapKMSKeyInLocation(t, "us-central1") + kmseast := BootstrapKMSKeyInLocation(t, "us-east1") + context1 := map[string]interface{}{ + "pid": getTestProjectFromEnv(), + "random_suffix": randString(t, 10), + "kms_key_name_central": kmscentral.CryptoKey.Name, + "kms_key_name_east": kmseast.CryptoKey.Name, + } + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSecretManagerSecretDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccSecretMangerSecret_cmek(context1), + }, + { + ResourceName: "google_secret_manager_secret.secret-basic", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccSecretManagerSecret_basic(context map[string]interface{}) string { return Nprintf(` resource "google_secret_manager_secret" "secret-basic" { @@ -52,3 +80,41 @@ resource "google_secret_manager_secret" "secret-basic" { } `, context) } + +func testAccSecretMangerSecret_cmek(context map[string]interface{}) string { + return Nprintf(` +data "google_project" "project" { + project_id = "%{pid}" +} +resource "google_project_iam_member" "kms-secret-binding" { + project = data.google_project.project.project_id + role = "roles/cloudkms.cryptoKeyEncrypterDecrypter" + member = "serviceAccount:service-${data.google_project.project.number}@gcp-sa-secretmanager.iam.gserviceaccount.com" +} +resource "google_secret_manager_secret" "secret-basic" { + secret_id = "tf-test-secret-%{random_suffix}" + + labels = { + label = "my-label" + } + replication { + user_managed { + replicas { + location = "us-central1" + customer_managed_encryption { + kms_key_name = "%{kms_key_name_central}" + } + } + replicas { + location = "us-east1" + customer_managed_encryption { + kms_key_name = "%{kms_key_name_east}" + } + } + + } + } + project = google_project_iam_member.kms-secret-binding.project +} +`, context) +} diff --git a/website/docs/r/secret_manager_secret.html.markdown b/website/docs/r/secret_manager_secret.html.markdown index 33ab2ec7ea..e157e4da4c 100644 --- a/website/docs/r/secret_manager_secret.html.markdown +++ b/website/docs/r/secret_manager_secret.html.markdown @@ -100,6 +100,18 @@ The `replicas` block supports: (Required) The canonical IDs of the location to replicate data. For example: "us-east1". +* `customer_managed_encryption` - + (Optional) + Customer Managed Encryption for the secret. + Structure is documented below. + + +The `customer_managed_encryption` block supports: + +* `kms_key_name` - + (Required) + Describes the Cloud KMS encryption key that will be used to protect destination secret. + - - -