Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a new datasource google_secret_manager_secret_version_access #13605

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/7060.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-datasource
`google_secret_manager_secret_version_access`
```
116 changes: 116 additions & 0 deletions google/data_source_secret_manager_secret_version_access.go
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
}
127 changes: 127 additions & 0 deletions google/data_source_secret_manager_secret_version_access_test.go
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 google/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ func Provider() *schema.Provider {
"google_pubsub_topic": dataSourceGooglePubsubTopic(),
"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}}`