Vault-11623: OSS changes for seal config and env vars (#21116)

* add config changes for name and priority fields in seal stanza

* change env vars and fix tests

* add header and fix func call

* tweak limits on seals

* fix missing import

* add docstrings
This commit is contained in:
Rachel Culpepper
2023-06-21 17:30:59 -04:00
committed by GitHub
parent 15aee2e0ba
commit 254d8f8356
7 changed files with 290 additions and 14 deletions

View File

@@ -99,7 +99,7 @@ func ParseConfig(d string) (*SharedConfig, error) {
if o := list.Filter("seal"); len(o.Items) > 0 {
result.found("seal", "Seal")
if err := parseKMS(&result.Seals, o, "seal", 3); err != nil {
if err := parseKMS(&result.Seals, o, "seal", 5); err != nil {
return nil, fmt.Errorf("error parsing 'seal': %w", err)
}
}
@@ -215,7 +215,12 @@ func (c *SharedConfig) Sanitized() map[string]interface{} {
cleanSeal := map[string]interface{}{
"type": s.Type,
"disabled": s.Disabled,
"name": s.Name,
}
if s.Priority > 0 {
cleanSeal["priority"] = s.Priority
}
sanitizedSeals = append(sanitizedSeals, cleanSeal)
}
result["seals"] = sanitizedSeals

View File

@@ -0,0 +1,63 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package configutil
var (
AliCloudKMSEnvVars = map[string]string{
"ALICLOUD_REGION": "region",
"ALICLOUD_DOMAIN": "domain",
"ALICLOUD_ACCESS_KEY": "access_key",
"ALICLOUD_SECRET_KEY": "secret_key",
"VAULT_ALICLOUDKMS_SEAL_KEY_ID": "kms_key_id",
}
AWSKMSEnvVars = map[string]string{
"AWS_REGION": "region",
"AWS_DEFAULT_REGION": "region",
"AWS_ACCESS_KEY_ID": "access_key",
"AWS_SESSION_TOKEN": "session_token",
"AWS_SECRET_ACCESS_KEY": "secret_key",
"VAULT_AWSKMS_SEAL_KEY_ID": "kms_key_id",
"AWS_KMS_ENDPOINT": "endpoint",
}
AzureEnvVars = map[string]string{
"AZURE_TENANT_ID": "tenant_id",
"AZURE_CLIENT_ID": "client_id",
"AZURE_CLIENT_SECRET": "client_secret",
"AZURE_ENVIRONMENT": "environment",
"VAULT_AZUREKEYVAULT_VAULT_NAME": "vault_name",
"VAULT_AZUREKEYVAULT_KEY_NAME": "key_name",
"AZURE_AD_RESOURCE": "resource",
}
GCPCKMSEnvVars = map[string]string{
"GOOGLE_CREDENTIALS": "credentials",
"GOOGLE_APPLICATION_CREDENTIALS": "credentials",
"GOOGLE_PROJECT": "project",
"GOOGLE_REGION": "region",
"VAULT_GCPCKMS_SEAL_KEY_RING": "key_ring",
"VAULT_GCPCKMS_SEAL_CRYPTO_KEY": "crypto_key",
}
OCIKMSEnvVars = map[string]string{
"VAULT_OCIKMS_SEAL_KEY_ID": "key_id",
"VAULT_OCIKMS_CRYPTO_ENDPOINT": "crypto_endpoint",
"VAULT_OCIKMS_MANAGEMENT_ENDPOINT": "management_endpoint",
}
TransitEnvVars = map[string]string{
"VAULT_ADDR": "address",
"VAULT_TOKEN": "token",
"VAULT_TRANSIT_SEAL_KEY_NAME": "key_name",
"VAULT_TRANSIT_SEAL_MOUNT_PATH": "mount_path",
"VAULT_NAMESPACE": "namespace",
"VAULT_TRANSIT_SEAL_DISABLE_RENEWAL": "disable_renewal",
"VAULT_CACERT": "tls_ca_cert",
"VAULT_CLIENT_CERT": "tls_client_cert",
"VAULT_CLIENT_KEY": "tls_client_key",
"VAULT_TLS_SERVER_NAME": "tls_server_name",
"VAULT_SKIP_VERIFY": "tls_skip_verify",
}
)

View File

@@ -8,6 +8,7 @@ import (
"crypto/rand"
"fmt"
"io"
"os"
"strings"
"github.com/hashicorp/errwrap"
@@ -30,6 +31,7 @@ import (
var (
ConfigureWrapper = configureWrapper
CreateSecureRandomReaderFunc = createSecureRandomReader
GetEnvConfigFunc = getEnvConfig
)
// Entropy contains Entropy configuration for the server
@@ -55,6 +57,9 @@ type KMS struct {
Disabled bool
Config map[string]string
Priority int `hcl:"priority"`
Name string `hcl:"name"`
}
func (k *KMS) GoString() string {
@@ -63,7 +68,7 @@ func (k *KMS) GoString() string {
func parseKMS(result *[]*KMS, list *ast.ObjectList, blockName string, maxKMS int) error {
if len(list.Items) > maxKMS {
return fmt.Errorf("only two or less %q blocks are permitted", blockName)
return fmt.Errorf("only %d or less %q blocks are permitted", maxKMS, blockName)
}
seals := make([]*KMS, 0, len(list.Items))
@@ -102,6 +107,28 @@ func parseKMS(result *[]*KMS, list *ast.ObjectList, blockName string, maxKMS int
delete(m, "disabled")
}
var priority int
if v, ok := m["priority"]; ok {
priority, err = parseutil.SafeParseInt(v)
if err != nil {
return multierror.Prefix(fmt.Errorf("unable to parse 'priority' in kms type %q: %w", key, err), fmt.Sprintf("%s.%s", blockName, key))
}
delete(m, "priority")
if priority < 1 {
return multierror.Prefix(fmt.Errorf("invalid priority in kms type %q: %d", key, priority), fmt.Sprintf("%s.%s", blockName, key))
}
}
name := strings.ToLower(key)
if v, ok := m["name"]; ok {
name, ok = v.(string)
if !ok {
return multierror.Prefix(fmt.Errorf("unable to parse 'name' in kms type %q: unexpected type %T", key, v), fmt.Sprintf("%s.%s", blockName, key))
}
delete(m, "name")
}
strMap := make(map[string]string, len(m))
for k, v := range m {
s, err := parseutil.ParseString(v)
@@ -115,6 +142,8 @@ func parseKMS(result *[]*KMS, list *ast.ObjectList, blockName string, maxKMS int
Type: strings.ToLower(key),
Purpose: purpose,
Disabled: disabled,
Priority: priority,
Name: name,
}
if len(strMap) > 0 {
seal.Config = strMap
@@ -168,6 +197,11 @@ func configureWrapper(configKMS *KMS, infoKeys *[]string, info *map[string]strin
var kmsInfo map[string]string
var err error
envConfig := GetEnvConfigFunc(configKMS)
for name, val := range envConfig {
configKMS.Config[name] = val
}
switch wrapping.WrapperType(configKMS.Type) {
case wrapping.WrapperTypeShamir:
return nil, nil
@@ -235,7 +269,7 @@ func GetAEADKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[st
func GetAliCloudKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := alicloudkms.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
// If the error is any other than logical.KeyNotFoundError, return the error
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
@@ -255,7 +289,7 @@ func GetAliCloudKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, ma
var GetAWSKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := awskms.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
// If the error is any other than logical.KeyNotFoundError, return the error
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
@@ -275,7 +309,7 @@ var GetAWSKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, m
func GetAzureKeyVaultKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := azurekeyvault.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
// If the error is any other than logical.KeyNotFoundError, return the error
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
@@ -293,7 +327,7 @@ func GetAzureKeyVaultKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrappe
func GetGCPCKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := gcpckms.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
// If the error is any other than logical.KeyNotFoundError, return the error
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
@@ -312,7 +346,7 @@ func GetGCPCKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map
func GetOCIKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := ocikms.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
return nil, nil, err
}
@@ -328,7 +362,7 @@ func GetOCIKMSKMSFunc(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[
var GetTransitKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrapper, map[string]string, error) {
wrapper := transit.NewWrapper()
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithConfigMap(kms.Config))...)
wrapperInfo, err := wrapper.SetConfig(context.Background(), append(opts, wrapping.WithDisallowEnvVars(true), wrapping.WithConfigMap(kms.Config))...)
if err != nil {
// If the error is any other than logical.KeyNotFoundError, return the error
if !errwrap.ContainsType(err, new(logical.KeyNotFoundError)) {
@@ -350,3 +384,34 @@ var GetTransitKMSFunc = func(kms *KMS, opts ...wrapping.Option) (wrapping.Wrappe
func createSecureRandomReader(conf *SharedConfig, wrapper wrapping.Wrapper) (io.Reader, error) {
return rand.Reader, nil
}
func getEnvConfig(kms *KMS) map[string]string {
envValues := make(map[string]string)
var wrapperEnvVars map[string]string
switch wrapping.WrapperType(kms.Type) {
case wrapping.WrapperTypeAliCloudKms:
wrapperEnvVars = AliCloudKMSEnvVars
case wrapping.WrapperTypeAwsKms:
wrapperEnvVars = AWSKMSEnvVars
case wrapping.WrapperTypeAzureKeyVault:
wrapperEnvVars = AzureEnvVars
case wrapping.WrapperTypeGcpCkms:
wrapperEnvVars = GCPCKMSEnvVars
case wrapping.WrapperTypeOciKms:
wrapperEnvVars = OCIKMSEnvVars
case wrapping.WrapperTypeTransit:
wrapperEnvVars = TransitEnvVars
default:
return nil
}
for envVar, configName := range wrapperEnvVars {
val := os.Getenv(envVar)
if val != "" {
envValues[configName] = val
}
}
return envValues
}

View File

@@ -0,0 +1,102 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package configutil
import (
"os"
"reflect"
"testing"
)
func Test_getEnvConfig(t *testing.T) {
tests := []struct {
name string
kms *KMS
envVars map[string]string
want map[string]string
}{
{
"AliCloud wrapper",
&KMS{
Type: "alicloudkms",
Priority: 1,
},
map[string]string{"ALICLOUD_REGION": "test_region", "ALICLOUD_DOMAIN": "test_domain", "ALICLOUD_ACCESS_KEY": "test_access_key", "ALICLOUD_SECRET_KEY": "test_secret_key", "VAULT_ALICLOUDKMS_SEAL_KEY_ID": "test_key_id"},
map[string]string{"region": "test_region", "domain": "test_domain", "access_key": "test_access_key", "secret_key": "test_secret_key", "kms_key_id": "test_key_id"},
},
{
"AWS KMS wrapper",
&KMS{
Type: "awskms",
Priority: 1,
},
map[string]string{"AWS_REGION": "test_region", "AWS_ACCESS_KEY_ID": "test_access_key", "AWS_SECRET_ACCESS_KEY": "test_secret_key", "VAULT_AWSKMS_SEAL_KEY_ID": "test_key_id"},
map[string]string{"region": "test_region", "access_key": "test_access_key", "secret_key": "test_secret_key", "kms_key_id": "test_key_id"},
},
{
"Azure KeyVault wrapper",
&KMS{
Type: "azurekeyvault",
Priority: 1,
},
map[string]string{"AZURE_TENANT_ID": "test_tenant_id", "AZURE_CLIENT_ID": "test_client_id", "AZURE_CLIENT_SECRET": "test_client_secret", "AZURE_ENVIRONMENT": "test_environment", "VAULT_AZUREKEYVAULT_VAULT_NAME": "test_vault_name", "VAULT_AZUREKEYVAULT_KEY_NAME": "test_key_name"},
map[string]string{"tenant_id": "test_tenant_id", "client_id": "test_client_id", "client_secret": "test_client_secret", "environment": "test_environment", "vault_name": "test_vault_name", "key_name": "test_key_name"},
},
{
"GCP CKMS wrapper",
&KMS{
Type: "gcpckms",
Priority: 1,
},
map[string]string{"GOOGLE_CREDENTIALS": "test_credentials", "GOOGLE_PROJECT": "test_project", "GOOGLE_REGION": "test_region", "VAULT_GCPCKMS_SEAL_KEY_RING": "test_key_ring", "VAULT_GCPCKMS_SEAL_CRYPTO_KEY": "test_crypto_key"},
map[string]string{"credentials": "test_credentials", "project": "test_project", "region": "test_region", "key_ring": "test_key_ring", "crypto_key": "test_crypto_key"},
},
{
"OCI KMS wrapper",
&KMS{
Type: "ocikms",
Priority: 1,
},
map[string]string{"VAULT_OCIKMS_SEAL_KEY_ID": "test_key_id", "VAULT_OCIKMS_CRYPTO_ENDPOINT": "test_crypto_endpoint", "VAULT_OCIKMS_MANAGEMENT_ENDPOINT": "test_management_endpoint"},
map[string]string{"key_id": "test_key_id", "crypto_endpoint": "test_crypto_endpoint", "management_endpoint": "test_management_endpoint"},
},
{
"Transit wrapper",
&KMS{
Type: "transit",
Priority: 1,
},
map[string]string{"VAULT_ADDR": "test_address", "VAULT_TOKEN": "test_token", "VAULT_TRANSIT_SEAL_KEY_NAME": "test_key_name", "VAULT_TRANSIT_SEAL_MOUNT_PATH": "test_mount_path"},
map[string]string{"address": "test_address", "token": "test_token", "key_name": "test_key_name", "mount_path": "test_mount_path"},
},
{
"Environment vars not set",
&KMS{
Type: "awskms",
Priority: 1,
},
map[string]string{},
map[string]string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for envName, envVal := range tt.envVars {
if err := os.Setenv(envName, envVal); err != nil {
t.Errorf("error setting environment vars for test: %s", err)
}
}
if got := GetEnvConfigFunc(tt.kms); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getEnvConfig() = %v, want %v", got, tt.want)
}
for env := range tt.envVars {
if err := os.Unsetenv(env); err != nil {
t.Errorf("error unsetting environment vars for test: %s", err)
}
}
})
}
}