Skip to content

Commit

Permalink
secret/kvv2: fix drift detection when disable_read is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
fairclothjm committed Oct 5, 2023
1 parent 95a3230 commit 53b794a
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
1 change: 1 addition & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
FieldNamespacePath = "namespace_path"
FieldPathFQ = "path_fq"
FieldData = "data"
FieldDisableRead = "disable_read"
FieldName = "name"
FieldVersion = "version"
FieldMetadata = "metadata"
Expand Down
18 changes: 16 additions & 2 deletions vault/resource_kv_secret_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ var (
}
)

func kvSecretV2DisableReadDiff(ctx context.Context, diff *schema.ResourceDiff, m interface{}) error {
if diff.Get(consts.FieldDisableRead).(bool) && diff.Id() != "" {
// When disable_read is true we need to remove the computed data keys
// from the diff. Otherwise, we will report drift because they were
// never set but the provider expects them to be because they are
// computed fields.
log.Printf("[DEBUG] %q is set, clearing %q and %q", consts.FieldDisableRead, consts.FieldData, consts.FieldMetadata)
diff.Clear(consts.FieldData)
diff.Clear(consts.FieldMetadata)
}
return nil
}

func kvSecretV2Resource(name string) *schema.Resource {
return &schema.Resource{
CreateContext: kvSecretV2Write,
Expand All @@ -41,6 +54,7 @@ func kvSecretV2Resource(name string) *schema.Resource {
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
CustomizeDiff: kvSecretV2DisableReadDiff,

Schema: map[string]*schema.Schema{
consts.FieldMount: {
Expand Down Expand Up @@ -77,7 +91,7 @@ func kvSecretV2Resource(name string) *schema.Resource {
Description: "An object that holds option settings.",
},

"disable_read": {
consts.FieldDisableRead: {
Type: schema.TypeBool,
Optional: true,
Default: false,
Expand Down Expand Up @@ -223,7 +237,7 @@ func kvSecretV2Write(ctx context.Context, d *schema.ResourceData, meta interface
}

func kvSecretV2Read(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
shouldRead := !d.Get("disable_read").(bool)
shouldRead := !d.Get(consts.FieldDisableRead).(bool)

path := d.Id()
if path == "" {
Expand Down
122 changes: 122 additions & 0 deletions vault/resource_kv_secret_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ package vault

import (
"fmt"
"reflect"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/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"
)

var testKVV2Data = map[string]interface{}{
"foo": "bar",
"baz": "qux",
}

func TestAccKVSecretV2(t *testing.T) {
t.Parallel()
resourceName := "vault_kv_secret_v2.test"
Expand Down Expand Up @@ -114,6 +122,120 @@ func TestAccKVSecretV2(t *testing.T) {
})
}

func TestAccKVSecretV2_DisableRead(t *testing.T) {
t.Parallel()
resourceName := "vault_kv_secret_v2.test"
mount := acctest.RandomWithPrefix("tf-kvv2")
name := acctest.RandomWithPrefix("tf-secret")

resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testutil.TestAccPreCheck(t) },
Steps: []resource.TestStep{
{
PreConfig: func() {
mountKVEngine(t, mount, name)
},
Config: testKVSecretV2Config_DisableRead(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, "disable_read", "true"),
),
},
{
PreConfig: func() {
writeKVData(t, mount, name)
},
Config: testKVSecretV2Config_DisableRead(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, "disable_read", "true"),
),
},
{
PreConfig: func() {
readKVData(t, mount, name)
},
Config: testKVSecretV2Config_DisableRead(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, "disable_read", "true"),
),
},
},
})
}

func readKVData(t *testing.T, mount, name string) {
t.Helper()
client := testProvider.Meta().(*provider.ProviderMeta).GetClient()

// Read data at path
path := fmt.Sprintf("%s/data/%s", mount, name)
resp, err := client.Logical().Read(path)
if err != nil {
t.Fatalf(fmt.Sprintf("error reading from Vault; err=%s", err))
}

if resp == nil {
t.Fatalf("empty response")
}
if len(resp.Data) == 0 {
t.Fatalf("kvv2 secret data should not be empty")
}
if !reflect.DeepEqual(resp.Data["data"], testKVV2Data) {
t.Fatalf("kvv2 secret data does not match got: %#+v, want: %#+v", resp.Data["data"], testKVV2Data)
}
}

func writeKVData(t *testing.T, mount, name string) {
t.Helper()
client := testProvider.Meta().(*provider.ProviderMeta).GetClient()

data := map[string]interface{}{
consts.FieldData: testKVV2Data,
}
// Write data at path
path := fmt.Sprintf("%s/data/%s", mount, name)
resp, err := client.Logical().Write(path, data)
if err != nil {
t.Fatalf(fmt.Sprintf("error writing to Vault; err=%s", err))
}

if resp == nil {
t.Fatalf("empty response")
}
}

func mountKVEngine(t *testing.T, mount, name string) {
t.Helper()
client := testProvider.Meta().(*provider.ProviderMeta).GetClient()

err := client.Sys().Mount(mount, &api.MountInput{
Type: "kv-v2",
Description: "Mount for testing KV datasource",
})
if err != nil {
t.Fatalf(fmt.Sprintf("error mounting kvv2 engine; err=%s", err))
}
}

func testKVSecretV2Config_DisableRead(mount, name string) string {
return fmt.Sprintf(`
resource "vault_kv_secret_v2" "test" {
mount = "%s"
name = "%s"
disable_read = true
data_json = jsonencode({})
}`, mount, name)
}

func testKVSecretV2Config_initial(mount, name string) string {
ret := fmt.Sprintf(`
%s
Expand Down

0 comments on commit 53b794a

Please sign in to comment.