Skip to content

Commit 046dc68

Browse files
Added a new datasource secret_manager_secret_version_access (#7060) (#5147)
Signed-off-by: Modular Magician <[email protected]>
1 parent 37f4d0f commit 046dc68

File tree

5 files changed

+287
-0
lines changed

5 files changed

+287
-0
lines changed

.changelog/7060.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-datasource
2+
`google_secret_manager_secret_version_access`
3+
```
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package google
2+
3+
import (
4+
"encoding/base64"
5+
"fmt"
6+
"log"
7+
"regexp"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
func dataSourceSecretManagerSecretVersionAccess() *schema.Resource {
13+
return &schema.Resource{
14+
Read: dataSourceSecretManagerSecretVersionAccessRead,
15+
Schema: map[string]*schema.Schema{
16+
"project": {
17+
Type: schema.TypeString,
18+
Optional: true,
19+
Computed: true,
20+
},
21+
"secret": {
22+
Type: schema.TypeString,
23+
Required: true,
24+
DiffSuppressFunc: compareSelfLinkOrResourceName,
25+
},
26+
"version": {
27+
Type: schema.TypeString,
28+
Optional: true,
29+
Computed: true,
30+
},
31+
"name": {
32+
Type: schema.TypeString,
33+
Computed: true,
34+
},
35+
"secret_data": {
36+
Type: schema.TypeString,
37+
Computed: true,
38+
Sensitive: true,
39+
},
40+
},
41+
}
42+
}
43+
44+
func dataSourceSecretManagerSecretVersionAccessRead(d *schema.ResourceData, meta interface{}) error {
45+
config := meta.(*Config)
46+
userAgent, err := generateUserAgentString(d, config.userAgent)
47+
if err != nil {
48+
return err
49+
}
50+
51+
fv, err := parseProjectFieldValue("secrets", d.Get("secret").(string), "project", d, config, false)
52+
if err != nil {
53+
return err
54+
}
55+
if d.Get("project").(string) != "" && d.Get("project").(string) != fv.Project {
56+
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)
57+
}
58+
project := fv.Project
59+
if err := d.Set("project", project); err != nil {
60+
return fmt.Errorf("Error setting project: %s", err)
61+
}
62+
if err := d.Set("secret", fv.Name); err != nil {
63+
return fmt.Errorf("Error setting secret: %s", err)
64+
}
65+
66+
var url string
67+
versionNum := d.Get("version")
68+
69+
if versionNum != "" {
70+
url, err = replaceVars(d, config, "{{SecretManagerBasePath}}projects/{{project}}/secrets/{{secret}}/versions/{{version}}")
71+
if err != nil {
72+
return err
73+
}
74+
} else {
75+
url, err = replaceVars(d, config, "{{SecretManagerBasePath}}projects/{{project}}/secrets/{{secret}}/versions/latest")
76+
if err != nil {
77+
return err
78+
}
79+
}
80+
81+
url = fmt.Sprintf("%s:access", url)
82+
resp, err := sendRequest(config, "GET", project, url, userAgent, nil)
83+
if err != nil {
84+
return fmt.Errorf("Error retrieving available secret manager secret version access: %s", err.Error())
85+
}
86+
87+
if err := d.Set("name", resp["name"].(string)); err != nil {
88+
return fmt.Errorf("Error setting name: %s", err)
89+
}
90+
91+
secretVersionRegex := regexp.MustCompile("projects/(.+)/secrets/(.+)/versions/(.+)$")
92+
93+
parts := secretVersionRegex.FindStringSubmatch(resp["name"].(string))
94+
// should return [full string, project number, secret name, version number]
95+
if len(parts) != 4 {
96+
panic(fmt.Sprintf("secret name, %s, does not match format, projects/{{project}}/secrets/{{secret}}/versions/{{version}}", resp["name"].(string)))
97+
}
98+
99+
log.Printf("[DEBUG] Received Google SecretManager Version: %q", parts[3])
100+
101+
if err := d.Set("version", parts[3]); err != nil {
102+
return fmt.Errorf("Error setting version: %s", err)
103+
}
104+
105+
data := resp["payload"].(map[string]interface{})
106+
secretData, err := base64.StdEncoding.DecodeString(data["data"].(string))
107+
if err != nil {
108+
return fmt.Errorf("Error decoding secret manager secret version data: %s", err.Error())
109+
}
110+
if err := d.Set("secret_data", string(secretData)); err != nil {
111+
return fmt.Errorf("Error setting secret_data: %s", err)
112+
}
113+
114+
d.SetId(resp["name"].(string))
115+
return nil
116+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package google
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
10+
)
11+
12+
func TestAccDatasourceSecretManagerSecretVersionAccess_basic(t *testing.T) {
13+
t.Parallel()
14+
15+
randomString := randString(t, 10)
16+
17+
vcrTest(t, resource.TestCase{
18+
PreCheck: func() { testAccPreCheck(t) },
19+
Providers: testAccProviders,
20+
CheckDestroy: testAccCheckSecretManagerSecretVersionDestroyProducer(t),
21+
Steps: []resource.TestStep{
22+
{
23+
Config: testAccDatasourceSecretManagerSecretVersionAccess_basic(randomString),
24+
Check: resource.ComposeTestCheckFunc(
25+
testAccCheckDatasourceSecretManagerSecretVersionAccess("data.google_secret_manager_secret_version_access.basic", "1"),
26+
),
27+
},
28+
},
29+
})
30+
}
31+
32+
func TestAccDatasourceSecretManagerSecretVersionAccess_latest(t *testing.T) {
33+
t.Parallel()
34+
35+
randomString := randString(t, 10)
36+
37+
vcrTest(t, resource.TestCase{
38+
PreCheck: func() { testAccPreCheck(t) },
39+
Providers: testAccProviders,
40+
CheckDestroy: testAccCheckSecretManagerSecretVersionDestroyProducer(t),
41+
Steps: []resource.TestStep{
42+
{
43+
Config: testAccDatasourceSecretManagerSecretVersionAccess_latest(randomString),
44+
Check: resource.ComposeTestCheckFunc(
45+
testAccCheckDatasourceSecretManagerSecretVersionAccess("data.google_secret_manager_secret_version_access.latest", "2"),
46+
),
47+
},
48+
},
49+
})
50+
}
51+
52+
func testAccCheckDatasourceSecretManagerSecretVersionAccess(n, expected string) resource.TestCheckFunc {
53+
return func(s *terraform.State) error {
54+
rs, ok := s.RootModule().Resources[n]
55+
if !ok {
56+
return fmt.Errorf("Can't find Secret Version data source: %s", n)
57+
}
58+
59+
if rs.Primary.ID == "" {
60+
return errors.New("data source ID not set.")
61+
}
62+
63+
version, ok := rs.Primary.Attributes["version"]
64+
if !ok {
65+
return errors.New("can't find 'version' attribute")
66+
}
67+
68+
if version != expected {
69+
return fmt.Errorf("expected %s, got %s, version not found", expected, version)
70+
}
71+
return nil
72+
}
73+
}
74+
75+
func testAccDatasourceSecretManagerSecretVersionAccess_latest(randomString string) string {
76+
return fmt.Sprintf(`
77+
resource "google_secret_manager_secret" "secret-basic" {
78+
secret_id = "tf-test-secret-version-%s"
79+
labels = {
80+
label = "my-label"
81+
}
82+
replication {
83+
automatic = true
84+
}
85+
}
86+
87+
resource "google_secret_manager_secret_version" "secret-version-basic-1" {
88+
secret = google_secret_manager_secret.secret-basic.name
89+
secret_data = "my-tf-test-secret-first"
90+
}
91+
92+
resource "google_secret_manager_secret_version" "secret-version-basic-2" {
93+
secret = google_secret_manager_secret.secret-basic.name
94+
secret_data = "my-tf-test-secret-second"
95+
96+
depends_on = [google_secret_manager_secret_version.secret-version-basic-1]
97+
}
98+
99+
data "google_secret_manager_secret_version_access" "latest" {
100+
secret = google_secret_manager_secret_version.secret-version-basic-2.secret
101+
}
102+
`, randomString)
103+
}
104+
105+
func testAccDatasourceSecretManagerSecretVersionAccess_basic(randomString string) string {
106+
return fmt.Sprintf(`
107+
resource "google_secret_manager_secret" "secret-basic" {
108+
secret_id = "tf-test-secret-version-%s"
109+
labels = {
110+
label = "my-label"
111+
}
112+
replication {
113+
automatic = true
114+
}
115+
}
116+
117+
resource "google_secret_manager_secret_version" "secret-version-basic" {
118+
secret = google_secret_manager_secret.secret-basic.name
119+
secret_data = "my-tf-test-secret-%s"
120+
}
121+
122+
data "google_secret_manager_secret_version_access" "basic" {
123+
secret = google_secret_manager_secret_version.secret-version-basic.secret
124+
version = 1
125+
}
126+
`, randomString, randomString)
127+
}

google-beta/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ func Provider() *schema.Provider {
10501050
"google_runtimeconfig_variable": dataSourceGoogleRuntimeconfigVariable(),
10511051
"google_secret_manager_secret": dataSourceSecretManagerSecret(),
10521052
"google_secret_manager_secret_version": dataSourceSecretManagerSecretVersion(),
1053+
"google_secret_manager_secret_version_access": dataSourceSecretManagerSecretVersionAccess(),
10531054
"google_service_account": dataSourceGoogleServiceAccount(),
10541055
"google_service_account_access_token": dataSourceGoogleServiceAccountAccessToken(),
10551056
"google_service_account_id_token": dataSourceGoogleServiceAccountIdToken(),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
subcategory: "Secret Manager"
3+
page_title: "Google: google_secret_manager_secret_version_access"
4+
description: |-
5+
Get a payload of Secret Manager secret's version.
6+
---
7+
8+
# google\_secret\_manager\_secret\_version\_access
9+
10+
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).
11+
12+
## Example Usage
13+
14+
```hcl
15+
data "google_secret_manager_secret_version_access" "basic" {
16+
secret = "my-secret"
17+
}
18+
```
19+
20+
## Argument Reference
21+
22+
The following arguments are supported:
23+
24+
* `project` - (Optional) The project to get the secret version for. If it
25+
is not provided, the provider project is used.
26+
27+
* `secret` - (Required) The secret to get the secret version for.
28+
29+
* `version` - (Optional) The version of the secret to get. If it
30+
is not provided, the latest version is retrieved.
31+
32+
33+
## Attributes Reference
34+
35+
The following attributes are exported:
36+
37+
* `secret_data` - The secret data. No larger than 64KiB.
38+
39+
* `name` - The resource name of the SecretVersion. Format:
40+
`projects/{{project}}/secrets/{{secret_id}}/versions/{{version}}`

0 commit comments

Comments
 (0)