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 3 commits 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

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

## 4.5.0 (Nov 19, 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": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few keys missing from this

  • auto_rotate_period
  • imported_key (it's listed as imported below)
  • latest_version
  • min_available_version

There are also a few optional keys depending on options set in the response returned see formatKeyPolicy

  • key_size is returned if set on creation
  • imported_key_allow_rotation is returned if imported_key is true
  • backup_info and restore_info are returned if the key was backed up/restored
  • kdf, kdf_mode, convergent_encryption and possibly convergent_encryption_version are returned if derived is true

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few keys missing from this

Sorry I used an old vault release without some of these keys and after testing it with the new version I forgot to add them.

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