5c84c36915
* Add more cli subcommands * Add metadata commands * Add more subcommands * Update cli * Move archive commands to delete * Add helpers for making http calls to the kv backend * rename cli header * Format the various maps from kv * Add list command * Update help text * Add a command to enable versioning on a backend * Rename enable-versions command * Some review feedback * Fix listing of top level keys * Fix issue when metadata is nil * Add test for lising top level keys * Fix some typos * Add a note about deleting all versions
427 lines
8.4 KiB
Go
427 lines
8.4 KiB
Go
package keysutil
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/vault/logical"
|
|
)
|
|
|
|
var compilerOpt []string
|
|
|
|
func TestBase58(t *testing.T) {
|
|
tCases := []struct {
|
|
in string
|
|
out string
|
|
}{
|
|
{
|
|
"",
|
|
"0",
|
|
},
|
|
{
|
|
"foo",
|
|
"sapp",
|
|
},
|
|
{
|
|
"5d5746d044b9a9429249966c9e3fee178ca679b91487b11d4b73c9865202104c",
|
|
"cozMP2pOYdDiNGeFQ2afKAOGIzO0HVpJ8OPFXuVPNbHasFyenK9CzIIPuOG7EFWOCy4YWvKGZa671N4kRSoaxZ",
|
|
},
|
|
{
|
|
"5ba33e16d742f3c785f6e7e8bb6f5fe82346ffa1c47aa8e95da4ddd5a55bb334",
|
|
"cotpEJPnhuTRofLi4lDe5iKw2fkSGc6TpUYeuWoBp8eLYJBWLRUVDZI414OjOCWXKZ0AI8gqNMoxd4eLOklwYk",
|
|
},
|
|
{
|
|
" ",
|
|
"w",
|
|
},
|
|
{
|
|
"-",
|
|
"J",
|
|
},
|
|
{
|
|
"0",
|
|
"M",
|
|
},
|
|
{
|
|
"1",
|
|
"N",
|
|
},
|
|
{
|
|
"-1",
|
|
"30B",
|
|
},
|
|
{
|
|
"11",
|
|
"3h7",
|
|
},
|
|
{
|
|
"abc",
|
|
"qMin",
|
|
},
|
|
{
|
|
"1234598760",
|
|
"1a0AFzKIPnihTq",
|
|
},
|
|
{
|
|
"abcdefghijklmnopqrstuvwxyz",
|
|
"hUBXsgd3F2swSlEgbVi2p0Ncr6kzVeJTLaW",
|
|
},
|
|
}
|
|
|
|
for _, c := range tCases {
|
|
e := Base62Encode([]byte(c.in))
|
|
d := string(Base62Decode(e))
|
|
|
|
if d != c.in {
|
|
t.Fatalf("decoded value didn't match input %#v %#v", c.in, d)
|
|
}
|
|
|
|
if e != c.out {
|
|
t.Fatalf("encoded value didn't match expected %#v, %#v", e, c.out)
|
|
}
|
|
}
|
|
|
|
d := Base62Decode("!0000/")
|
|
if len(d) != 0 {
|
|
t.Fatalf("Decode of invalid string should be empty, got %#v", d)
|
|
}
|
|
}
|
|
|
|
func TestEncrytedKeysStorage_BadPolicy(t *testing.T) {
|
|
policy := &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: false,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
_, err := NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != ErrPolicyDerivedKeys {
|
|
t.Fatalf("Unexpected Error: %s", err)
|
|
}
|
|
|
|
policy = &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: false,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
_, err = NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != ErrPolicyConvergentEncryption {
|
|
t.Fatalf("Unexpected Error: %s", err)
|
|
}
|
|
|
|
policy = &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 1,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
_, err = NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != ErrPolicyConvergentVersion {
|
|
t.Fatalf("Unexpected Error: %s", err)
|
|
}
|
|
|
|
policy = &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
}
|
|
|
|
func TestEncryptedKeysStorage_List(t *testing.T) {
|
|
s := &logical.InmemStorage{}
|
|
policy := &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
err := policy.Rotate(ctx, s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
es, err := NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: "test",
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: "test/foo",
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: "test/foo1/test",
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
keys, err := es.Wrap(s).List(ctx, "test/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Test prefixed with "/"
|
|
keys, err = es.Wrap(s).List(ctx, "/test/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(keys) != 2 || keys[0] != "foo1/" || keys[1] != "foo" {
|
|
t.Fatalf("bad keys: %#v", keys)
|
|
}
|
|
|
|
keys, err = es.Wrap(s).List(ctx, "/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(keys) != 2 || keys[0] != "test" || keys[1] != "test/" {
|
|
t.Fatalf("bad keys: %#v", keys)
|
|
}
|
|
|
|
keys, err = es.Wrap(s).List(ctx, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(keys) != 2 || keys[0] != "test" || keys[1] != "test/" {
|
|
t.Fatalf("bad keys: %#v", keys)
|
|
}
|
|
}
|
|
|
|
func TestEncryptedKeysStorage_CRUD(t *testing.T) {
|
|
s := &logical.InmemStorage{}
|
|
policy := &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
err := policy.Rotate(ctx, s)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
es, err := NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: "test/foo",
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: "test/foo1/test",
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
keys, err := es.Wrap(s).List(ctx, "test/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Test prefixed with "/"
|
|
keys, err = es.Wrap(s).List(ctx, "/test/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(keys) != 2 || keys[0] != "foo1/" || keys[1] != "foo" {
|
|
t.Fatalf("bad keys: %#v", keys)
|
|
}
|
|
|
|
// Test the cached value is correct
|
|
keys, err = es.Wrap(s).List(ctx, "test/")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(keys) != 2 || keys[0] != "foo1/" || keys[1] != "foo" {
|
|
t.Fatalf("bad keys: %#v", keys)
|
|
}
|
|
|
|
data, err := es.Wrap(s).Get(ctx, "test/foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !reflect.DeepEqual(data.Value, []byte("test")) {
|
|
t.Fatalf("bad data: %#v", data)
|
|
}
|
|
|
|
err = es.Wrap(s).Delete(ctx, "test/foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
data, err = es.Wrap(s).Get(ctx, "test/foo")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if data != nil {
|
|
t.Fatal("data should be nil")
|
|
}
|
|
|
|
}
|
|
|
|
func BenchmarkEncrytedKeyStorage_List(b *testing.B) {
|
|
s := &logical.InmemStorage{}
|
|
policy := &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
err := policy.Rotate(ctx, s)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
es, err := NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
for i := 0; i < 10000; i++ {
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: fmt.Sprintf("test/%d", i),
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
keys, err := es.Wrap(s).List(ctx, "test/")
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
compilerOpt = keys
|
|
}
|
|
}
|
|
|
|
func BenchmarkEncrytedKeyStorage_Put(b *testing.B) {
|
|
s := &logical.InmemStorage{}
|
|
policy := &Policy{
|
|
Name: "metadata",
|
|
Type: KeyType_AES256_GCM96,
|
|
Derived: true,
|
|
KDF: Kdf_hkdf_sha256,
|
|
ConvergentEncryption: true,
|
|
ConvergentVersion: 2,
|
|
VersionTemplate: EncryptedKeyPolicyVersionTpl,
|
|
versionPrefixCache: &sync.Map{},
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
err := policy.Rotate(ctx, s)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
es, err := NewEncryptedKeyStorageWrapper(EncryptedKeyStorageConfig{
|
|
Policy: policy,
|
|
Prefix: "prefix",
|
|
})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
err = es.Wrap(s).Put(ctx, &logical.StorageEntry{
|
|
Key: fmt.Sprintf("test/%d", i),
|
|
Value: []byte("test"),
|
|
})
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|