From fdd479ca20bd5f8cbde0ebf951c742b8e2c584cd Mon Sep 17 00:00:00 2001 From: vinay-gopalan <86625824+vinay-gopalan@users.noreply.github.com> Date: Wed, 10 Aug 2022 15:50:13 -0700 Subject: [PATCH 1/2] Fix/add kv data map (#1576) --- vault/data_source_kv_secret.go | 13 ++++++++++++- vault/data_source_kv_secret_test.go | 8 ++++++++ vault/data_source_kv_secret_v2.go | 13 ++++++++++++- vault/data_source_kv_secret_v2_test.go | 4 ++++ vault/data_source_kv_subkeys_v2.go | 10 ++++++++++ vault/data_source_kv_subkeys_v2_test.go | 3 +++ website/docs/d/kv_secret.html.md | 5 ++++- website/docs/d/kv_secret_v2.html.md | 5 ++++- website/docs/d/kv_subkeys_v2.html.md | 4 +++- 9 files changed, 60 insertions(+), 5 deletions(-) diff --git a/vault/data_source_kv_secret.go b/vault/data_source_kv_secret.go index f9195f809..8c41b64ab 100644 --- a/vault/data_source_kv_secret.go +++ b/vault/data_source_kv_secret.go @@ -26,6 +26,12 @@ func kvSecretDataSource() *schema.Resource { 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, }, @@ -70,7 +76,8 @@ func kvSecretDataSourceRead(ctx context.Context, d *schema.ResourceData, meta in return diag.Errorf("no secret found at %q", path) } - jsonData, err := json.Marshal(secret.Data) + data := secret.Data + jsonData, err := json.Marshal(data) if err != nil { return diag.Errorf("error marshaling JSON for %q: %s", path, err) } @@ -79,6 +86,10 @@ func kvSecretDataSourceRead(ctx context.Context, d *schema.ResourceData, meta in return diag.FromErr(err) } + if err := d.Set(consts.FieldData, serializeDataMapToString(data)); err != nil { + return diag.FromErr(err) + } + if err := d.Set(consts.FieldLeaseID, secret.LeaseID); err != nil { return diag.FromErr(err) } diff --git a/vault/data_source_kv_secret_test.go b/vault/data_source_kv_secret_test.go index d4bbc291e..3f658d01e 100644 --- a/vault/data_source_kv_secret_test.go +++ b/vault/data_source_kv_secret_test.go @@ -27,6 +27,10 @@ func TestDataSourceKVSecret(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/%s", mount, name)), resource.TestCheckResourceAttr(resourceName, consts.FieldLeaseRenewable, "false"), + resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), + resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), + resource.TestCheckResourceAttr(resourceName, "data.test", "false"), + resource.TestCheckResourceAttr(resourceName, "data.baz", "{\"riff\":\"raff\"}"), testutil.CheckJSONData(resourceName, consts.FieldDataJSON, expectedSubkeys), ), }, @@ -35,6 +39,10 @@ func TestDataSourceKVSecret(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/%s-updated", mount, name)), resource.TestCheckResourceAttr(resourceName, consts.FieldLeaseRenewable, "false"), + resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), + resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), + resource.TestCheckResourceAttr(resourceName, "data.test", "false"), + resource.TestCheckResourceAttr(resourceName, "data.baz", "{\"riff\":\"raff\"}"), testutil.CheckJSONData(resourceName, consts.FieldDataJSON, expectedSubkeys), ), }, diff --git a/vault/data_source_kv_secret_v2.go b/vault/data_source_kv_secret_v2.go index beb5ec95a..b7dcec9ab 100644 --- a/vault/data_source_kv_secret_v2.go +++ b/vault/data_source_kv_secret_v2.go @@ -48,7 +48,14 @@ func kvSecretV2DataSource() *schema.Resource { consts.FieldDataJSON: { Type: schema.TypeString, Computed: true, - Description: "Map of strings read from Vault", + 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, }, @@ -121,6 +128,10 @@ func kvSecretV2DataSourceRead(_ context.Context, d *schema.ResourceData, meta in return diag.FromErr(err) } + if err := d.Set(consts.FieldData, serializeDataMapToString(data.(map[string]interface{}))); err != nil { + return diag.FromErr(err) + } + if v, ok := secret.Data["metadata"]; ok { metadata := v.(map[string]interface{}) diff --git a/vault/data_source_kv_secret_v2_test.go b/vault/data_source_kv_secret_v2_test.go index 9e135cf0f..202794250 100644 --- a/vault/data_source_kv_secret_v2_test.go +++ b/vault/data_source_kv_secret_v2_test.go @@ -29,6 +29,10 @@ func TestDataSourceKVV2Secret(t *testing.T) { resource.TestCheckResourceAttr(resourceName, consts.FieldName, name), resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/data/%s", mount, name)), resource.TestCheckResourceAttr(resourceName, "destroyed", "false"), + resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), + resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), + resource.TestCheckResourceAttr(resourceName, "data.test", "false"), + resource.TestCheckResourceAttr(resourceName, "data.baz", "{\"riff\":\"raff\"}"), testutil.CheckJSONData(resourceName, consts.FieldDataJSON, expectedSubkeys), ), }, diff --git a/vault/data_source_kv_subkeys_v2.go b/vault/data_source_kv_subkeys_v2.go index 53514d9dc..6f197c95e 100644 --- a/vault/data_source_kv_subkeys_v2.go +++ b/vault/data_source_kv_subkeys_v2.go @@ -59,6 +59,12 @@ func kvSecretSubkeysV2DataSource() *schema.Resource { // cleanly support nested values Description: "Subkeys for the KV-V2 secret read from Vault.", }, + consts.FieldData: { + Type: schema.TypeMap, + Computed: true, + Description: "Subkeys stored as a map of strings.", + Sensitive: true, + }, }, } } @@ -103,6 +109,10 @@ func kvSecretSubkeysDataSourceRead(_ context.Context, d *schema.ResourceData, me if err := d.Set(consts.FieldDataJSON, string(jsonData)); err != nil { return diag.FromErr(err) } + + if err := d.Set(consts.FieldData, serializeDataMapToString(data.(map[string]interface{}))); err != nil { + return diag.FromErr(err) + } } d.SetId(path) diff --git a/vault/data_source_kv_subkeys_v2_test.go b/vault/data_source_kv_subkeys_v2_test.go index 9f5296639..ee2768ff1 100644 --- a/vault/data_source_kv_subkeys_v2_test.go +++ b/vault/data_source_kv_subkeys_v2_test.go @@ -27,6 +27,9 @@ func TestDataSourceKVSubkeys(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/subkeys/%s", mount, secretPath)), resource.TestCheckResourceAttrSet(resourceName, consts.FieldDataJSON), + resource.TestCheckResourceAttr(resourceName, "data.zip", "null"), + resource.TestCheckResourceAttr(resourceName, "data.foo", "null"), + resource.TestCheckResourceAttr(resourceName, "data.baz", "{\"riff\":null}"), testutil.CheckJSONData(resourceName, consts.FieldDataJSON, expectedSubkeys), ), }, diff --git a/website/docs/d/kv_secret.html.md b/website/docs/d/kv_secret.html.md index d99d7ba3a..b2d142733 100644 --- a/website/docs/d/kv_secret.html.md +++ b/website/docs/d/kv_secret.html.md @@ -65,11 +65,14 @@ Use of this resource requires the `read` capability on the given path. The following attributes are exported: -* `data_json` - A mapping whose keys are the top-level data keys returned from +* `data` - A mapping whose keys are the top-level data keys returned from Vault and whose values are the corresponding values. This map can only represent string data, so any non-string values returned from Vault are serialized as JSON. +* `data_json` - String containing a JSON-encoded object that that is + read as the secret data at the given path. + * `lease_id` - The lease identifier assigned by Vault, if any. * `lease_duration` - The duration of the secret lease, in seconds. Once diff --git a/website/docs/d/kv_secret_v2.html.md b/website/docs/d/kv_secret_v2.html.md index e13849cc3..f0d6efb1e 100644 --- a/website/docs/d/kv_secret_v2.html.md +++ b/website/docs/d/kv_secret_v2.html.md @@ -78,11 +78,14 @@ The following attributes are exported: * `path` - Full path where the KVV2 secret is written. -* `data_json` - A mapping whose keys are the top-level data keys returned from +* `data` - A mapping whose keys are the top-level data keys returned from Vault and whose values are the corresponding values. This map can only represent string data, so any non-string values returned from Vault are serialized as JSON. +* `data_json` - String containing a JSON-encoded object that that is + read as the secret data at the given path. + * `created_time` - Time at which secret was created. * `custom_metadata` - Custom metadata for the secret. diff --git a/website/docs/d/kv_subkeys_v2.html.md b/website/docs/d/kv_subkeys_v2.html.md index 91744fe24..7d6768cf8 100644 --- a/website/docs/d/kv_subkeys_v2.html.md +++ b/website/docs/d/kv_subkeys_v2.html.md @@ -83,4 +83,6 @@ The following attributes are exported: * `path` - Full path where the KV-V2 secrets are listed. -* `data_json` - Subkeys for the KV-V2 secret read from Vault.. +* `data_json` - Subkeys for the KV-V2 secret read from Vault. + +* `data` - Subkeys for the KV-V2 secret stored as a serialized map of strings. From 3a8a779094a67fc1b9cb34ce382ebbfd3459a727 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Thu, 11 Aug 2022 10:15:01 -0700 Subject: [PATCH 2/2] update tests responding to feedback --- vault/data_source_kv_secret.go | 5 ++--- vault/data_source_kv_secret_test.go | 2 ++ vault/data_source_kv_secret_v2_test.go | 1 + vault/data_source_kv_subkeys_v2_test.go | 1 + website/docs/d/kv_secret.html.md | 2 +- website/docs/d/kv_secret_v2.html.md | 2 +- website/docs/r/kv_secret.html.md | 2 +- website/docs/r/kv_secret_v2.html.md | 2 +- 8 files changed, 10 insertions(+), 7 deletions(-) diff --git a/vault/data_source_kv_secret.go b/vault/data_source_kv_secret.go index 8c41b64ab..175eac772 100644 --- a/vault/data_source_kv_secret.go +++ b/vault/data_source_kv_secret.go @@ -76,8 +76,7 @@ func kvSecretDataSourceRead(ctx context.Context, d *schema.ResourceData, meta in return diag.Errorf("no secret found at %q", path) } - data := secret.Data - jsonData, err := json.Marshal(data) + jsonData, err := json.Marshal(secret.Data) if err != nil { return diag.Errorf("error marshaling JSON for %q: %s", path, err) } @@ -86,7 +85,7 @@ func kvSecretDataSourceRead(ctx context.Context, d *schema.ResourceData, meta in return diag.FromErr(err) } - if err := d.Set(consts.FieldData, serializeDataMapToString(data)); err != nil { + if err := d.Set(consts.FieldData, serializeDataMapToString(secret.Data)); err != nil { return diag.FromErr(err) } diff --git a/vault/data_source_kv_secret_test.go b/vault/data_source_kv_secret_test.go index 3f658d01e..77c314bc2 100644 --- a/vault/data_source_kv_secret_test.go +++ b/vault/data_source_kv_secret_test.go @@ -27,6 +27,7 @@ func TestDataSourceKVSecret(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/%s", mount, name)), resource.TestCheckResourceAttr(resourceName, consts.FieldLeaseRenewable, "false"), + resource.TestCheckResourceAttr(resourceName, "data.%", "4"), resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), resource.TestCheckResourceAttr(resourceName, "data.test", "false"), @@ -39,6 +40,7 @@ func TestDataSourceKVSecret(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/%s-updated", mount, name)), resource.TestCheckResourceAttr(resourceName, consts.FieldLeaseRenewable, "false"), + resource.TestCheckResourceAttr(resourceName, "data.%", "4"), resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), resource.TestCheckResourceAttr(resourceName, "data.test", "false"), diff --git a/vault/data_source_kv_secret_v2_test.go b/vault/data_source_kv_secret_v2_test.go index 202794250..9bf695c40 100644 --- a/vault/data_source_kv_secret_v2_test.go +++ b/vault/data_source_kv_secret_v2_test.go @@ -29,6 +29,7 @@ func TestDataSourceKVV2Secret(t *testing.T) { resource.TestCheckResourceAttr(resourceName, consts.FieldName, name), resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/data/%s", mount, name)), resource.TestCheckResourceAttr(resourceName, "destroyed", "false"), + resource.TestCheckResourceAttr(resourceName, "data.%", "4"), resource.TestCheckResourceAttr(resourceName, "data.zip", "zap"), resource.TestCheckResourceAttr(resourceName, "data.foo", "bar"), resource.TestCheckResourceAttr(resourceName, "data.test", "false"), diff --git a/vault/data_source_kv_subkeys_v2_test.go b/vault/data_source_kv_subkeys_v2_test.go index ee2768ff1..f05bc4562 100644 --- a/vault/data_source_kv_subkeys_v2_test.go +++ b/vault/data_source_kv_subkeys_v2_test.go @@ -27,6 +27,7 @@ func TestDataSourceKVSubkeys(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, consts.FieldPath, fmt.Sprintf("%s/subkeys/%s", mount, secretPath)), resource.TestCheckResourceAttrSet(resourceName, consts.FieldDataJSON), + resource.TestCheckResourceAttr(resourceName, "data.%", "3"), resource.TestCheckResourceAttr(resourceName, "data.zip", "null"), resource.TestCheckResourceAttr(resourceName, "data.foo", "null"), resource.TestCheckResourceAttr(resourceName, "data.baz", "{\"riff\":null}"), diff --git a/website/docs/d/kv_secret.html.md b/website/docs/d/kv_secret.html.md index b2d142733..3d16ca956 100644 --- a/website/docs/d/kv_secret.html.md +++ b/website/docs/d/kv_secret.html.md @@ -70,7 +70,7 @@ The following attributes are exported: represent string data, so any non-string values returned from Vault are serialized as JSON. -* `data_json` - String containing a JSON-encoded object that that is +* `data_json` - JSON-encoded string that that is read as the secret data at the given path. * `lease_id` - The lease identifier assigned by Vault, if any. diff --git a/website/docs/d/kv_secret_v2.html.md b/website/docs/d/kv_secret_v2.html.md index f0d6efb1e..e6f160aa7 100644 --- a/website/docs/d/kv_secret_v2.html.md +++ b/website/docs/d/kv_secret_v2.html.md @@ -83,7 +83,7 @@ The following attributes are exported: represent string data, so any non-string values returned from Vault are serialized as JSON. -* `data_json` - String containing a JSON-encoded object that that is +* `data_json` - JSON-encoded string that that is read as the secret data at the given path. * `created_time` - Time at which secret was created. diff --git a/website/docs/r/kv_secret.html.md b/website/docs/r/kv_secret.html.md index 56c383225..107e4f413 100644 --- a/website/docs/r/kv_secret.html.md +++ b/website/docs/r/kv_secret.html.md @@ -45,7 +45,7 @@ The following arguments are supported: * `path` - (Required) Full path of the KV-V1 secret. -* `data_json` - (Required) String containing a JSON-encoded object that will be +* `data_json` - (Required) JSON-encoded string that will be written as the secret data at the given path. ## Required Vault Capabilities diff --git a/website/docs/r/kv_secret_v2.html.md b/website/docs/r/kv_secret_v2.html.md index 7df404f4b..a82ab54fe 100644 --- a/website/docs/r/kv_secret_v2.html.md +++ b/website/docs/r/kv_secret_v2.html.md @@ -66,7 +66,7 @@ The following arguments are supported: * `delete_all_versions` - (Optional) If set to true, permanently deletes all versions for the specified key. -* `data_json` - (Required) String containing a JSON-encoded object that will be +* `data_json` - (Required) JSON-encoded string that will be written as the secret data at the given path. ## Required Vault Capabilities