From e4b16a5c7204bc2afbdfb32c0cd9ea9ac68b2a54 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 15 Dec 2020 09:11:53 +0100 Subject: [PATCH] util: allow tenants to (re)configure VaultTokens settings A tenant can place a ConfigMap in their Kubernetes Namespace with configuration options that differ from the global (by the Storage Admin set) values. The ConfigMap needs to be located in the Tenants namespace, as described in the documentation See-also: docs/design/proposals/encryption-with-vault-tokens.md Signed-off-by: Niels de Vos --- examples/kms/vault/tenant-config.yaml | 12 +++++ internal/util/vault_tokens.go | 64 +++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 examples/kms/vault/tenant-config.yaml diff --git a/examples/kms/vault/tenant-config.yaml b/examples/kms/vault/tenant-config.yaml new file mode 100644 index 000000000..202c71909 --- /dev/null +++ b/examples/kms/vault/tenant-config.yaml @@ -0,0 +1,12 @@ +--- +# This is an optional (re)configuration of the connection to the Vault +# Service that can be created in a Kubernetes Namespace for a Tenant. +apiVersion: v1 +kind: ConfigMap +metadata: + name: ceph-csi-kms-config +data: + vaultAddress: "http://vault.default.svc.cluster.local:8200" + vaultBackendPath: "secret/" + vaultTLSServerName: "vault.default.svc.cluster.local" + vaultCAVerify: "false" diff --git a/internal/util/vault_tokens.go b/internal/util/vault_tokens.go index 3d41691f1..2ce9d83d8 100644 --- a/internal/util/vault_tokens.go +++ b/internal/util/vault_tokens.go @@ -127,6 +127,11 @@ func InitVaultTokensKMS(tenant, kmsID string, config map[string]interface{}) (En } } } + + err = kms.parseTenantConfig() + if err != nil { + return nil, fmt.Errorf("failed to parse config for tenant: %w", err) + } } // fetch the Vault Token from the Secret (TokenName) in the Kubernetes @@ -339,3 +344,62 @@ func getCertificate(tenant, secretName, key string) (string, error) { return string(cert), nil } + +// isTenantConfigOption return true if a tenant may (re)configure the option in +// their own ConfigMap, false otherwise. +func isTenantConfigOption(opt string) bool { + switch opt { + case "vaultAddress": + case "vaultBackendPath": + case "vaultTLSServerName": + case "vaultCAFromSecret": + case "vaultCAVerify": + default: + return false + } + + return true +} + +// parseTenantConfig gets the optional ConfigMap from the Tenants namespace, +// and applies the allowable options (see isTenantConfigOption) to the KMS +// configuration. +func (kms *VaultTokensKMS) parseTenantConfig() error { + if kms.Tenant == "" || kms.ConfigName == "" { + return nil + } + + // fetch the ConfigMap from the tanants namespace + c := NewK8sClient() + cm, err := c.CoreV1().ConfigMaps(kms.Tenant).Get(context.TODO(), + kms.ConfigName, metav1.GetOptions{}) + if apierrs.IsNotFound(err) { + // the tenant did not (re)configure any options + return nil + } else if err != nil { + return fmt.Errorf("failed to get config (%s) for tenant (%s): %w", + kms.ConfigName, kms.Tenant, err) + } + + // create a new map with config options, but only include the options + // that a tenant may (re)configure + config := make(map[string]interface{}) + for k, v := range cm.Data { + if isTenantConfigOption(k) { + config[k] = v + } // else: silently ignore the option + } + if len(config) == 0 { + // no options configured by the tenant + return nil + } + + // apply the configuration options from the tenant + err = kms.parseConfig(config) + if err != nil { + return fmt.Errorf("failed to parse config (%s) for tenant (%s): %w", + kms.ConfigName, kms.Tenant, err) + } + + return nil +}