Skip to content

Commit

Permalink
Add vault_transit_encrypt and vault_transit_decrypt (#872)
Browse files Browse the repository at this point in the history
* add data_sources for vault_transit_encrypt and vault_transit_decrypt

* docs: data_sources for vault_transit_encrypt and vault_transit_decrypt
  • Loading branch information
razaj92 committed Oct 2, 2020
1 parent a6aed02 commit 293699e
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 0 deletions.
69 changes: 69 additions & 0 deletions vault/data_source_transit_decrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package vault

import (
"encoding/base64"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/vault/api"
)

func transitDecryptDataSource() *schema.Resource {
return &schema.Resource{
Read: transitDecryptDataSourceRead,

Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
Description: "Name of the decryption key to use.",
},
"backend": {
Type: schema.TypeString,
Required: true,
Description: "The Transit secret backend the key belongs to.",
},
"plaintext": {
Type: schema.TypeString,
Computed: true,
Description: "Decrypted plain text",
Sensitive: true,
},
"context": {
Type: schema.TypeString,
Optional: true,
Description: "Specifies the context for key derivation",
},
"ciphertext": {
Type: schema.TypeString,
Required: true,
Description: "Transit encrypted cipher text.",
},
},
}
}

func transitDecryptDataSourceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

backend := d.Get("backend").(string)
key := d.Get("key").(string)
ciphertext := d.Get("ciphertext").(string)

context := base64.StdEncoding.EncodeToString([]byte(d.Get("context").(string)))
payload := map[string]interface{}{
"ciphertext": ciphertext,
"context": context,
}

decryptedData, err := client.Logical().Write(backend+"/decrypt/"+key, payload)
if err != nil {
return fmt.Errorf("issue encrypting with key: %s", err)
}

plaintext, _ := base64.StdEncoding.DecodeString(decryptedData.Data["plaintext"].(string))

d.SetId(base64.StdEncoding.EncodeToString([]byte(ciphertext)))
d.Set("plaintext", string(plaintext))

return nil
}
67 changes: 67 additions & 0 deletions vault/data_source_transit_decrypt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package vault

import (
"fmt"
"testing"

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

func TestDataSourceTransitDecrypt(t *testing.T) {
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceTransitDecrypt_config,
Check: testDataSourceTransitDecrypt_check,
},
},
})

}

var testDataSourceTransitDecrypt_config = `
resource "vault_mount" "test" {
path = "transit"
type = "transit"
description = "This is an example mount"
}
resource "vault_transit_secret_backend_key" "test" {
name = "test"
backend = vault_mount.test.path
deletion_allowed = true
}
data "vault_transit_encrypt" "test" {
backend = vault_mount.test.path
key = vault_transit_secret_backend_key.test.name
plaintext = "foo"
}
data "vault_transit_decrypt" "test" {
backend = vault_mount.test.path
key = vault_transit_secret_backend_key.test.name
ciphertext = data.vault_transit_encrypt.test.ciphertext
}
`

func testDataSourceTransitDecrypt_check(s *terraform.State) error {
resourceState := s.Modules[0].Resources["data.vault_transit_decrypt.test"]
if resourceState == nil {
return fmt.Errorf("resource not found in state %v", s.Modules[0].Resources)
}

iState := resourceState.Primary
if iState == nil {
return fmt.Errorf("resource has no primary instance")
}

if got, want := iState.Attributes["plaintext"], "foo"; got != want {
return fmt.Errorf("Decrypted plaintext %s; did not match encrypted plaintext 'foo'", iState.Attributes["plaintext"])
}

return nil
}
77 changes: 77 additions & 0 deletions vault/data_source_transit_encrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package vault

import (
"encoding/base64"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"

"github.com/hashicorp/vault/api"
)

func transitEncryptDataSource() *schema.Resource {
return &schema.Resource{
Read: transitEncryptDataSourceRead,

Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
Description: "Name of the encryption key to use.",
},
"backend": {
Type: schema.TypeString,
Required: true,
Description: "The Transit secret backend the key belongs to.",
},
"plaintext": {
Type: schema.TypeString,
Required: true,
Description: "Map of strings read from Vault.",
Sensitive: true,
},
"context": {
Type: schema.TypeString,
Optional: true,
Description: "Specifies the context for key derivation",
},
"key_version": {
Type: schema.TypeInt,
Optional: true,
Description: "The version of the key to use for encryption",
},
"ciphertext": {
Type: schema.TypeString,
Computed: true,
Description: "Transit encrypted cipher text.",
},
},
}
}

func transitEncryptDataSourceRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*api.Client)

backend := d.Get("backend").(string)
key := d.Get("key").(string)
keyVersion := d.Get("key_version").(int)

plaintext := base64.StdEncoding.EncodeToString([]byte(d.Get("plaintext").(string)))
context := base64.StdEncoding.EncodeToString([]byte(d.Get("context").(string)))
payload := map[string]interface{}{
"plaintext": plaintext,
"context": context,
"key_version": keyVersion,
}

encryptedData, err := client.Logical().Write(backend+"/encrypt/"+key, payload)
if err != nil {
return fmt.Errorf("issue encrypting with key: %s", err)
}

