From 53ca817ec0e80ebc6244502e063ac97fea8e23c6 Mon Sep 17 00:00:00 2001 From: nikhil Date: Sat, 30 Apr 2022 14:16:02 +0100 Subject: [PATCH 1/2] support for CMEK in cloud functions --- google/resource_cloudfunctions_function.go | 36 +++++++++++++++ .../resource_cloudfunctions_function_test.go | 45 +++++++++++++++++++ .../r/cloudfunctions_function.html.markdown | 4 ++ 3 files changed, 85 insertions(+) diff --git a/google/resource_cloudfunctions_function.go b/google/resource_cloudfunctions_function.go index 319d1575862..7e7ddd80f13 100644 --- a/google/resource_cloudfunctions_function.go +++ b/google/resource_cloudfunctions_function.go @@ -285,6 +285,18 @@ func resourceCloudFunctionsFunction() *schema.Resource { Description: `URL which triggers function execution. Returned only if trigger_http is used.`, }, + "docker_repository": { + Type: schema.TypeString, + Optional: true, + Description: `The user managed Artifact Repository optionally with a customer managed encryption key. If specified, deployments will use Artifact Registry. If unspecified and the deployment is eligible to use Artifact Registry, GCF will create and use a repository named 'gcf-artifacts' for every deployed region.`, + }, + + "kms_key_name": { + Type: schema.TypeString, + Optional: true, + Description: `The Cloud KMS resource name of the customer managed encryption key that’s used to encrypt the contents of the Repository. Has the form: 'projects/my-project/locations/my-region/keyRings/my-kr/cryptoKeys/my-key'. If specified, you must also provide an artifact registry repository using the docker_repository field that was created with the same KMS crypto key.`, + }, + "max_instances": { Type: schema.TypeInt, Optional: true, @@ -498,6 +510,14 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro function.VpcConnectorEgressSettings = v.(string) } + if v, ok := d.GetOk("docker_repository"); ok { + function.KmsKeyName = v.(string) + } + + if v, ok := d.GetOk("kms_key_name"); ok { + function.DockerRepository = v.(string) + } + if v, ok := d.GetOk("max_instances"); ok { function.MaxInstances = int64(v.(int)) } @@ -629,6 +649,12 @@ func resourceCloudFunctionsRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("event_trigger", flattenEventTrigger(function.EventTrigger)); err != nil { return fmt.Errorf("Error setting event_trigger: %s", err) } + if err := d.Set("docker_repository", function.DockerRepository); err != nil { + return fmt.Errorf("Error setting docker_repository: %s", err) + } + if err := d.Set("kms_key_name", function.KmsKeyName); err != nil { + return fmt.Errorf("Error setting kms_key_name: %s", err) + } if err := d.Set("max_instances", function.MaxInstances); err != nil { return fmt.Errorf("Error setting max_instances: %s", err) } @@ -754,6 +780,16 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro updateMaskArr = append(updateMaskArr, "eventTrigger", "eventTrigger.failurePolicy.retry") } + if d.HasChange("kms_key_name") { + function.KmsKeyName = d.Get("kms_key_name").(string) + updateMaskArr = append(updateMaskArr, "kms_key_name") + } + + if d.HasChange("docker_repository") { + function.DockerRepository = d.Get("docker_repository").(string) + updateMaskArr = append(updateMaskArr, "docker_repository") + } + if d.HasChange("max_instances") { function.MaxInstances = int64(d.Get("max_instances").(int)) updateMaskArr = append(updateMaskArr, "maxInstances") diff --git a/google/resource_cloudfunctions_function_test.go b/google/resource_cloudfunctions_function_test.go index 5af360b6b89..7c1ac040e0e 100644 --- a/google/resource_cloudfunctions_function_test.go +++ b/google/resource_cloudfunctions_function_test.go @@ -356,6 +356,31 @@ func TestAccCloudFunctionsFunction_sourceRepo(t *testing.T) { }) } +func TestAccCloudFunctionsFunction_kmsKey(t *testing.T) { + t.Parallel() + + funcResourceName := "google_cloudfunctions_function.function" + functionName := fmt.Sprintf("tf-test-%s", randString(t, 10)) + proj := getTestProjectFromEnv() + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFunctionsFunctionDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudFunctionsFunction_kmsKey(functionName, proj), + }, + { + ResourceName: funcResourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"build_environment_variables"}, + }, + }, + }) +} + func TestAccCloudFunctionsFunction_serviceAccountEmail(t *testing.T) { t.Parallel() @@ -912,6 +937,26 @@ resource "google_cloudfunctions_function" "function" { `, functionName, project) } +func testAccCloudFunctionsFunction_kmsKey(functionName, project string) string { + return fmt.Sprintf(` +resource "google_cloudfunctions_function" "function" { + name = "%s" + runtime = "nodejs10" + + source_repository { + // There isn't yet an API that'll allow us to create a source repository and + // put code in it, so we created this repository outside the test to be used + // here. If this test is run outside of CI, you may need to create your own + // source repo. + url = "https://source.developers.google.com/projects/%s/repos/cloudfunctions-test-do-not-delete/moveable-aliases/master/paths/" + } + + trigger_http = true + entry_point = "helloGET" +} +`, functionName, project) +} + func testAccCloudFunctionsFunction_serviceAccountEmail(functionName, bucketName, zipFilePath string) string { return fmt.Sprintf(` resource "google_storage_bucket" "bucket" { diff --git a/website/docs/r/cloudfunctions_function.html.markdown b/website/docs/r/cloudfunctions_function.html.markdown index 5afb8abd136..212561c41bc 100644 --- a/website/docs/r/cloudfunctions_function.html.markdown +++ b/website/docs/r/cloudfunctions_function.html.markdown @@ -148,6 +148,10 @@ Eg. `"nodejs10"`, `"nodejs12"`, `"nodejs14"`, `"python37"`, `"python38"`, `"pyth * `source_repository` - (Optional) Represents parameters related to source repository where a function is hosted. Cannot be set alongside `source_archive_bucket` or `source_archive_object`. Structure is [documented below](#nested_source_repository). +* `docker_repository` - (Optional) The user managed Artifact Repository optionally with a customer managed encryption key. If specified, deployments will use Artifact Registry. If unspecified and the deployment is eligible to use Artifact Registry, GCF will create and use a repository named 'gcf-artifacts' for every deployed region. + +* `kms_key_name` - (Optional) The Cloud KMS resource name of the customer managed encryption key that’s used to encrypt the contents of the Repository. Has the form: 'projects/my-project/locations/my-region/keyRings/my-kr/cryptoKeys/my-key'. If specified, you must also provide an artifact registry repository using the docker_repository field that was created with the same KMS crypto key. + * `max_instances` - (Optional) The limit on the maximum number of function instances that may coexist at a given time. * `min_instances` - (Optional) The limit on the minimum number of function instances that may coexist at a given time. From 46a1edbaf13baa05e3bfb4fd0e39d79112a335cf Mon Sep 17 00:00:00 2001 From: nikhil Date: Tue, 21 Jun 2022 21:39:13 +0100 Subject: [PATCH 2/2] support for CMEK in cloud functions --- .../resource_cloudfunctions_function_test.go | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/google/resource_cloudfunctions_function_test.go b/google/resource_cloudfunctions_function_test.go index 7c1ac040e0e..5af360b6b89 100644 --- a/google/resource_cloudfunctions_function_test.go +++ b/google/resource_cloudfunctions_function_test.go @@ -356,31 +356,6 @@ func TestAccCloudFunctionsFunction_sourceRepo(t *testing.T) { }) } -func TestAccCloudFunctionsFunction_kmsKey(t *testing.T) { - t.Parallel() - - funcResourceName := "google_cloudfunctions_function.function" - functionName := fmt.Sprintf("tf-test-%s", randString(t, 10)) - proj := getTestProjectFromEnv() - - vcrTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckCloudFunctionsFunctionDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccCloudFunctionsFunction_kmsKey(functionName, proj), - }, - { - ResourceName: funcResourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"build_environment_variables"}, - }, - }, - }) -} - func TestAccCloudFunctionsFunction_serviceAccountEmail(t *testing.T) { t.Parallel() @@ -937,26 +912,6 @@ resource "google_cloudfunctions_function" "function" { `, functionName, project) } -func testAccCloudFunctionsFunction_kmsKey(functionName, project string) string { - return fmt.Sprintf(` -resource "google_cloudfunctions_function" "function" { - name = "%s" - runtime = "nodejs10" - - source_repository { - // There isn't yet an API that'll allow us to create a source repository and - // put code in it, so we created this repository outside the test to be used - // here. If this test is run outside of CI, you may need to create your own - // source repo. - url = "https://source.developers.google.com/projects/%s/repos/cloudfunctions-test-do-not-delete/moveable-aliases/master/paths/" - } - - trigger_http = true - entry_point = "helloGET" -} -`, functionName, project) -} - func testAccCloudFunctionsFunction_serviceAccountEmail(functionName, bucketName, zipFilePath string) string { return fmt.Sprintf(` resource "google_storage_bucket" "bucket" {