From 4f11ef8fc0bdaa064f3221f0964bf86fca89d614 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 09:00:10 +0200 Subject: [PATCH 1/6] refactor(data_source_kv_secret_v2): Patch request context through to the `Read()` functions. --- vault/data_source_kv_secret_v2.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vault/data_source_kv_secret_v2.go b/vault/data_source_kv_secret_v2.go index 8a5645572c..503a9a4aad 100644 --- a/vault/data_source_kv_secret_v2.go +++ b/vault/data_source_kv_secret_v2.go @@ -91,7 +91,7 @@ func kvSecretV2DataSource() *schema.Resource { } } -func kvSecretV2DataSourceRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { return diag.FromErr(e) @@ -113,10 +113,10 @@ func kvSecretV2DataSourceRead(_ context.Context, d *schema.ResourceData, meta in data := map[string][]string{ "version": {strconv.Itoa(v.(int))}, } - secret, err = client.Logical().ReadWithData(path, data) + secret, err = client.Logical().ReadWithDataWithContext(ctx, path, data) log.Printf("[DEBUG] Reading secret at %q (version %d) from Vault", path, v) } else { - secret, err = client.Logical().Read(path) + secret, err = client.Logical().ReadWithContext(ctx, path) log.Printf("[DEBUG] Reading secret at %q (latest version) from Vault", path) } From 273c1028b352733b249801a67408657a3c599dba Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 09:03:17 +0200 Subject: [PATCH 2/6] refactor(data_source_kv_secret_v2): Replace `interface{}` with `any`. --- vault/data_source_kv_secret_v2.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vault/data_source_kv_secret_v2.go b/vault/data_source_kv_secret_v2.go index 503a9a4aad..452b82640a 100644 --- a/vault/data_source_kv_secret_v2.go +++ b/vault/data_source_kv_secret_v2.go @@ -91,7 +91,7 @@ func kvSecretV2DataSource() *schema.Resource { } } -func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { return diag.FromErr(e) @@ -138,14 +138,14 @@ func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta return diag.FromErr(err) } - if v, ok := data.(map[string]interface{}); ok { + if v, ok := data.(map[string]any); ok { if err := d.Set(consts.FieldData, serializeDataMapToString(v)); err != nil { return diag.FromErr(err) } } if v, ok := secret.Data["metadata"]; ok { - metadata := v.(map[string]interface{}) + metadata := v.(map[string]any) if v, ok := metadata["created_time"]; ok { if err := d.Set("created_time", v); err != nil { @@ -172,7 +172,7 @@ func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta } if customMetadata, ok := metadata["custom_metadata"]; ok && customMetadata != nil { - if v, ok := customMetadata.(map[string]interface{}); ok { + if v, ok := customMetadata.(map[string]any); ok { if err := d.Set("custom_metadata", serializeDataMapToString(v)); err != nil { return diag.FromErr(err) } From a05ad058e1eb2c3f4eaf3bf89aaa22c05471bf7d Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 09:26:20 +0200 Subject: [PATCH 3/6] feat(data_source_kv_secret_v2_metadata): Add data source for reading secret metadata. This is primarily useful for accessing a secret's version in a non-ephemeral way, without also loading the secret itself. The non-ephemeral version can then be used as a write-only version argument, controlling upgrade behavior without storing the secret in the state. Issue: https://github.com/hashicorp/terraform-provider-vault/issues/2537 --- vault/data_source_kv_secret_v2.go | 203 ++++++++++++--------- vault/data_source_kv_secret_v2_metadata.go | 20 ++ vault/provider.go | 4 + 3 files changed, 141 insertions(+), 86 deletions(-) create mode 100644 vault/data_source_kv_secret_v2_metadata.go diff --git a/vault/data_source_kv_secret_v2.go b/vault/data_source_kv_secret_v2.go index 452b82640a..33dd61c9de 100644 --- a/vault/data_source_kv_secret_v2.go +++ b/vault/data_source_kv_secret_v2.go @@ -7,6 +7,7 @@ import ( "context" "encoding/json" "log" + "maps" "strconv" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -17,81 +18,107 @@ import ( "github.com/hashicorp/terraform-provider-vault/internal/provider" ) +var kvSecretV2DataSourceMetadataFields = map[string]*schema.Schema{ + consts.FieldMount: { + Type: schema.TypeString, + Required: true, + Description: "Path where KV-V2 engine is mounted", + }, + + consts.FieldName: { + Type: schema.TypeString, + Required: true, + Description: "Full name of the secret. For a nested secret, " + + "the name is the nested path excluding the mount and data " + + "prefix. For example, for a secret at 'kvv2/data/foo/bar/baz', " + + "the name is 'foo/bar/baz'", + }, + + consts.FieldVersion: { + Type: schema.TypeInt, + Optional: true, + Description: "Version of the secret to retrieve", + }, + + consts.FieldPath: { + Type: schema.TypeString, + Computed: true, + Description: "Full path where the KVV2 secret is written.", + }, + + "created_time": { + Type: schema.TypeString, + Computed: true, + Description: "Time at which the secret was created", + }, + + "custom_metadata": { + Type: schema.TypeMap, + Computed: true, + Description: "Custom metadata for the secret", + }, + + "deletion_time": { + Type: schema.TypeString, + Computed: true, + Description: "Deletion time for the secret", + }, + + "destroyed": { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the secret has been destroyed", + }, +} + +var kvSecretV2DataSourceDataFields = map[string]*schema.Schema{ + consts.FieldDataJSON: { + Type: schema.TypeString, + Computed: true, + Description: "JSON-encoded secret data read from Vault.", + Sensitive: true, + }, + + consts.FieldData: { + Type: schema.TypeMap, + Computed: true, + Description: "Map of strings read from Vault.", + Sensitive: true, + }, +} + func kvSecretV2DataSource() *schema.Resource { return &schema.Resource{ - ReadContext: provider.ReadContextWrapper(kvSecretV2DataSourceRead), + ReadContext: provider.ReadContextWrapper(func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + const includeData = true + + return kvSecretV2DataSourceRead(ctx, d, meta, includeData) + }), DeprecationMessage: "Deprecated. Please use new Ephemeral KVV2 Secret resource `vault_kv_secret_v2` instead", - Schema: map[string]*schema.Schema{ - consts.FieldMount: { - Type: schema.TypeString, - Required: true, - Description: "Path where KV-V2 engine is mounted", - }, - - consts.FieldName: { - Type: schema.TypeString, - Required: true, - Description: "Full name of the secret. For a nested secret, " + - "the name is the nested path excluding the mount and data " + - "prefix. For example, for a secret at 'kvv2/data/foo/bar/baz', " + - "the name is 'foo/bar/baz'", - }, - - consts.FieldVersion: { - Type: schema.TypeInt, - Optional: true, - Description: "Version of the secret to retrieve", - }, - - consts.FieldPath: { - Type: schema.TypeString, - Computed: true, - Description: "Full path where the KVV2 secret is written.", - }, - - consts.FieldDataJSON: { - Type: schema.TypeString, - Computed: true, - Description: "JSON-encoded secret data read from Vault.", - Sensitive: true, - }, - - consts.FieldData: { - Type: schema.TypeMap, - Computed: true, - Description: "Map of strings read from Vault.", - Sensitive: true, - }, - - "created_time": { - Type: schema.TypeString, - Computed: true, - Description: "Time at which the secret was created", - }, - - "custom_metadata": { - Type: schema.TypeMap, - Computed: true, - Description: "Custom metadata for the secret", - }, - - "deletion_time": { - Type: schema.TypeString, - Computed: true, - Description: "Deletion time for the secret", - }, - - "destroyed": { - Type: schema.TypeBool, - Computed: true, - Description: "Indicates whether the secret has been destroyed", - }, - }, + Schema: mergeSchemaFields( + kvSecretV2DataSourceMetadataFields, + kvSecretV2DataSourceDataFields, + ), } } -func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { +func mergeSchemaFields(ms ...map[string]*schema.Schema) map[string]*schema.Schema { + var size int + for _, m := range ms { + size += len(m) + } + + out := make(map[string]*schema.Schema, size) + + for _, m := range ms { + maps.Copy(out, m) + } + + return out +} + +func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta any, includeData bool) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { return diag.FromErr(e) @@ -103,6 +130,8 @@ func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta // prefix for v2 secrets is "data" path := getKVV2Path(mount, name, consts.FieldData) + d.SetId(path) + if err := d.Set(consts.FieldPath, path); err != nil { return diag.FromErr(err) } @@ -127,23 +156,6 @@ func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta return diag.Errorf("no secret found at %q", path) } - data := secret.Data["data"] - - jsonData, err := json.Marshal(data) - if err != nil { - return diag.Errorf("error marshaling JSON for %q: %s", path, err) - } - - if err := d.Set(consts.FieldDataJSON, string(jsonData)); err != nil { - return diag.FromErr(err) - } - - if v, ok := data.(map[string]any); ok { - if err := d.Set(consts.FieldData, serializeDataMapToString(v)); err != nil { - return diag.FromErr(err) - } - } - if v, ok := secret.Data["metadata"]; ok { metadata := v.(map[string]any) @@ -180,7 +192,26 @@ func kvSecretV2DataSourceRead(ctx context.Context, d *schema.ResourceData, meta } } - d.SetId(path) + if !includeData { + return nil + } + + data := secret.Data["data"] + + jsonData, err := json.Marshal(data) + if err != nil { + return diag.Errorf("error marshaling JSON for %q: %s", path, err) + } + + if err := d.Set(consts.FieldDataJSON, string(jsonData)); err != nil { + return diag.FromErr(err) + } + + if v, ok := data.(map[string]any); ok { + if err := d.Set(consts.FieldData, serializeDataMapToString(v)); err != nil { + return diag.FromErr(err) + } + } return nil } diff --git a/vault/data_source_kv_secret_v2_metadata.go b/vault/data_source_kv_secret_v2_metadata.go new file mode 100644 index 0000000000..8ba5b3e642 --- /dev/null +++ b/vault/data_source_kv_secret_v2_metadata.go @@ -0,0 +1,20 @@ +package vault + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-vault/internal/provider" +) + +func kvSecretV2MetadataDataSource() *schema.Resource { + return &schema.Resource{ + ReadContext: provider.ReadContextWrapper(func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + const includeData = false + + return kvSecretV2DataSourceRead(ctx, d, meta, includeData) + }), + Schema: kvSecretV2DataSourceMetadataFields, + } +} diff --git a/vault/provider.go b/vault/provider.go index 364f8b4cf2..df3db043bd 100644 --- a/vault/provider.go +++ b/vault/provider.go @@ -151,6 +151,10 @@ var ( Resource: UpdateSchemaResource(kvSecretV2DataSource()), PathInventory: []string{"/secret/data/{path}/?version={version}}"}, }, + "vault_kv_secret_v2_metadata": { + Resource: UpdateSchemaResource(kvSecretV2MetadataDataSource()), + PathInventory: []string{"/secret/data/{path}/?version={version}}"}, + }, "vault_kv_secrets_list": { Resource: UpdateSchemaResource(kvSecretListDataSource()), PathInventory: []string{"/secret/{path}/?list=true"}, From 9109b0bdfdeafff739ec8495768d5d82e691021d Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 11:16:37 +0200 Subject: [PATCH 4/6] test(data_source_kv_secret_v2_metadata): Add unit test. --- .../data_source_kv_secret_v2_metadata_test.go | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 vault/data_source_kv_secret_v2_metadata_test.go diff --git a/vault/data_source_kv_secret_v2_metadata_test.go b/vault/data_source_kv_secret_v2_metadata_test.go new file mode 100644 index 0000000000..2a2e877069 --- /dev/null +++ b/vault/data_source_kv_secret_v2_metadata_test.go @@ -0,0 +1,167 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package vault + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/vault/api" + + "github.com/hashicorp/terraform-provider-vault/internal/consts" + "github.com/hashicorp/terraform-provider-vault/internal/provider" + "github.com/hashicorp/terraform-provider-vault/testutil" +) + +func TestDataSourceKVV2SecretMetadata(t *testing.T) { + t.Parallel() + mount := acctest.RandomWithPrefix("tf-kv") + name := acctest.RandomWithPrefix("foo") + + resourceName := "data.vault_kv_secret_v2_metadata.test" + resource.Test(t, resource.TestCase{ + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t), + PreCheck: func() { testutil.TestAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testDataSourceKVV2SecretMetadataConfig(mount, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, consts.FieldMount, mount), + resource.TestCheckResourceAttr(resourceName, consts.FieldName, name), + resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/data/%s", mount, name)), + resource.TestCheckResourceAttr(resourceName, "destroyed", "false"), + ), + }, + { + Config: testDataSourceKVV2SecretMetadataWithVersionConfig(mount, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, consts.FieldMount, mount), + resource.TestCheckResourceAttr(resourceName, consts.FieldName, name), + resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/data/%s", mount, name)), + resource.TestCheckResourceAttr(resourceName, "destroyed", "false"), + ), + }, + }, + }) +} + +func TestDataSourceKVV2SecretMetadata_deletedSecret(t *testing.T) { + mount := acctest.RandomWithPrefix("tf-kv") + name := acctest.RandomWithPrefix("foo") + + config := fmt.Sprintf(` +data "vault_kv_secret_v2_metadata" "test" { + mount = "%s" + name = "%s" +} +`, mount, name) + + resource.Test(t, resource.TestCase{ + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(context.Background(), t), + PreCheck: func() { testutil.TestAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + PreConfig: func() { + client := testProvider.Meta().(*provider.ProviderMeta).MustGetClient() + + err := client.Sys().Mount(mount, &api.MountInput{ + Type: "kv-v2", + Description: "Mount for testing KV datasource", + }) + if err != nil { + t.Fatalf("error mounting kvv2 engine; err=%s", err) + } + + m := map[string]interface{}{ + "foo": "bar", + "baz": "qux", + } + + data := map[string]interface{}{ + consts.FieldData: m, + } + + // Write data at path + path := fmt.Sprintf("%s/data/%s", mount, name) + resp, err := client.Logical().Write(path, data) + if err != nil { + t.Fatalf("error writing to Vault; err=%s", err) + } + + if resp == nil { + t.Fatalf("empty response") + } + + // Soft Delete KV V2 secret at path + // Secret data returned from Vault is nil + // confirm that plan does not result in panic + _, err = client.Logical().Delete(path) + if err != nil { + t.Fatal(err) + } + }, + Config: config, + PlanOnly: true, + }, + }, + }) +} + +func testDataSourceKVV2SecretMetadataConfig(mount, name string) string { + return fmt.Sprintf(` +%s + +resource "vault_kv_secret_v2" "test" { + mount = vault_mount.kvv2.path + name = "%s" + cas = 1 + delete_all_versions = true + data_json = jsonencode( + { + zip = "zap", + foo = "bar", + test = false + baz = { + riff = "raff" + } + } + ) +} + +data "vault_kv_secret_v2_metadata" "test" { + mount = vault_mount.kvv2.path + name = vault_kv_secret_v2.test.name +}`, kvV2MountConfig(mount), name) +} + +func testDataSourceKVV2SecretMetadataWithVersionConfig(mount, name string) string { + return fmt.Sprintf(` +%s + +resource "vault_kv_secret_v2" "test" { + mount = vault_mount.kvv2.path + name = "%s" + cas = 1 + delete_all_versions = true + data_json = jsonencode( + { + zip = "zap", + foo = "bar", + test = false + baz = { + riff = "raff" + } + } + ) +} + +data "vault_kv_secret_v2_metadata" "test" { + mount = vault_mount.kvv2.path + name = vault_kv_secret_v2.test.name + version = 1 +}`, kvV2MountConfig(mount), name) +} From a3e0d8e407ac504fab2d30543bd9f85339026ed3 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 10:15:06 +0200 Subject: [PATCH 5/6] docs(data_source_kv_secret_v2_metadata): Add documentation for the new data source. --- website/docs/d/kv_secret_v2_metadata.html.md | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 website/docs/d/kv_secret_v2_metadata.html.md diff --git a/website/docs/d/kv_secret_v2_metadata.html.md b/website/docs/d/kv_secret_v2_metadata.html.md new file mode 100644 index 0000000000..8a474bf2ed --- /dev/null +++ b/website/docs/d/kv_secret_v2_metadata.html.md @@ -0,0 +1,82 @@ +--- +layout: "vault" +page_title: "Vault: vault_kv_secret_v2_metadata data source" +sidebar_current: "docs-vault-datasource-kv-secret-v2-metadata" +description: |- + Reads a KV-V2 secret's metadata from a given path in Vault +--- + +# vault\_kv\_secret\_v2\_metadata + +Reads a KV-V2 secret's metadata from a given path in Vault without exposing the secret content. + +This data source is primarily intended to be used with the `vault_kv_secret_v2` ephemeral data source. +It provides non-ephemeral access to the secret's version number and other metadata without loading the sensitive secret content into the state file. +The non-ephemeral version can then be used to [control updates of write-only arguments](https://developer.hashicorp.com/terraform/language/resources/ephemeral/write-only#update-write-only-arguments-with-versions). + + +## Example Usage + +```hcl +data "vault_kv_secret_v2_metadata" "example" { + mount = "mount" + name = "secret" +} + +# Load explicit version to avoid drift between the stateful version and the ephemeral secret data. +ephemeral "vault_kv_secret_v2" "example" { + mount = data.vault_kv_secret_v2_metadata.example.mount + name = data.vault_kv_secret_v2_metadata.example.name + version = data.vault_kv_secret_v2_metadata.example.version +} + +# Use the ephemeral secret data and stateful version to control updates of write-only arguments. +resource "vault_database_secret_backend_connection" "postgres" { + postgresql { + username = ephemeral.vault_kv_secret_v2.example.data.username + password_wo = ephemeral.vault_kv_secret_v2.example.data.password + + # Use non-ephemeral version from metadata data source to trigger updates when needed + password_wo_version = data.vault_kv_secret_v2_metadata.example.version + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `namespace` - (Optional) The namespace of the target resource. + The value should not contain leading or trailing forward slashes. + The `namespace` is always relative to the provider's configured [namespace](/docs/providers/vault/index.html#namespace). + *Available only for Vault Enterprise*. + +* `mount` - (Required) Path where KV-V2 engine is mounted. + +* `name` - (Required) Full name of the secret. For a nested secret + the name is the nested path excluding the mount and data + prefix. For example, for a secret at `kvv2/data/foo/bar/baz` + the name is `foo/bar/baz`. + +* `version` - (Optional) Specific version of the secret metadata to retrieve. + If not specified, the latest version's metadata is returned. + +## Required Vault Capabilities + +Use of this resource requires the `read` capability on the given path. + +## Attributes Reference + +The following attributes are exported: + +* `path` - (string) Full path where the KVV2 secret is written. + +* `created_time` - (string) Time at which secret was created. + +* `custom_metadata` - (map of strings) Custom metadata for the secret. + +* `deletion_time` - (string) Deletion time for the secret. + +* `destroyed` - (bool) Indicates whether the secret has been destroyed. + +* `version` - (int) Version of the secret. From 7e8e9b885a2bad6ca1f6ac797a12d6fe035df4cd Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 31 Jul 2025 10:34:28 +0200 Subject: [PATCH 6/6] docs(ephemeral-resources): Update `vault_kv_secret_v2` usage example. --- .../ephemeral-resources/kv_secret_v2.html.md | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/website/docs/ephemeral-resources/kv_secret_v2.html.md b/website/docs/ephemeral-resources/kv_secret_v2.html.md index 9b0160dcab..e1440bdf26 100644 --- a/website/docs/ephemeral-resources/kv_secret_v2.html.md +++ b/website/docs/ephemeral-resources/kv_secret_v2.html.md @@ -16,39 +16,50 @@ refer to [the Vault documentation](https://www.vaultproject.io/docs/secrets/kv/k ```hcl resource "vault_mount" "kvv2" { - path = "my-kvv2" - type = "kv" - options = { version = "2" } + path = "my-kvv2" + type = "kv" + options = { version = "2" } } resource "vault_kv_secret_v2" "db_root" { - mount = vault_mount.kvv2.path - name = "pgx-root" - data_json_wo = jsonencode( + mount = vault_mount.kvv2.path + name = "pgx-root" + data_json_wo = jsonencode( { - password = "root-user-password" + password = "root-user-password" } ) data_json_wo_version = 1 } +# +# Read the database root password and manage a backend connection +# +data "vault_kv_secret_v2_metadata" "db_secret" { + mount = vault_mount.kvv2.path + name = vault_kv_secret_v2.db_root.name +} + +# Load explicit version to avoid drift between the stateful version and the ephemeral secret data. ephemeral "vault_kv_secret_v2" "db_secret" { - mount = vault_mount.kvv2.path + mount = vault_mount.kvv2.path mount_id = vault_mount.kvv2.id - name = vault_kv_secret_v2.db_root.name + name = data.vault_kv_secret_v2_metadata.db_secret.name + version = data.vault_kv_secret_v2_metadata.db_secret.version } +# Use the ephemeral secret data and stateful version to control updates of write-only arguments. resource "vault_database_secret_backend_connection" "postgres" { - backend = vault_mount.db.path - name = "postrgres-db" + backend = "db-mount" + name = "postgres-db" allowed_roles = ["*"] postgresql { - connection_url = "postgresql://{{username}}:{{password}}@localhost:5432/postgres" + connection_url = "postgresql://{{username}}:{{password}}@localhost:5432/postgres" password_authentication = "" - username = "postgres" - password_wo = tostring(ephemeral.vault_kv_secret_v2.db_secret.data.password) - password_wo_version = 1 + username = "postgres" + password_wo = ephemeral.vault_kv_secret_v2.db_secret.data.password + password_wo_version = data.vault_kv_secret_v2_metadata.db_secret.version } } ``` @@ -88,5 +99,3 @@ The following attributes are exported in addition to the arguments listed above: * `deletion_time` - Deletion time for the secret. * `destroyed` - Indicates whether the secret has been destroyed. - -* `custom_metadata` - Custom metadata for the secret. \ No newline at end of file