Skip to content

Commit

Permalink
Added a new datasource secret_manager_secret_version_access (GoogleCl…
Browse files Browse the repository at this point in the history
  • Loading branch information
mitj04 authored Jan 30, 2023
1 parent 62c9b73 commit 70e71b1
Show file tree
Hide file tree
Showing 4 changed files with 284 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions mmv1/third_party/terraform/utils/provider.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
@@ -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}}`

0 comments on commit 70e71b1

Please sign in to comment.