From 68a32c06b4d69970ac2489ff5177d5703ca604cd Mon Sep 17 00:00:00 2001 From: Saksham Sharma Date: Thu, 27 Jul 2017 16:06:20 -0700 Subject: [PATCH] Add cloudprovidedkms provider support --- .../server/options/encryptionconfig/config.go | 28 +++++--- .../encryptionconfig/encryptionconfig_test.go | 64 +++++++++++++++++++ .../options/encryptionconfig/plugins.go | 4 ++ .../server/options/encryptionconfig/types.go | 20 +++++- 4 files changed, 105 insertions(+), 11 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index 8d86339b09..fd5421b1ac 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -36,10 +36,11 @@ import ( ) const ( - aesCBCTransformerPrefixV1 = "k8s:enc:aescbc:v1:" - aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:" - secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:" - kmsTransformerPrefixV1 = "k8s:enc:kms:v1:" + aesCBCTransformerPrefixV1 = "k8s:enc:aescbc:v1:" + aesGCMTransformerPrefixV1 = "k8s:enc:aesgcm:v1:" + secretboxTransformerPrefixV1 = "k8s:enc:secretbox:v1:" + kmsTransformerPrefixV1 = "k8s:enc:kms:v1:" + cloudProvidedKMSTransformerPrefixV1 = "k8s:enc:cloudprovidedkms:v1:" ) // GetTransformerOverrides returns the transformer overrides by reading and parsing the encryption provider configuration file @@ -150,7 +151,6 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e if found == true { return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") } - f, err := os.Open(provider.KMS.ConfigFile) if err != nil { return nil, fmt.Errorf("error opening KMS provider configuration file %q: %v", provider.KMS.ConfigFile, err) @@ -163,7 +163,19 @@ func GetPrefixTransformers(config *ResourceConfig) ([]value.PrefixTransformer, e if pluginFound == false { return nil, fmt.Errorf("KMS plugin %q not found", provider.KMS.Name) } - transformer, err = getEnvelopePrefixTransformer(provider.KMS, envelopeService) + transformer, err = getEnvelopePrefixTransformer(provider.KMS.CoreKMSConfig, envelopeService, kmsTransformerPrefixV1) + found = true + } + + if provider.CloudProvidedKMS != nil { + if found == true { + return nil, fmt.Errorf("more than one provider specified in a single element, should split into different list elements") + } + envelopeService, err := KMSPluginRegistry.getCloudProvidedPlugin(provider.CloudProvidedKMS.Name) + if err != nil { + return nil, fmt.Errorf("could not configure Cloud-Provided KMS plugin %q, %v", provider.CloudProvidedKMS.Name, err) + } + transformer, err = getEnvelopePrefixTransformer(provider.CloudProvidedKMS.CoreKMSConfig, envelopeService, cloudProvidedKMSTransformerPrefixV1) found = true } @@ -284,13 +296,13 @@ func GetSecretboxPrefixTransformer(config *SecretboxConfig) (value.PrefixTransfo // getEnvelopePrefixTransformer returns a prefix transformer from the provided config. // envelopeService is used as the root of trust. -func getEnvelopePrefixTransformer(config *KMSConfig, envelopeService envelope.Service) (value.PrefixTransformer, error) { +func getEnvelopePrefixTransformer(config *CoreKMSConfig, envelopeService envelope.Service, prefix string) (value.PrefixTransformer, error) { envelopeTransformer, err := envelope.NewEnvelopeTransformer(envelopeService, config.CacheSize, aestransformer.NewCBCTransformer) if err != nil { return value.PrefixTransformer{}, err } return value.PrefixTransformer{ Transformer: envelopeTransformer, - Prefix: []byte(kmsTransformerPrefixV1 + config.Name + ":"), + Prefix: []byte(prefix + config.Name + ":"), }, nil } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go index 3bb5b68804..22bb3b3876 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/encryptionconfig_test.go @@ -58,6 +58,9 @@ resources: name: testprovider configfile: testproviderconfig cachesize: 10 + - cloudprovidedkms: + name: testprovider + cachesize: 10 - aescbc: keys: - name: key1 @@ -97,6 +100,9 @@ resources: secret: c2VjcmV0IGlzIHNlY3VyZQ== - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== + - cloudprovidedkms: + name: testprovider + cachesize: 10 - identity: {} ` @@ -118,6 +124,9 @@ resources: configfile: testproviderconfig cachesize: 10 - identity: {} + - cloudprovidedkms: + name: testprovider + cachesize: 10 - secretbox: keys: - name: key1 @@ -141,6 +150,9 @@ resources: keys: - name: key1 secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - cloudprovidedkms: + name: testprovider + cachesize: 10 - aescbc: keys: - name: key1 @@ -182,6 +194,45 @@ resources: - name: key2 secret: dGhpcyBpcyBwYXNzd29yZA== - identity: {} + - cloudprovidedkms: + name: testprovider + cachesize: 10 + - aesgcm: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== +` + + correctConfigWithCloudProvidedKMSFirst = ` +kind: EncryptionConfig +apiVersion: v1 +resources: + - resources: + - secrets + providers: + - cloudprovidedkms: + name: testprovider + cachesize: 10 + - kms: + name: testprovider + configfile: testproviderconfig + cachesize: 10 + - secretbox: + keys: + - name: key1 + secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY= + - aescbc: + keys: + - name: key1 + secret: c2VjcmV0IGlzIHNlY3VyZQ== + - name: key2 + secret: dGhpcyBpcyBwYXNzd29yZA== + - identity: {} + - cloudprovidedkms: + name: testprovider + cachesize: 10 - aesgcm: keys: - name: key1 @@ -252,6 +303,12 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) { KMSPluginRegistry.Register(testEnvelopeServiceProviderName, func(config io.Reader) (envelope.Service, error) { return &testEnvelopeService{}, nil }) + KMSPluginRegistry.RegisterCloudProvidedKMSPlugin(func(name string) (envelope.Service, error) { + if name == testEnvelopeServiceProviderName { + return &testEnvelopeService{}, nil + } + return nil, fmt.Errorf("no such cloud provided KMS plugin registered: %q", name) + }) // Creates compound/prefix transformers with different ordering of available transformers. // Transforms data using one of them, and tries to untransform using the others. @@ -281,12 +338,18 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) { t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithKMSFirst) } + cloudProvidedKMSFirstTransformerOverrides, err := ParseEncryptionConfiguration(strings.NewReader(correctConfigWithCloudProvidedKMSFirst)) + if err != nil { + t.Fatalf("error while parsing configuration file: %s.\nThe file was:\n%s", err, correctConfigWithCloudProvidedKMSFirst) + } + // Pick the transformer for any of the returned resources. identityFirstTransformer := identityFirstTransformerOverrides[schema.ParseGroupResource("secrets")] aesGcmFirstTransformer := aesGcmFirstTransformerOverrides[schema.ParseGroupResource("secrets")] aesCbcFirstTransformer := aesCbcFirstTransformerOverrides[schema.ParseGroupResource("secrets")] secretboxFirstTransformer := secretboxFirstTransformerOverrides[schema.ParseGroupResource("secrets")] kmsFirstTransformer := kmsFirstTransformerOverrides[schema.ParseGroupResource("secrets")] + cloudProvidedKMSFirstTransformer := cloudProvidedKMSFirstTransformerOverrides[schema.ParseGroupResource("secrets")] context := value.DefaultContext([]byte(sampleContextText)) originalText := []byte(sampleText) @@ -300,6 +363,7 @@ func TestEncryptionProviderConfigCorrect(t *testing.T) { {secretboxFirstTransformer, "secretboxFirst"}, {identityFirstTransformer, "identityFirst"}, {kmsFirstTransformer, "kmsFirst"}, + {cloudProvidedKMSFirstTransformer, "cloudProvidedKMSFirst"}, } for _, testCase := range transformers { diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go index c55e6a20dd..b45e130f20 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/plugins.go @@ -18,6 +18,7 @@ package encryptionconfig import ( "bytes" + "fmt" "io" "io/ioutil" "reflect" @@ -112,6 +113,9 @@ func (ps *KMSPlugins) fetchPluginFromRegistry(name string) (Factory, bool) { // getCloudProvidedPlugin creates an instance of the named cloud provided KMS plugin. func (ps *KMSPlugins) getCloudProvidedPlugin(name string) (envelope.Service, error) { + if ps.cloudKMS == nil { + return nil, fmt.Errorf("no cloud registered for KMS plugins") + } return ps.cloudKMS(name) } diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go index c983e942da..1e77fd0868 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/types.go @@ -45,8 +45,11 @@ type ProviderConfig struct { Secretbox *SecretboxConfig `json:"secretbox,omitempty"` // identity is the (empty) configuration for the identity transformer. Identity *IdentityConfig `json:"identity,omitempty"` - // kms contains the name and path to configuration file for a KMS based envelope transformer. + // kms contains the name, cache size and path to configuration file for a KMS based envelope transformer. KMS *KMSConfig `json:"kms,omitempty"` + // cloudProvidedKMSConfig contains the name and cache size for a KMS based envelope transformer which uses + // the KMS provided by the cloud. + CloudProvidedKMS *CloudProvidedKMSConfig `json:"cloudprovidedkms,omitempty"` } // AESConfig contains the API configuration for an AES transformer. @@ -74,13 +77,24 @@ type Key struct { // IdentityConfig is an empty struct to allow identity transformer in provider configuration. type IdentityConfig struct{} -// KMS contains the name and path to configuration file for a KMS based envelope transformer. -type KMSConfig struct { +// CoreKMSConfig contains the name and cache sized for a KMS based envelope transformer. +type CoreKMSConfig struct { // name is the name of the KMS plugin to be used. Name string `json:"name"` // cacheSize is the maximum number of secrets which are cached in memory. The default value is 1000. // +optional CacheSize int `json:"cachesize,omitempty"` +} + +// KMSConfig contains the name, cache size and path to configuration file for a KMS based envelope transformer. +type KMSConfig struct { + *CoreKMSConfig // configfile is the path to the configuration file for the named KMS provider. ConfigFile string `json:"configfile"` } + +// CloudProvidedKMSConfig contains the name and cache size for a KMS based envelope transformer which uses +// the KMS provided by the cloud. +type CloudProvidedKMSConfig struct { + *CoreKMSConfig +}