cipherText := encryptedData.Data["ciphertext"]

d.SetId(base64.StdEncoding.EncodeToString([]byte(cipherText.(string))))
d.Set("ciphertext", cipherText)

return nil
}
67 changes: 67 additions & 0 deletions vault/data_source_transit_encrypt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package vault

import (
"fmt"
"testing"

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

func TestDataSourceTransitEncrypt(t *testing.T) {
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
Steps: []resource.TestStep{
{
Config: testDataSourceTransitEncrypt_config,
Check: testDataSourceTransitEncrypt_check,
},
},
})

}

var testDataSourceTransitEncrypt_config = `
resource "vault_mount" "test" {
path = "transit"
type = "transit"
description = "This is an example mount"
}
resource "vault_transit_secret_backend_key" "test" {
name = "test"
backend = vault_mount.test.path
deletion_allowed = true
}
data "vault_transit_encrypt" "test" {
backend = vault_mount.test.path
key = vault_transit_secret_backend_key.test.name
plaintext = "foo"
}
data "vault_transit_decrypt" "test" {
backend = vault_mount.test.path
key = vault_transit_secret_backend_key.test.name
ciphertext = data.vault_transit_encrypt.test.ciphertext
}
`

func testDataSourceTransitEncrypt_check(s *terraform.State) error {
resourceState := s.Modules[0].Resources["data.vault_transit_decrypt.test"]
if resourceState == nil {
return fmt.Errorf("resource not found in state %v", s.Modules[0].Resources)
}

iState := resourceState.Primary
if iState == nil {
return fmt.Errorf("resource has no primary instance")
}

if got, want := iState.Attributes["plaintext"], "foo"; got != want {
return fmt.Errorf("Encrypted ciphertext %s; did not decrypt to plaintext %s", iState.Attributes["ciphertext"], iState.Attributes["plaintext"])
}

return nil
}
8 changes: 8 additions & 0 deletions vault/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ var (
Resource: authBackendDataSource(),
PathInventory: []string{"/sys/auth"},
},
"vault_transit_encrypt": {
Resource: transitEncryptDataSource(),
PathInventory: []string{"/transit/encrypt/{name}"},
},
"vault_transit_decrypt": {
Resource: transitDecryptDataSource(),
PathInventory: []string{"/transit/decrypt/{name}"},
},
}

ResourceRegistry = map[string]*Description{
Expand Down
37 changes: 37 additions & 0 deletions website/docs/d/transit_decrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
layout: "vault"
page_title: "Vault: vault_transit_decrypt data source"
sidebar_current: "docs-vault-datasource-transit-decrypt"
description: |-
Decrypt ciphertext using a Vault Transit encryption key.
---

# vault\_transit\_decrypt

This is a data source which can be used to decrypt ciphertext using a Vault Transit key.

## Example Usage

```hcl
data "vault_transit_decrypt" "test" {
backend = "transit"
key = "test"
ciphertext = "vault:v1:S3GtnJ5GUNCWV+/pdL9+g1Feu/nzAv+RlmTmE91Tu0rBkeIU8MEb2nSspC/1IQ=="
}
```

## Argument Reference

Each document configuration may have one or more `rule` blocks, which each accept the following arguments:

* `key` - (Required) Specifies the name of the transit key to decrypt against.

* `backend` - (Required) The path the transit secret backend is mounted at, with no leading or trailing `/`.

* `ciphertext` - (Required) Ciphertext to be decoded.

* `context` - (Optional) Context for key derivation. This is required if key derivation is enabled for this key.

## Attributes Reference

* `plaintext` - Decrypted plaintext returned from Vault
50 changes: 50 additions & 0 deletions website/docs/d/transit_encrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
layout: "vault"
page_title: "Vault: vault_transit_encrypt data source"
sidebar_current: "docs-vault-datasource-transit-encrypt"
description: |-
Encrypts plaintext using a Vault Transit encryption key.
---

# vault\_transit\_encrypt

This is a data source which can be used to encrypt plaintext using a Vault Transit key.

## Example Usage

```hcl
resource "vault_mount" "test" {
path = "transit"
type = "transit"
description = "This is an example mount"
}
resource "vault_transit_secret_backend_key" "test" {
backend = "${vault_mount.test.path}"
name = "test"
}
data "vault_transit_encrypt" "test" {
backend = "${vault_mount.test.path}"
key = "${vault_transit_secret_backend_key.test.name}"
plaintext = "foobar"
}
```

## Argument Reference

Each document configuration may have one or more `rule` blocks, which each accept the following arguments:

* `key` - (Required) Specifies the name of the transit key to encrypt against.

* `backend` - (Required) The path the transit secret backend is mounted at, with no leading or trailing `/`.

* `plaintext` - (Required) Plaintext to be encoded.

* `context` - (Optional) Context for key derivation. This is required if key derivation is enabled for this key.

* `key_version` - (Optional) The version of the key to use for encryption. If not set, uses the latest version. Must be greater than or equal to the key's `min_encryption_version`, if set.

## Attributes Reference

* `ciphertext` - Encrypted ciphertext returned from Vault

0 comments on commit 293699e

Please sign in to comment.