Skip to content

Commit 784dfd9

Browse files
secretmanager: ephemeral support for google_secret_manager_secret_version (#14700) (#10821)
[upstream:7ebc2a1884c0a2e3f7d02b5312db9625d8a3d248] Signed-off-by: Modular Magician <[email protected]>
1 parent 4174290 commit 784dfd9

File tree

5 files changed

+428
-2
lines changed

5 files changed

+428
-2
lines changed

.changelog/14700.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
secretmanager: ephemeral support for `google_secret_manager_secret_version`
3+
```

google-beta/fwprovider/framework_provider.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ import (
3737
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwmodels"
3838
"github.com/hashicorp/terraform-provider-google-beta/google-beta/fwvalidators"
3939
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/apigee"
40-
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/resourcemanager"
41-
4240
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/firebase"
41+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/resourcemanager"
42+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/secretmanager"
4343
"github.com/hashicorp/terraform-provider-google-beta/google-beta/services/storage"
4444
"github.com/hashicorp/terraform-provider-google-beta/version"
4545

@@ -1344,5 +1344,6 @@ func (p *FrameworkProvider) EphemeralResources(_ context.Context) []func() ephem
13441344
resourcemanager.GoogleEphemeralServiceAccountIdToken,
13451345
resourcemanager.GoogleEphemeralServiceAccountJwt,
13461346
resourcemanager.GoogleEphemeralServiceAccountKey,
1347+
secretmanager.GoogleEphemeralSecretManagerSecretVersion,
13471348
}
13481349
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
// ----------------------------------------------------------------------------
4+
//
5+
// *** AUTO GENERATED CODE *** Type: Handwritten ***
6+
//
7+
// ----------------------------------------------------------------------------
8+
//
9+
// This code is generated by Magic Modules using the following:
10+
//
11+
// Source file: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/secretmanager/ephemeral_google_secret_manager_secret_version.go
12+
//
13+
// DO NOT EDIT this file directly. Any changes made to this file will be
14+
// overwritten during the next generation cycle.
15+
//
16+
// ----------------------------------------------------------------------------
17+
package secretmanager
18+
19+
import (
20+
"context"
21+
"encoding/base64"
22+
"fmt"
23+
24+
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
25+
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
26+
"github.com/hashicorp/terraform-plugin-framework/types"
27+
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
28+
)
29+
30+
var _ ephemeral.EphemeralResource = &googleEphemeralSecretManagerSecretVersion{}
31+
32+
func GoogleEphemeralSecretManagerSecretVersion() ephemeral.EphemeralResource {
33+
return &googleEphemeralSecretManagerSecretVersion{}
34+
}
35+
36+
type googleEphemeralSecretManagerSecretVersion struct {
37+
providerConfig *transport_tpg.Config
38+
}
39+
40+
func (p *googleEphemeralSecretManagerSecretVersion) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
41+
resp.TypeName = req.ProviderTypeName + "_secret_manager_secret_version"
42+
}
43+
44+
type ephemeralSecretManagerSecretVersionModel struct {
45+
Project types.String `tfsdk:"project"`
46+
Secret types.String `tfsdk:"secret"`
47+
Version types.String `tfsdk:"version"`
48+
IsSecretDataBase64 types.Bool `tfsdk:"is_secret_data_base64"`
49+
SecretData types.String `tfsdk:"secret_data"`
50+
Name types.String `tfsdk:"name"`
51+
CreateTime types.String `tfsdk:"create_time"`
52+
DestroyTime types.String `tfsdk:"destroy_time"`
53+
Enabled types.Bool `tfsdk:"enabled"`
54+
}
55+
56+
func (p *googleEphemeralSecretManagerSecretVersion) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
57+
resp.Schema.Description = "This ephemeral resource provides access to a Google Secret Manager secret version."
58+
resp.Schema.MarkdownDescription = "This ephemeral resource provides access to a Google Secret Manager secret version."
59+
60+
resp.Schema = schema.Schema{
61+
Attributes: map[string]schema.Attribute{
62+
// Arguments
63+
"project": schema.StringAttribute{
64+
Description: "The project to get the secret version for. If it is not provided, the provider project is used.",
65+
Optional: true,
66+
Computed: true,
67+
},
68+
"secret": schema.StringAttribute{
69+
Description: "The secret to get the secret version for.",
70+
Required: true,
71+
},
72+
"version": schema.StringAttribute{
73+
Description: "The version of the secret to get. If it is not provided, the latest version is retrieved.",
74+
Optional: true,
75+
},
76+
"is_secret_data_base64": schema.BoolAttribute{
77+
Description: "If true, the secret data returned will not get base64 decoded. Defaults to false.",
78+
Optional: true,
79+
},
80+
// Attributes
81+
"secret_data": schema.StringAttribute{
82+
Description: "The secret data. No larger than 64KiB.",
83+
Computed: true,
84+
Sensitive: true,
85+
},
86+
"name": schema.StringAttribute{
87+
Description: "The resource name of the SecretVersion. Format: `projects/{{project}}/secrets/{{secret_id}}/versions/{{version}}`.",
88+
Computed: true,
89+
},
90+
"create_time": schema.StringAttribute{
91+
Description: "The time at which the Secret was created.",
92+
Computed: true,
93+
},
94+
"destroy_time": schema.StringAttribute{
95+
Description: "The time at which the Secret was destroyed. Only present if state is DESTROYED.",
96+
Computed: true,
97+
},
98+
"enabled": schema.BoolAttribute{
99+
Description: "True if the current state of the SecretVersion is enabled.",
100+
Computed: true,
101+
},
102+
},
103+
}
104+
}
105+
106+
func (p *googleEphemeralSecretManagerSecretVersion) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
107+
// Prevent panic if the provider has not been configured.
108+
if req.ProviderData == nil {
109+
return
110+
}
111+
112+
pd, ok := req.ProviderData.(*transport_tpg.Config)
113+
if !ok {
114+
resp.Diagnostics.AddError(
115+
"Unexpected Data Source Configure Type",
116+
fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
117+
)
118+
return
119+
}
120+
121+
// Required for accessing userAgent and passing as an argument into a util function
122+
p.providerConfig = pd
123+
}
124+
125+
func (p *googleEphemeralSecretManagerSecretVersion) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
126+
var data ephemeralSecretManagerSecretVersionModel
127+
128+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
129+
if resp.Diagnostics.HasError() {
130+
return
131+
}
132+
133+
config := p.providerConfig
134+
userAgent := p.providerConfig.UserAgent
135+
136+
secret := data.Secret.ValueString()
137+
project := data.Project.ValueString()
138+
version := data.Version.ValueString()
139+
140+
if project == "" {
141+
project = config.Project
142+
}
143+
144+
var url string
145+
if version != "" {
146+
url = fmt.Sprintf("%s%s/versions/%s", config.SecretManagerBasePath, secret, version)
147+
} else {
148+
url = fmt.Sprintf("%s%s/versions/latest", config.SecretManagerBasePath, secret)
149+
}
150+
151+
versionResp, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
152+
Config: config,
153+
Method: "GET",
154+
Project: project,
155+
RawURL: url,
156+
UserAgent: userAgent,
157+
})
158+
if err != nil {
159+
resp.Diagnostics.AddError("Error retrieving secret version", err.Error())
160+
return
161+
}
162+
163+
accessURL := fmt.Sprintf("%s%s:access", config.SecretManagerBasePath, versionResp["name"])
164+
accessResp, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
165+
Config: config,
166+
Method: "GET",
167+
Project: project,
168+
RawURL: accessURL,
169+
UserAgent: userAgent,
170+
})
171+
if err != nil {
172+
resp.Diagnostics.AddError("Error accessing secret data", err.Error())
173+
return
174+
}
175+
176+
// This check seems counterintuitive, but read docs on the `google_secret_manager_secret_version` resource.
177+
// It states: "If set to 'true', the secret data is expected to be base64-encoded string and would be sent as is."
178+
payload := accessResp["payload"].(map[string]interface{})
179+
payloadData := payload["data"].(string)
180+
if !data.IsSecretDataBase64.ValueBool() {
181+
decoded, err := base64.StdEncoding.DecodeString(payload["data"].(string))
182+
if err != nil {
183+
resp.Diagnostics.AddError("Error decoding secret data", err.Error())
184+
return
185+
}
186+
payloadData = string(decoded)
187+
}
188+
189+
data.SecretData = types.StringValue(payloadData)
190+
data.Name = types.StringValue(versionResp["name"].(string))
191+
data.CreateTime = types.StringValue(versionResp["createTime"].(string))
192+
data.Project = types.StringValue(project)
193+
data.Enabled = types.BoolValue(true)
194+
195+
if destroyTime, ok := versionResp["destroyTime"]; ok {
196+
data.DestroyTime = types.StringValue(destroyTime.(string))
197+
}
198+
199+
resp.Diagnostics.Append(resp.Result.Set(ctx, data)...)
200+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
// ----------------------------------------------------------------------------
4+
//
5+
// *** AUTO GENERATED CODE *** Type: Handwritten ***
6+
//
7+
// ----------------------------------------------------------------------------
8+
//
9+
// This code is generated by Magic Modules using the following:
10+
//
11+
// Source file: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/secretmanager/ephemeral_google_secret_manager_secret_version_test.go
12+
//
13+
// DO NOT EDIT this file directly. Any changes made to this file will be
14+
// overwritten during the next generation cycle.
15+
//
16+
// ----------------------------------------------------------------------------
17+
package secretmanager_test
18+
19+
import (
20+
"encoding/base64"
21+
"fmt"
22+
"testing"
23+
24+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
25+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest"
26+
)
27+
28+
func TestAccEphemeralSecretManagerSecretVersion_basic(t *testing.T) {
29+
t.Parallel()
30+
acctest.SkipIfVcr(t)
31+
32+
secret := "tf-test-secret-" + acctest.RandString(t, 10)
33+
secretData := "secret-data"
34+
35+
resource.Test(t, resource.TestCase{
36+
PreCheck: func() { acctest.AccTestPreCheck(t) },
37+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
38+
Steps: []resource.TestStep{
39+
{
40+
Config: testAccEphemeralSecretManagerSecretVersion_basic(secret, secretData),
41+
Check: resource.ComposeTestCheckFunc(
42+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "secret_data", secretData),
43+
),
44+
},
45+
},
46+
})
47+
}
48+
49+
func TestAccEphemeralSecretManagerSecretVersion_base64(t *testing.T) {
50+
t.Parallel()
51+
acctest.SkipIfVcr(t)
52+
53+
secret := "tf-test-secret-" + acctest.RandString(t, 10)
54+
secretData := "secret-data"
55+
56+
resource.Test(t, resource.TestCase{
57+
PreCheck: func() { acctest.AccTestPreCheck(t) },
58+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
59+
Steps: []resource.TestStep{
60+
{
61+
Config: testAccEphemeralSecretManagerSecretVersion_base64(secret, secretData),
62+
Check: resource.ComposeTestCheckFunc(
63+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "is_secret_data_base64", "true"),
64+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "secret_data", base64.StdEncoding.EncodeToString([]byte(secretData))),
65+
),
66+
},
67+
},
68+
})
69+
}
70+
71+
func testAccEphemeralSecretManagerSecretVersion_basic(secret, secretData string) string {
72+
return fmt.Sprintf(`
73+
resource "google_secret_manager_secret" "secret" {
74+
secret_id = "%s"
75+
76+
replication {
77+
auto {}
78+
}
79+
}
80+
81+
resource "google_secret_manager_secret_version" "version" {
82+
secret = google_secret_manager_secret.secret.id
83+
secret_data = "%s"
84+
}
85+
86+
ephemeral "google_secret_manager_secret_version" "ephemeral" {
87+
secret = google_secret_manager_secret_version.version.secret
88+
version = google_secret_manager_secret_version.version.version
89+
}
90+
91+
resource "google_secret_manager_secret_version" "version_two_based_on_ephemeral" {
92+
secret = google_secret_manager_secret_version.version.secret
93+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
94+
secret_data_wo_version = "1"
95+
}
96+
97+
data "google_secret_manager_secret_version" "default" {
98+
secret = google_secret_manager_secret_version.version_two_based_on_ephemeral.secret
99+
version = google_secret_manager_secret_version.version_two_based_on_ephemeral.version
100+
}
101+
`, secret, secretData)
102+
}
103+
104+
func testAccEphemeralSecretManagerSecretVersion_base64(secret, secretData string) string {
105+
return fmt.Sprintf(`
106+
resource "google_secret_manager_secret" "secret" {
107+
secret_id = "%s"
108+
109+
replication {
110+
auto {}
111+
}
112+
}
113+
114+
resource "google_secret_manager_secret_version" "version" {
115+
secret = google_secret_manager_secret.secret.id
116+
secret_data = base64encode("%s")
117+
is_secret_data_base64 = true
118+
}
119+
120+
ephemeral "google_secret_manager_secret_version" "ephemeral" {
121+
secret = google_secret_manager_secret_version.version.secret
122+
version = google_secret_manager_secret_version.version.version
123+
is_secret_data_base64 = true
124+
}
125+
126+
resource "google_secret_manager_secret_version" "version_two_based_on_ephemeral" {
127+
secret = google_secret_manager_secret_version.version.secret
128+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
129+
secret_data_wo_version = "1"
130+
is_secret_data_base64 = true
131+
}
132+
133+
data "google_secret_manager_secret_version" "default" {
134+
secret = google_secret_manager_secret_version.version_two_based_on_ephemeral.secret
135+
version = google_secret_manager_secret_version.version_two_based_on_ephemeral.version
136+
is_secret_data_base64 = true
137+
}
138+
`, secret, secretData)
139+
}

0 commit comments

Comments
 (0)