From 70e71b142415d20b731a135da0b22672dce0b677 Mon Sep 17 00:00:00 2001 From: mitj04 <111354996+mitj04@users.noreply.github.com> Date: Mon, 30 Jan 2023 22:16:00 +0000 Subject: [PATCH] Added a new datasource secret_manager_secret_version_access (#7060) --- ...ce_secret_manager_secret_version_access.go | 116 ++++++++++++++++ ...cret_manager_secret_version_access_test.go | 127 ++++++++++++++++++ .../terraform/utils/provider.go.erb | 1 + ...anager_secret_version_access.html.markdown | 40 ++++++ 4 files changed, 284 insertions(+) create mode 100644 mmv1/third_party/terraform/data_sources/data_source_secret_manager_secret_version_access.go create mode 100644 mmv1/third_party/terraform/tests/data_source_secret_manager_secret_version_access_test.go create mode 100644 mmv1/third_party/terraform/website/docs/d/secret_manager_secret_version_access.html.markdown diff --git a/mmv1/third_party/terraform/data_sources/data_source_secret_manager_secret_version_access.go b/mmv1/third_party/terraform/data_sources/data_source_secret_manager_secret_version_access.go new file mode 100644 index 000000000000..d5e6ed7a181d --- /dev/null +++ b/mmv1/third_party/terraform/data_sources/data_source_secret_manager_secret_version_access.go @@ -0,0 +1,116 @@ +package google + +import ( + "encoding/base64" + "fmt" + "log" + "regexp" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceSecretManagerSecretVersionAccess() *schema.Resource { + return &schema.Resource{ + Read: dataSourceSecretManagerSecretVersionAccessRead, + Schema: map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "secret": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "secret_data": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + } +} + +func dataSourceSecretManagerSecretVersionAccessRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + fv, err := parseProjectFieldValue("secrets", d.Get("secret").(string), "project", d, config, false) + if err != nil { + return err + } + if d.Get("project").(string) != "" && d.Get("project").(string) != fv.Project { + return fmt.Errorf("The project set on this secret version (%s) is not equal to the project where this secret exists (%s).", d.Get("project").(string), fv.Project) + } + project := fv.Project + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("secret", fv.Name); err != nil { + return fmt.Errorf("Error setting secret: %s", err) + } + + var url string + versionNum := d.Get("version") + + if versionNum != "" { + url, err = replaceVars(d, config, "{{SecretManagerBasePath}}projects/{{project}}/secrets/{{secret}}/versions/{{version}}") + if err != nil { + return err + } + } else { + url, err = replaceVars(d, config, "{{SecretManagerBasePath}}projects/{{project}}/secrets/{{secret}}/versions/latest") + if err != nil { + return err + } + } + + url = fmt.Sprintf("%s:access", url) + resp, err := sendRequest(config, "GET", project, url, userAgent, nil) + if err != nil { + return fmt.Errorf("Error retrieving available secret manager secret version access: %s", err.Error()) + } + + if err := d.Set("name", resp["name"].(string)); err != nil { + return fmt.Errorf("Error setting name: %s", err) + } + + secretVersionRegex := regexp.MustCompile("projects/(.+)/secrets/(.+)/versions/(.+)$") + + parts := secretVersionRegex.FindStringSubmatch(resp["name"].(string)) + // should return [full string, project number, secret name, version number] + if len(parts) != 4 { + panic(fmt.Sprintf("secret name, %s, does not match format, projects/{{project}}/secrets/{{secret}}/versions/{{version}}", resp["name"].(string))) + } + + log.Printf("[DEBUG] Received Google SecretManager Version: %q", parts[3]) + + if err := d.Set("version", parts[3]); err != nil { + return fmt.Errorf("Error setting version: %s", err) + } + + data := resp["payload"].(map[string]interface{}) + secretData, err := base64.StdEncoding.DecodeString(data["data"].(string)) + if err != nil { + return fmt.Errorf("Error decoding secret manager secret version data: %s", err.Error()) + } + if err := d.Set("secret_data", string(secretData)); err != nil { + return fmt.Errorf("Error setting secret_data: %s", err) + } + + d.SetId(resp["name"].(string)) + return nil +} diff --git a/mmv1/third_party/terraform/tests/data_source_secret_manager_secret_version_access_test.go b/mmv1/third_party/terraform/tests/data_source_secret_manager_secret_version_access_test.go new file mode 100644 index 000000000000..1484c9355d99 --- /dev/null +++ b/mmv1/third_party/terraform/tests/data_source_secret_manager_secret_version_access_test.go @@ -0,0 +1,127 @@ +package google + +import ( + "errors" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDatasourceSecretManagerSecretVersionAccess_basic(t *testing.T) { + t.Parallel() + + randomString := randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSecretManagerSecretVersionDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDatasourceSecretManagerSecretVersionAccess_basic(randomString), + Check: resource.ComposeTestCheckFunc( + testAccCheckDatasourceSecretManagerSecretVersionAccess("data.google_secret_manager_secret_version_access.basic", "1"), + ), + }, + }, + }) +} + +func TestAccDatasourceSecretManagerSecretVersionAccess_latest(t *testing.T) { + t.Parallel() + + randomString := randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckSecretManagerSecretVersionDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDatasourceSecretManagerSecretVersionAccess_latest(randomString), + Check: resource.ComposeTestCheckFunc( + testAccCheckDatasourceSecretManagerSecretVersionAccess("data.google_secret_manager_secret_version_access.latest", "2"), + ), + }, + }, + }) +} + +func testAccCheckDatasourceSecretManagerSecretVersionAccess(n, expected string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find Secret Version data source: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("data source ID not set.") + } + + version, ok := rs.Primary.Attributes["version"] + if !ok { + return errors.New("can't find 'version' attribute") + } + + if version != expected { + return fmt.Errorf("expected %s, got %s, version not found", expected, version) + } + return nil + } +} + +func testAccDatasourceSecretManagerSecretVersionAccess_latest(randomString string) string { + return fmt.Sprintf(` +resource "google_secret_manager_secret" "secret-basic" { + secret_id = "tf-test-secret-version-%s" + labels = { + label = "my-label" + } + replication { + automatic = true + } +} + +resource "google_secret_manager_secret_version" "secret-version-basic-1" { + secret = google_secret_manager_secret.secret-basic.name + secret_data = "my-tf-test-secret-first" +} + +resource "google_secret_manager_secret_version" "secret-version-basic-2" { + secret = google_secret_manager_secret.secret-basic.name + secret_data = "my-tf-test-secret-second" + + depends_on = [google_secret_manager_secret_version.secret-version-basic-1] +} + +data "google_secret_manager_secret_version_access" "latest" { + secret = google_secret_manager_secret_version.secret-version-basic-2.secret +} +`, randomString) +} + +func testAccDatasourceSecretManagerSecretVersionAccess_basic(randomString string) string { + return fmt.Sprintf(` +resource "google_secret_manager_secret" "secret-basic" { + secret_id = "tf-test-secret-version-%s" + labels = { + label = "my-label" + } + replication { + automatic = true + } +} + +resource "google_secret_manager_secret_version" "secret-version-basic" { + secret = google_secret_manager_secret.secret-basic.name + secret_data = "my-tf-test-secret-%s" +} + +data "google_secret_manager_secret_version_access" "basic" { + secret = google_secret_manager_secret_version.secret-version-basic.secret + version = 1 +} +`, randomString, randomString) +} diff --git a/mmv1/third_party/terraform/utils/provider.go.erb b/mmv1/third_party/terraform/utils/provider.go.erb index cf7604ab33fd..766f9b6730e2 100644 --- a/mmv1/third_party/terraform/utils/provider.go.erb +++ b/mmv1/third_party/terraform/utils/provider.go.erb @@ -311,6 +311,7 @@ func Provider() *schema.Provider { <% end -%> "google_secret_manager_secret": dataSourceSecretManagerSecret(), "google_secret_manager_secret_version": dataSourceSecretManagerSecretVersion(), + "google_secret_manager_secret_version_access": dataSourceSecretManagerSecretVersionAccess(), "google_service_account": dataSourceGoogleServiceAccount(), "google_service_account_access_token": dataSourceGoogleServiceAccountAccessToken(), "google_service_account_id_token": dataSourceGoogleServiceAccountIdToken(), diff --git a/mmv1/third_party/terraform/website/docs/d/secret_manager_secret_version_access.html.markdown b/mmv1/third_party/terraform/website/docs/d/secret_manager_secret_version_access.html.markdown new file mode 100644 index 000000000000..2878536fca0f --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/secret_manager_secret_version_access.html.markdown @@ -0,0 +1,40 @@ +--- +subcategory: "Secret Manager" +page_title: "Google: google_secret_manager_secret_version_access" +description: |- + Get a payload of Secret Manager secret's version. +--- + +# google\_secret\_manager\_secret\_version\_access + +Get a payload of Secret Manager secret's version. It only requires the [Secret Manager Secret Accessor](https://cloud.google.com/secret-manager/docs/access-control#secretmanager.secretAccessor) role. For more information see the [official documentation](https://cloud.google.com/secret-manager/docs/) and [API](https://cloud.google.com/secret-manager/docs/reference/rest/v1/projects.secrets.versions/access). + +## Example Usage + +```hcl +data "google_secret_manager_secret_version_access" "basic" { + secret = "my-secret" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `project` - (Optional) The project to get the secret version for. If it + is not provided, the provider project is used. + +* `secret` - (Required) The secret to get the secret version for. + +* `version` - (Optional) The version of the secret to get. If it + is not provided, the latest version is retrieved. + + +## Attributes Reference + +The following attributes are exported: + +* `secret_data` - The secret data. No larger than 64KiB. + +* `name` - The resource name of the SecretVersion. Format: + `projects/{{project}}/secrets/{{secret_id}}/versions/{{version}}`