Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: data_source vault_transit_secret_backend_key #2327

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Unreleased

FEATURES:

* Add new data source `vault_transit_secret_backend_key`. ([#2327](https://github.com/hashicorp/terraform-provider-vault/pull/2327))

## 4.4.0 (Aug 7, 2024)

FEATURES:
Expand Down
176 changes: 176 additions & 0 deletions vault/data_source_transit_secret_backend_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package vault

import (
"context"
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
)

func transitSecretBackendKeyDataSource() *schema.Resource {
return &schema.Resource{
ReadContext: provider.ReadContextWrapper(readTransitSecretBackendKey),
Schema: map[string]*schema.Schema{
consts.FieldBackend: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Full path where transit backend is mounted.",
},
consts.FieldName: {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Name of the key.",
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: "Specifies the type of the key.",
},
"deletion_allowed": {
Type: schema.TypeBool,
Computed: true,
Description: "Specifies if the key is allowed to be deleted.",
},
"derived": {
Type: schema.TypeBool,
Computed: true,
Description: "Specifies if key derivation is used.",
},
"exportable": {
Type: schema.TypeBool,
Computed: true,
Description: "Speficies if keys is exportable.",
},
"allow_plaintext_backup": {
Type: schema.TypeBool,
Computed: true,
Description: "Specifies if taking backup of named key in the plaintext format is enabled.",
},
"keys": {
Type: schema.TypeList,
Computed: true,
Description: "List of key versions in the keyring with the corresponding creation time, name and public key.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"creation_time": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"public_key": {
Type: schema.TypeString,
Computed: true,
},
"certificate_chain": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"min_decryption_version": {
Type: schema.TypeInt,
Computed: true,
Description: "Minimum key version to use for decryption.",
},
"min_encryption_version": {
Type: schema.TypeInt,
Computed: true,
Description: "Minimum key version to use for encryption.",
},
"supports_encryption": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether or not the key supports encryption, based on key type.",
},
"supports_decryption": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether or not the key supports decryption, based on key type.",
},
"supports_derivation": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether or not the key supports derivation, based on key type.",
},
"supports_signing": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether or not the key supports signing, based on key type.",
},
"imported": {
Type: schema.TypeBool,
Computed: true,
Description: "Specifies if the key is imported.",
},
},
}
}

func readTransitSecretBackendKey(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client, err := provider.GetClient(d, meta)
if err != nil {
return diag.FromErr(err)
}

backend := d.Get(consts.FieldBackend).(string)
keyName := d.Get(consts.FieldName).(string)
path := fmt.Sprintf("%s/keys/%s", backend, keyName)

resp, err := client.Logical().ReadWithContext(ctx, path)
if err != nil {
return diag.FromErr(fmt.Errorf("error reading from Vault: %s", err))
}
log.Printf("[DEBUG] Read %q from Vault", path)
if resp == nil {
return diag.FromErr(fmt.Errorf("no key found at %q", path))
}

d.SetId(path)

keyComputedFields := []string{
"type",
"deletion_allowed",
"derived",
"exportable",
"allow_plaintext_backup",
"min_decryption_version",
"min_encryption_version",
"supports_encryption",
"supports_decryption",
"supports_derivation",
"supports_signing",
"imported",
}

for _, k := range keyComputedFields {
if err := d.Set(k, resp.Data[k]); err != nil {
return diag.FromErr(err)
}
}

var keys []interface{}
for _, keyData := range resp.Data["keys"].(map[string]interface{}) {
keyMap := keyData.(map[string]interface{})
keys = append(keys, keyMap)
}

if err := d.Set("keys", keys); err != nil {
return diag.FromErr(err)
}

return nil
}
67 changes: 67 additions & 0 deletions vault/data_source_transit_secret_backend_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package vault

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"

"github.com/hashicorp/terraform-provider-vault/internal/consts"
"github.com/hashicorp/terraform-provider-vault/internal/provider"
"github.com/hashicorp/terraform-provider-vault/testutil"
)

func TestAccDataSourceTransitSecretKey(t *testing.T) {
backend := acctest.RandomWithPrefix("tf-test-transit-backend")
keyName := acctest.RandomWithPrefix("tf-test-transit-key")
dataName := "data.vault_transit_secret_backend_key.test"
resource.Test(t, resource.TestCase{
ProviderFactories: providerFactories,
PreCheck: func() {
testutil.TestAccPreCheck(t)
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion111)
},
Steps: []resource.TestStep{
{
Config: testTransitSecretKeyDataSource(backend, keyName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(dataName, consts.FieldBackend, backend),
resource.TestCheckResourceAttr(dataName, consts.FieldName, keyName),
resource.TestCheckResourceAttr(dataName, "type", "rsa-4096"),
resource.TestCheckResourceAttr(dataName, "deletion_allowed", "true"),
resource.TestCheckResourceAttr(dataName, "exportable", "true"),
resource.TestCheckResourceAttr(dataName, "keys.0.name", "rsa-4096"),
resource.TestCheckResourceAttr(dataName, "keys.0.certificate_chain", ""),
resource.TestCheckResourceAttrSet(dataName, "keys.0.creation_time"),
resource.TestCheckResourceAttrSet(dataName, "keys.0.public_key"),
),
},
},
})
}

func testTransitSecretKeyDataSource(path, keyName string) string {
return fmt.Sprintf(`
resource "vault_mount" "test" {
path = "%s"
type = "transit"
description = "Transit engine mount"
}

resource "vault_transit_secret_backend_key" "test" {
backend = vault_mount.test.path
name = "%s"
type = "rsa-4096"
deletion_allowed = true
exportable = true
}

data "vault_transit_secret_backend_key" "test" {
backend = vault_mount.test.path
name = vault_transit_secret_backend_key.test.name
}`, path, keyName)
}
4 changes: 4 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ var (
Resource: UpdateSchemaResource(transformDecodeDataSource()),
PathInventory: []string{"/transform/decode/{role_name}"},
},
"vault_transit_secret_backend_key": {
Resource: UpdateSchemaResource(transitSecretBackendKeyDataSource()),
PathInventory: []string{"/transit/keys/{key_name}"},
},
}

ResourceRegistry = map[string]*provider.Description{
Expand Down