diff --git a/internal/util/crypto.go b/internal/util/crypto.go index e0634ec71..6b87f60b5 100644 --- a/internal/util/crypto.go +++ b/internal/util/crypto.go @@ -19,11 +19,8 @@ package util import ( "context" "encoding/base64" - "encoding/json" "errors" "fmt" - "io/ioutil" - "os" "path" "strings" @@ -34,22 +31,12 @@ const ( mapperFilePrefix = "luks-rbd-" mapperFilePathPrefix = "/dev/mapper" - kmsTypeKey = "encryptionKMSType" - // kmsConfigPath is the location of the vault config file kmsConfigPath = "/etc/ceph-csi-encryption-kms-config/config.json" // Passphrase size - 20 bytes is 160 bits to satisfy: // https://tools.ietf.org/html/rfc6749#section-10.10 encryptionPassphraseSize = 20 - // podNamespace ENV should be set in the cephcsi container - podNamespace = "POD_NAMESPACE" - - // kmsConfigMapName env to read a ConfigMap by name - kmsConfigMapName = "KMS_CONFIGMAP_NAME" - - // defaultConfigMapToRead default ConfigMap name to fetch kms connection details - defaultConfigMapToRead = "csi-kms-connection-details" ) var ( @@ -183,68 +170,6 @@ func (i integratedDEK) DecryptDEK(volumeID, encyptedDEK string) (string, error) return encyptedDEK, nil } -// GetKMS returns an instance of Key Management System. -// -// - tenant is the owner of the Volume, used to fetch the Vault Token from the -// Kubernetes Namespace where the PVC lives -// - kmsID is the service name of the KMS configuration -// - secrets contain additional details, like TLS certificates to connect to -// the KMS -func GetKMS(tenant, kmsID string, secrets map[string]string) (EncryptionKMS, error) { - if kmsID == "" || kmsID == defaultKMSType { - return initSecretsKMS(secrets) - } - var config map[string]interface{} - // #nosec - content, err := ioutil.ReadFile(kmsConfigPath) - if err != nil { - if !os.IsNotExist(err) { - return nil, fmt.Errorf("failed to read kms configuration from %s: %w", - kmsConfigPath, err) - } - // If the configmap is not mounted to the CSI pods read the configmap - // the kubernetes. - namespace := os.Getenv(podNamespace) - if namespace == "" { - return nil, fmt.Errorf("%q is not set", podNamespace) - } - name := os.Getenv(kmsConfigMapName) - if name == "" { - name = defaultConfigMapToRead - } - config, err = getVaultConfiguration(namespace, name) - if err != nil { - return nil, fmt.Errorf("failed to read kms configuration from configmap %s in namespace %s: %w", - namespace, name, err) - } - } else { - err = json.Unmarshal(content, &config) - if err != nil { - return nil, fmt.Errorf("failed to parse kms configuration: %w", err) - } - } - - kmsConfig, ok := config[kmsID].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("missing encryption KMS configuration with %s", kmsID) - } - - kmsType, ok := kmsConfig[kmsTypeKey] - if !ok { - return nil, fmt.Errorf("encryption KMS configuration for %s is missing KMS type", kmsID) - } - - switch kmsType { - case kmsTypeSecretsMetadata: - return initSecretsMetadataKMS(kmsID, secrets) - case kmsTypeVault: - return InitVaultKMS(kmsID, kmsConfig, secrets) - case kmsTypeVaultTokens: - return InitVaultTokensKMS(tenant, kmsID, kmsConfig) - } - return nil, fmt.Errorf("unknown encryption KMS type %s", kmsType) -} - // StoreNewCryptoPassphrase generates a new passphrase and saves it in the KMS. func (ve *VolumeEncryption) StoreNewCryptoPassphrase(volumeID string) error { passphrase, err := generateNewEncryptionPassphrase() diff --git a/internal/util/kms.go b/internal/util/kms.go index 76e0b578a..5e227702e 100644 --- a/internal/util/kms.go +++ b/internal/util/kms.go @@ -18,7 +18,10 @@ package util import ( "context" + "encoding/json" "fmt" + "io/ioutil" + "os" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -27,20 +30,122 @@ const ( // kmsProviderKey is the name of the KMS provider that is registered at // the kmsManager. This is used in the ConfigMap configuration options. kmsProviderKey = "KMS_PROVIDER" + // kmsTypeKey is the name of the KMS provider that is registered at + // the kmsManager. This is used in the configfile configuration + // options. + kmsTypeKey = "encryptionKMSType" + + // podNamespace ENV should be set in the cephcsi container + podNamespace = "POD_NAMESPACE" + + // kmsConfigMapName env to read a ConfigMap by name + kmsConfigMapName = "KMS_CONFIGMAP_NAME" + + // defaultConfigMapToRead default ConfigMap name to fetch kms connection details + defaultConfigMapToRead = "csi-kms-connection-details" ) -// getKMSConfig returns the (.Data) contents of the ConfigMap. +// GetKMS returns an instance of Key Management System. // -// FIXME: Ceph-CSI should not talk to Kubernetes directly. -func getKMSConfig(ns, configmap string) (map[string]string, error) { - c := NewK8sClient() - cm, err := c.CoreV1().ConfigMaps(ns).Get(context.Background(), - configmap, metav1.GetOptions{}) +// - tenant is the owner of the Volume, used to fetch the Vault Token from the +// Kubernetes Namespace where the PVC lives +// - kmsID is the service name of the KMS configuration +// - secrets contain additional details, like TLS certificates to connect to +// the KMS +func GetKMS(tenant, kmsID string, secrets map[string]string) (EncryptionKMS, error) { + if kmsID == "" || kmsID == defaultKMSType { + return initSecretsKMS(secrets) + } + + config, err := getKMSConfiguration() if err != nil { return nil, err } - return cm.Data, nil + // config contains a list of KMS connections, indexed by kmsID + section, ok := config[kmsID] + if !ok { + return nil, fmt.Errorf("could not get KMS configuration "+ + "for %q", kmsID) + } + + // kmsConfig can have additional sub-sections + kmsConfig, ok := section.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("failed to convert KMS configuration "+ + "section: %s", kmsID) + } + + return kmsManager.buildKMS(kmsID, tenant, kmsConfig, secrets) +} + +// getKMSConfiguration reads the configuration file from the filesystem, or if +// that fails the ConfigMap directly. The returned map contains all the KMS +// configuration sections, each keyed by its own kmsID. +func getKMSConfiguration() (map[string]interface{}, error) { + var config map[string]interface{} + // #nosec + content, err := ioutil.ReadFile(kmsConfigPath) + if err == nil { + // kmsConfigPath exists and was successfully read + err = json.Unmarshal(content, &config) + if err != nil { + return nil, fmt.Errorf("failed to parse KMS "+ + "configuration: %w", err) + } + } else { + // an error occurred while reading kmsConfigPath + if !os.IsNotExist(err) { + return nil, fmt.Errorf("failed to read KMS "+ + "configuration from %s: %w", kmsConfigPath, + err) + } + + // If the configmap is not mounted to the CSI pods read the + // configmap the kubernetes. + config, err = getKMSConfigMap() + if err != nil { + return nil, err + } + } + + return config, nil +} + +// getKMSConfigMap returns the contents of the ConfigMap. +// +// FIXME: Ceph-CSI should not talk to Kubernetes directly. +func getKMSConfigMap() (map[string]interface{}, error) { + ns := os.Getenv(podNamespace) + if ns == "" { + return nil, fmt.Errorf("%q is not set in the environment", + podNamespace) + } + cmName := os.Getenv(kmsConfigMapName) + if cmName == "" { + cmName = defaultConfigMapToRead + } + + c := NewK8sClient() + cm, err := c.CoreV1().ConfigMaps(ns).Get(context.Background(), + cmName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + // convert cm.Data from map[string]interface{} + kmsConfig := make(map[string]interface{}) + for kmsID, data := range cm.BinaryData { + section := make(map[string]interface{}) + err = json.Unmarshal(data, §ion) + if err != nil { + return nil, fmt.Errorf("could not convert contents "+ + "of %q to s config section", kmsID) + } + kmsConfig[kmsID] = section + } + + return kmsConfig, nil } // getKMSProvider inspects the configuration and tries to identify what @@ -76,7 +181,7 @@ func getKMSProvider(config map[string]interface{}) (string, error) { // KMSInitializerArgs get passed to KMSInitializerFunc when a new instance of a // KMSProvider is initialized. type KMSInitializerArgs struct { - Id, Tenant string + ID, Tenant string Config map[string]interface{} Secrets map[string]string } @@ -120,7 +225,12 @@ func RegisterKMSProvider(provider KMSProvider) bool { return true } -func (kf *kmsProviderList) buildKMS(providerName, kmsID, tenant string, config map[string]interface{}, secrets map[string]string) (EncryptionKMS, error) { +func (kf *kmsProviderList) buildKMS(kmsID, tenant string, config map[string]interface{}, secrets map[string]string) (EncryptionKMS, error) { + providerName, err := getKMSProvider(config) + if err != nil { + return nil, err + } + provider, ok := kf.providers[providerName] if !ok { return nil, fmt.Errorf("could not find KMS provider %q", @@ -128,7 +238,7 @@ func (kf *kmsProviderList) buildKMS(providerName, kmsID, tenant string, config m } return provider.Initializer(KMSInitializerArgs{ - Id: kmsID, + ID: kmsID, Tenant: tenant, Config: config, Secrets: secrets, diff --git a/internal/util/kms_test.go b/internal/util/kms_test.go index d52748130..c956fd19b 100644 --- a/internal/util/kms_test.go +++ b/internal/util/kms_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" ) -func noinitKMS(id, tenant string, config map[string]interface{}, secrets map[string]string) (EncryptionKMS, error) { +func noinitKMS(args KMSInitializerArgs) (EncryptionKMS, error) { return nil, nil } diff --git a/internal/util/secretskms.go b/internal/util/secretskms.go index ec1544f78..94ac4c375 100644 --- a/internal/util/secretskms.go +++ b/internal/util/secretskms.go @@ -93,11 +93,16 @@ type SecretsMetadataKMS struct { encryptionKMSID string } +var _ = RegisterKMSProvider(KMSProvider{ + UniqueID: kmsTypeSecretsMetadata, + Initializer: initSecretsMetadataKMS, +}) + // initSecretsMetadataKMS initializes a SecretsMetadataKMS that wraps a // SecretsKMS, so that the passphrase from the StorageClass secrets can be used // for encrypting/decrypting DEKs that are stored in a detached DEKStore. -func initSecretsMetadataKMS(encryptionKMSID string, secrets map[string]string) (EncryptionKMS, error) { - eKMS, err := initSecretsKMS(secrets) +func initSecretsMetadataKMS(args KMSInitializerArgs) (EncryptionKMS, error) { + eKMS, err := initSecretsKMS(args.Secrets) if err != nil { return nil, err } @@ -109,7 +114,7 @@ func initSecretsMetadataKMS(encryptionKMSID string, secrets map[string]string) ( smKMS := SecretsMetadataKMS{} smKMS.SecretsKMS = sKMS - smKMS.encryptionKMSID = encryptionKMSID + smKMS.encryptionKMSID = args.ID return smKMS, nil } diff --git a/internal/util/secretskms_test.go b/internal/util/secretskms_test.go index 75ff71b90..9da0c0d7b 100644 --- a/internal/util/secretskms_test.go +++ b/internal/util/secretskms_test.go @@ -41,17 +41,22 @@ func TestGenerateCipher(t *testing.T) { } func TestInitSecretsMetadataKMS(t *testing.T) { - secrets := map[string]string{} + args := KMSInitializerArgs{ + ID: "secrets-metadata-unit-test", + Tenant: "tenant", + Config: nil, + Secrets: map[string]string{}, + } // passphrase it not set, init should fail - kms, err := initSecretsMetadataKMS("secrets-metadata-unit-test", secrets) + kms, err := initSecretsMetadataKMS(args) assert.Error(t, err) assert.Nil(t, kms) // set a passphrase to get a working KMS - secrets[encryptionPassphraseKey] = "my-passphrase-from-kubernetes" + args.Secrets[encryptionPassphraseKey] = "my-passphrase-from-kubernetes" - kms, err = initSecretsMetadataKMS("secrets-metadata-unit-test", secrets) + kms, err = initSecretsMetadataKMS(args) assert.NoError(t, err) require.NotNil(t, kms) assert.Equal(t, "secrets-metadata-unit-test", kms.GetID()) @@ -62,9 +67,15 @@ func TestWorkflowSecretsMetadataKMS(t *testing.T) { secrets := map[string]string{ encryptionPassphraseKey: "my-passphrase-from-kubernetes", } + args := KMSInitializerArgs{ + ID: "secrets-metadata-unit-test", + Tenant: "tenant", + Config: nil, + Secrets: secrets, + } volumeID := "csi-vol-1b00f5f8-b1c1-11e9-8421-9243c1f659f0" - kms, err := initSecretsMetadataKMS("secrets-metadata-unit-test", secrets) + kms, err := initSecretsMetadataKMS(args) assert.NoError(t, err) require.NotNil(t, kms) @@ -90,3 +101,8 @@ func TestWorkflowSecretsMetadataKMS(t *testing.T) { assert.NotEqual(t, "", decryptedDEK) assert.Equal(t, plainDEK, decryptedDEK) } + +func TestSecretsMetadataKMSRegistered(t *testing.T) { + _, ok := kmsManager.providers[kmsTypeSecretsMetadata] + assert.True(t, ok) +} diff --git a/internal/util/vault.go b/internal/util/vault.go index 97766a19e..5977fb07a 100644 --- a/internal/util/vault.go +++ b/internal/util/vault.go @@ -260,21 +260,26 @@ func (vc *vaultConnection) Destroy() { } } +var _ = RegisterKMSProvider(KMSProvider{ + UniqueID: kmsTypeVault, + Initializer: initVaultKMS, +}) + // InitVaultKMS returns an interface to HashiCorp Vault KMS. -func InitVaultKMS(kmsID string, config map[string]interface{}, secrets map[string]string) (EncryptionKMS, error) { +func initVaultKMS(args KMSInitializerArgs) (EncryptionKMS, error) { kms := &VaultKMS{} - err := kms.initConnection(kmsID, config) + err := kms.initConnection(args.ID, args.Config) if err != nil { return nil, fmt.Errorf("failed to initialize Vault connection: %w", err) } - err = kms.initCertificates(config, secrets) + err = kms.initCertificates(args.Config, args.Secrets) if err != nil { return nil, fmt.Errorf("failed to initialize Vault certificates: %w", err) } vaultAuthPath := vaultDefaultAuthPath - err = setConfigString(&vaultAuthPath, config, "vaultAuthPath") + err = setConfigString(&vaultAuthPath, args.Config, "vaultAuthPath") if err != nil { return nil, err } @@ -285,7 +290,7 @@ func InitVaultKMS(kmsID string, config map[string]interface{}, secrets map[strin } vaultRole := vaultDefaultRole - err = setConfigString(&vaultRole, config, "vaultRole") + err = setConfigString(&vaultRole, args.Config, "vaultRole") if err != nil { return nil, err } @@ -293,7 +298,7 @@ func InitVaultKMS(kmsID string, config map[string]interface{}, secrets map[strin // vault.VaultBackendPathKey is "secret/" by default, use vaultPassphraseRoot if configured vaultPassphraseRoot := "" - err = setConfigString(&vaultPassphraseRoot, config, "vaultPassphraseRoot") + err = setConfigString(&vaultPassphraseRoot, args.Config, "vaultPassphraseRoot") if err == nil { // the old example did have "/v1/secret/", convert that format if strings.HasPrefix(vaultPassphraseRoot, "/v1/") { @@ -306,7 +311,7 @@ func InitVaultKMS(kmsID string, config map[string]interface{}, secrets map[strin } kms.vaultPassphrasePath = vaultDefaultPassphrasePath - err = setConfigString(&kms.vaultPassphrasePath, config, "vaultPassphrasePath") + err = setConfigString(&kms.vaultPassphrasePath, args.Config, "vaultPassphrasePath") if err != nil { return nil, err } diff --git a/internal/util/vault_test.go b/internal/util/vault_test.go index ac1e47962..946ecacc9 100644 --- a/internal/util/vault_test.go +++ b/internal/util/vault_test.go @@ -20,6 +20,8 @@ import ( "errors" "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestDetectAuthMountPath(t *testing.T) { @@ -95,3 +97,8 @@ func TestSetConfigString(t *testing.T) { t.Error("optionDefaultOverload should have been updated") } } + +func TestVaultKMSRegistered(t *testing.T) { + _, ok := kmsManager.providers[kmsTypeVault] + assert.True(t, ok) +} diff --git a/internal/util/vault_tokens.go b/internal/util/vault_tokens.go index 36ae5ea2e..f9c93d6a4 100644 --- a/internal/util/vault_tokens.go +++ b/internal/util/vault_tokens.go @@ -96,38 +96,44 @@ func (v *vaultTokenConf) convertStdVaultToCSIConfig(s *standardVault) { } } -// getVaultConfiguration fetches the vault configuration from the kubernetes -// configmap and converts the standard vault configuration (see json tag of -// standardVault structure) to the CSI vault configuration. -func getVaultConfiguration(namespace, name string) (map[string]interface{}, error) { - c := NewK8sClient() - cm, err := c.CoreV1().ConfigMaps(namespace).Get(context.Background(), name, metav1.GetOptions{}) +// convertConfig takes the keys/values in standard Vault environment variable +// format, and converts them to the format that is used in the configuration +// file. +// This uses JSON marshaling and unmarshaling to map the Vault environment +// configuration into bytes, then in the standardVault struct, which is passed +// through convertStdVaultToCSIConfig before converting back to a +// map[string]interface{} configuration. +// +// FIXME: this can surely be simplified?! +func transformConfig(svMap map[string]interface{}) (map[string]interface{}, error) { + // convert the map to JSON + data, err := json.Marshal(svMap) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to convert config %T to JSON: %w", svMap, err) } - config := make(map[string]interface{}) - // convert the standard vault configuration to CSI vault configuration and - // store it in the map that CSI expects - for k, v := range cm.Data { - sv := &standardVault{} - err = json.Unmarshal([]byte(v), sv) - if err != nil { - return nil, fmt.Errorf("failed to Unmarshal the vault configuration for %q: %w", k, err) - } - vc := vaultTokenConf{} - vc.convertStdVaultToCSIConfig(sv) - data, err := json.Marshal(vc) - if err != nil { - return nil, fmt.Errorf("failed to Marshal the CSI vault configuration for %q: %w", k, err) - } - jsonMap := make(map[string]interface{}) - err = json.Unmarshal(data, &jsonMap) - if err != nil { - return nil, fmt.Errorf("failed to Unmarshal the CSI vault configuration for %q: %w", k, err) - } - config[k] = jsonMap + + // convert the JSON back to a standardVault struct + sv := &standardVault{} + err = json.Unmarshal(data, sv) + if err != nil { + return nil, fmt.Errorf("failed to Unmarshal the vault configuration: %w", err) } - return config, nil + + // convert the standardVault struct to a vaultTokenConf struct + vc := vaultTokenConf{} + vc.convertStdVaultToCSIConfig(sv) + data, err = json.Marshal(vc) + if err != nil { + return nil, fmt.Errorf("failed to Marshal the CSI vault configuration: %w", err) + } + + // convert the vaultTokenConf struct to a map[string]interface{} + jsonMap := make(map[string]interface{}) + err = json.Unmarshal(data, &jsonMap) + if err != nil { + return nil, fmt.Errorf("failed to Unmarshal the CSI vault configuration: %w", err) + } + return jsonMap, nil } /* @@ -171,11 +177,29 @@ type VaultTokensKMS struct { TokenName string } +var _ = RegisterKMSProvider(KMSProvider{ + UniqueID: kmsTypeVaultTokens, + Initializer: initVaultTokensKMS, +}) + // InitVaultTokensKMS returns an interface to HashiCorp Vault KMS. -func InitVaultTokensKMS(tenant, kmsID string, config map[string]interface{}) (EncryptionKMS, error) { +// InitVaultTokensKMS returns an interface to HashiCorp Vault KMS. +func initVaultTokensKMS(args KMSInitializerArgs) (EncryptionKMS, error) { + var err error + + config := args.Config + _, ok := config[kmsProviderKey] + if ok { + // configuration comes from the ConfigMap, needs to be + // converted to vaultTokenConf type + config, err = transformConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to convert configuration: %w", err) + } + } + kms := &VaultTokensKMS{} - kms.Tenant = tenant - err := kms.initConnection(kmsID, config) + err = kms.initConnection(args.ID, args.Config) if err != nil { return nil, fmt.Errorf("failed to initialize Vault connection: %w", err) } @@ -190,14 +214,15 @@ func InitVaultTokensKMS(tenant, kmsID string, config map[string]interface{}) (En } // fetch the configuration for the tenant - if tenant != "" { + if args.Tenant != "" { + kms.Tenant = args.Tenant tenantsMap, ok := config["tenants"] if ok { // tenants is a map per tenant, containing key/values tenants, ok := tenantsMap.(map[string]map[string]interface{}) if ok { // get the map for the tenant of the current operation - tenantConfig, ok := tenants[tenant] + tenantConfig, ok := tenants[args.Tenant] if ok { // override connection details from the tenant err = kms.parseConfig(tenantConfig) @@ -216,9 +241,9 @@ func InitVaultTokensKMS(tenant, kmsID string, config map[string]interface{}) (En // fetch the Vault Token from the Secret (TokenName) in the Kubernetes // Namespace (tenant) - kms.vaultConfig[api.EnvVaultToken], err = getToken(tenant, kms.TokenName) + kms.vaultConfig[api.EnvVaultToken], err = getToken(args.Tenant, kms.TokenName) if err != nil { - return nil, fmt.Errorf("failed fetching token from %s/%s: %w", tenant, kms.TokenName, err) + return nil, fmt.Errorf("failed fetching token from %s/%s: %w", args.Tenant, kms.TokenName, err) } err = kms.initCertificates(config) diff --git a/internal/util/vault_tokens_test.go b/internal/util/vault_tokens_test.go index 71c0eefc6..af2d425b3 100644 --- a/internal/util/vault_tokens_test.go +++ b/internal/util/vault_tokens_test.go @@ -21,6 +21,9 @@ import ( "errors" "strings" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestParseConfig(t *testing.T) { @@ -34,7 +37,7 @@ func TestParseConfig(t *testing.T) { t.Errorf("unexpected error (%T): %s", err, err) } - // fill default options (normally done in InitVaultTokensKMS) + // fill default options (normally done in initVaultTokensKMS) config["vaultAddress"] = "https://vault.default.cluster.svc" config["tenantConfigName"] = vaultTokensDefaultConfigName config["tenantTokenName"] = vaultTokensDefaultTokenName @@ -65,7 +68,7 @@ func TestParseConfig(t *testing.T) { // TestInitVaultTokensKMS verifies that passing partial and complex // configurations get applied correctly. // -// When vault.New() is called at the end of InitVaultTokensKMS(), errors will +// When vault.New() is called at the end of initVaultTokensKMS(), errors will // mention the missing VAULT_TOKEN, and that is expected. func TestInitVaultTokensKMS(t *testing.T) { if true { @@ -74,39 +77,44 @@ func TestInitVaultTokensKMS(t *testing.T) { return } - config := make(map[string]interface{}) + args := KMSInitializerArgs{ + ID: "vault-tokens-config", + Tenant: "bob", + Config: make(map[string]interface{}), + Secrets: nil, + } // empty config map - _, err := InitVaultTokensKMS("bob", "vault-tokens-config", config) + _, err := initVaultTokensKMS(args) if !errors.Is(err, errConfigOptionMissing) { t.Errorf("unexpected error (%T): %s", err, err) } // fill required options - config["vaultAddress"] = "https://vault.default.cluster.svc" + args.Config["vaultAddress"] = "https://vault.default.cluster.svc" // parsing with all required options - _, err = InitVaultTokensKMS("bob", "vault-tokens-config", config) + _, err = initVaultTokensKMS(args) if err != nil && !strings.Contains(err.Error(), "VAULT_TOKEN") { t.Errorf("unexpected error: %s", err) } // fill tenants tenants := make(map[string]interface{}) - config["tenants"] = tenants + args.Config["tenants"] = tenants // empty tenants list - _, err = InitVaultTokensKMS("bob", "vault-tokens-config", config) + _, err = initVaultTokensKMS(args) if err != nil && !strings.Contains(err.Error(), "VAULT_TOKEN") { t.Errorf("unexpected error: %s", err) } // add tenant "bob" bob := make(map[string]interface{}) - config["tenants"].(map[string]interface{})["bob"] = bob bob["vaultAddress"] = "https://vault.bob.example.org" + args.Config["tenants"].(map[string]interface{})["bob"] = bob - _, err = InitVaultTokensKMS("bob", "vault-tokens-config", config) + _, err = initVaultTokensKMS(args) if err != nil && !strings.Contains(err.Error(), "VAULT_TOKEN") { t.Errorf("unexpected error: %s", err) } @@ -158,3 +166,33 @@ func TestStdVaultToCSIConfig(t *testing.T) { t.Errorf("unexpected value for VaultCAVerify: %s", v.VaultCAVerify) } } + +func TestTransformConfig(t *testing.T) { + cm := make(map[string]interface{}) + cm["KMS_PROVIDER"] = "vaulttokens" + cm["VAULT_ADDR"] = "https://vault.example.com" + cm["VAULT_BACKEND_PATH"] = "/secret" + cm["VAULT_CACERT"] = "" + cm["VAULT_TLS_SERVER_NAME"] = "vault.example.com" + cm["VAULT_CLIENT_CERT"] = "" + cm["VAULT_CLIENT_KEY"] = "" + cm["VAULT_NAMESPACE"] = "a-department" + cm["VAULT_SKIP_VERIFY"] = "true" // inverse of "vaultCAVerify" + + config, err := transformConfig(cm) + require.NoError(t, err) + assert.Equal(t, config["encryptionKMSType"], cm["KMS_PROVIDER"]) + assert.Equal(t, config["vaultAddress"], cm["VAULT_ADDR"]) + assert.Equal(t, config["vaultBackendPath"], cm["VAULT_BACKEND_PATH"]) + assert.Equal(t, config["vaultCAFromSecret"], cm["VAULT_CACERT"]) + assert.Equal(t, config["vaultTLSServerName"], cm["VAULT_TLS_SERVER_NAME"]) + assert.Equal(t, config["vaultClientCertFromSecret"], cm["VAULT_CLIENT_CERT"]) + assert.Equal(t, config["vaultClientCertKeyFromSecret"], cm["VAULT_CLIENT_KEY"]) + assert.Equal(t, config["vaultNamespace"], cm["VAULT_NAMESPACE"]) + assert.Equal(t, config["vaultCAVerify"], "false") +} + +func TestVaultTokensKMSRegistered(t *testing.T) { + _, ok := kmsManager.providers[kmsTypeVaultTokens] + assert.True(t, ok) +}