Vaultproviderspec (#1)
* Initial version of Vault KMS Provider * Renamed image file to be consistent with spec name * Brought spec inline with EnvelopeTransformer interfaces in PR 49350 * Wrap at 80
This commit is contained in:
parent
f20eb8c175
commit
40fe163224
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
|
|
@ -0,0 +1,302 @@
|
|||
# Vault based KMS provider for envelope encryption of secrets in etcd3
|
||||
|
||||
## Abstract
|
||||
|
||||
Kubernetes, starting with the release 1.7, adds Alpha support ( via PRs
|
||||
[41939](https://github.com/kubernetes/kubernetes/pull/41939) and
|
||||
[46460](https://github.com/kubernetes/kubernetes/pull/46460)) to encrypt secrets
|
||||
and resources in etcd3 via a configured Provider. This release supports three
|
||||
providers viz. aesgcm, aescbc, secretbox. These providers store the encryption
|
||||
key(s) locally in a server configuration file. The provider encrypts and
|
||||
decrypts secrets in-process. Building upon these, a KMS provider framework with
|
||||
an option to support different KMS providers like google cloud KMS is being
|
||||
added via PRs [48574](https://github.com/kubernetes/kubernetes/pull/48575) and
|
||||
[49350](https://github.com/kubernetes/kubernetes/pull/49350). The new KMS
|
||||
provider framework uses an envelope encryption scheme.
|
||||
|
||||
|
||||
This proposal adopts the KMS provider framework and adds a new KMS provider that
|
||||
uses Hashicorp Vault with a transit backend, to encrypt and decrypt the DEK
|
||||
stored in encrypted form in etcd3 along with encrypted secrets.
|
||||
|
||||
|
||||
Vault is widely used for Data encryption and securely storing secrets.
|
||||
Externalizing encryption/decryption of kubernetes secrets to vault provides
|
||||
various benefits
|
||||
|
||||
* Choice of industry standard encryption algorithms and strengths without having
|
||||
to implement specific providers for each (in K8S).
|
||||
* Reduced risk of encryption key compromise.
|
||||
* encryption key is stored and managed in Vault.
|
||||
* encryption key does not need to leave the Vault.
|
||||
* Vault provides ability to define access control suitable for a wide range of deployment scenarios and security needs.
|
||||
* Vault provides In-built auditing of vault API calls.
|
||||
* Ability for a customer already using Vault to leverage the instance to also
|
||||
secure keys used to encrypt secrets managed within a Kubernetes cluster
|
||||
* Separation of Kubernetes cluster management responsibilities from encryption key
|
||||
management and administration allowing an organization to better leverage
|
||||
competencies and skills within the DevOps teams.
|
||||
|
||||
Note, that the Vault Provider in this proposal
|
||||
|
||||
1. **requires** Vault transit backend.
|
||||
2. supports a wide range of authentication backends supported by vault (see below
|
||||
for exact list).
|
||||
3. does not depend on specific storage backend or any other specific configuration.
|
||||
|
||||
This proposal assumes familiarity with Vault and the transit back-end.
|
||||
|
||||
## High level design
|
||||
As with existing providers, the Vault based provider will implement the
|
||||
interface ``envelope.Service``. Based on value of *name* in the KMS provider
|
||||
configuration, the ``EnvelopeTransformer`` module will use an instance of the
|
||||
Vault provider for decryption and encryption of DEK before storing and after
|
||||
reading from the storage.
|
||||
|
||||
The KEK will be stored and managed in Vault backend. The Vault based provider
|
||||
configured in KMS Transformer configuration will make REST requests to encrypt
|
||||
and decrypt DEKs over a secure channel, if TLS is enabled. KMS Transformer will
|
||||
store the DEKs in etcd in encrypted form along with encrypted secrets. As with
|
||||
existing providers, encrypted DEKs will be stored with metadata used to identify
|
||||
the provider and KEK to be used for decryption.
|
||||
|
||||
The provider will support following authentication back-ends
|
||||
|
||||
* Vault token based,
|
||||
* TLS cert based,
|
||||
* Vault AppRole based.
|
||||
|
||||
Deployers can choose an authentication mechanism best suited to their
|
||||
requirements.
|
||||
The provider will work with vault REST APIs and will not require Vault to be
|
||||
configured or deployed in any specific way other than requiring a Transit
|
||||
Backend.
|
||||
|
||||
### Diagram illustrating interfaces and implementations
|
||||
|
||||

|
||||
|
||||
### Pseudocode
|
||||
#### Prefix Metadata
|
||||
Every encrypted secret will have the following metadata prefixed.
|
||||
``k8s:enc:kms:<api-version>:vault:len(<KEK-key-name>:<KEK-key-version>:<DEK
|
||||
encrypted with KEK>):<KEK-key-name>:<KEK-key-version>:<DEK encrypted with KEK>``
|
||||
|
||||
* ``<api-version>`` represents api version in the providers configuration file.
|
||||
* ``vault`` represents the KMS service *kind* value. It is a fixed value for Vault
|
||||
based provider.
|
||||
* ``KEK-key-name`` is determined from the vault service configuration in providers
|
||||
configuration file
|
||||
* ``KEK-key-version`` is an internal identifier used by vault to identify specific
|
||||
key version used to encrypt and decrypt. Vault sends ``kek-key-version``
|
||||
prefixed with encrypted data in the response to an encrypt request. The
|
||||
``kek-key-version`` will be stored as part of prefix and returned back to Vault
|
||||
during a decrypt request.
|
||||
|
||||
Of the above metadata,
|
||||
|
||||
* ``EnvelopeTransformer`` will add
|
||||
``k8s:enc:kms:<api-version>:vault:len(<KEK-key-name>:<KEK-key-version>:<DEK
|
||||
encrypted with KEK>)``
|
||||
* while the ``vaultEnvelopeService`` will add
|
||||
``<KEK-key-name>:<KEK-key-version>:<DEK encrypted with KEK>``.
|
||||
|
||||
|
||||
#### For each write of DEK
|
||||
``EnvelopeTransformer`` will write encrypted DEK along with encrypted secret in
|
||||
etcd.
|
||||
|
||||
Here's the pseudocode for ``vaultEnvelopeService.encrypt()``, invoked on each
|
||||
write of DEK.
|
||||
|
||||
KEY_NAME = <first key-name from vault provider config>
|
||||
PLAIN_DEK = <value of DEK>
|
||||
ENCRYPTED_DEK_WITH_KEY_VERSION = encrypt(base64(PLAIN_DEK), KEY_NAME)
|
||||
|
||||
// output from vault will have an extra prefix "vault" (other than key version) which will be stripped.
|
||||
|
||||
STORED_DEK = KEY_NAME:<ENCRYPTED_DEK_WITH_KEY_VERSION>
|
||||
|
||||
#### For each read of DEK
|
||||
``EnvelopeTransformer`` will read encrypted DEK along with encrypted secret from
|
||||
etcd
|
||||
|
||||
Here's the pseudocode ``vaultEnvelopeService.decrypt()`` invoked on each read of
|
||||
DEK.
|
||||
|
||||
// parse the provider kind, key name and encrypted DEK prefixed with key version
|
||||
KEY_NAME = //key-name from the prefix
|
||||
ENCRYPTED_DEK_WITH_KEY_VERSION = //<key version>:<encrypted DEK> from the stored value
|
||||
|
||||
// add "vault" prefix to ENCRYPTED_DEK_WITH_KEY_VERSION as required by vault decrypt API
|
||||
|
||||
base64Encoded = decrypt(vault:ENCRYPTED_DEK_WITH_KEY_VERSION, KEY_NAME)
|
||||
|
||||
PLAIN_DEK = base64.Decode(base64Encoded)
|
||||
|
||||
#### Example
|
||||
|
||||
DEK = "the quick brown fox"
|
||||
provider kind = "vault"
|
||||
api version version = "v1"
|
||||
Key name = "kube-secret-enc-key"
|
||||
key version = v1
|
||||
ciphertext returned from vault = vault:v1:aNOTZn0aUDMDbWAQL1E31tH/7zr7oslRjkSpRW0+BPdMfSJntyXZNCAwIbkTtn0=
|
||||
prefixed DEK used to tag secrets = vault:kube-secret-enc-key:v1:aNOTZn0aUDMDbWAQL1E31tH/7zr7oslRjkSpRW0+BPdMfSJntyXZNCAwIbkTtn0=
|
||||
|
||||
### Configuration
|
||||
|
||||
No new configuration file or startup parameter will be introduced.
|
||||
|
||||
The vault provider will be specified in the existing configuration file used to
|
||||
configure any of the encryption providers. The location of this configuration
|
||||
file is identified by the existing startup parameter:
|
||||
`--experimental-encryption-provider-config` .
|
||||
|
||||
Vault provider configuration will be identified by value "**vault**" for the
|
||||
``name`` attribute in ``kms`` provider.
|
||||
|
||||
The actual configuration of the vault provider will be in a separate
|
||||
configuration identified by the ``configfile`` attribute in the KMS provider.
|
||||
|
||||
Here is a sample configuration file with the vault provider configured:
|
||||
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- kms:
|
||||
name: vault
|
||||
cachesize: 10
|
||||
configfile: /home/myvault/vault-config.yaml
|
||||
|
||||
#### Minimal required Configuration
|
||||
The Vault based Provider needs the following configuration elements, at a
|
||||
minimum:
|
||||
|
||||
1. ``addr`` Vault service base endpoint eg. https://example.com:8200
|
||||
2. ``key-names`` list of names of the keys in Vault to be used. eg: key-name:
|
||||
kube-secret-enc-key.
|
||||
|
||||
Note : key name does not need to be changed if key is rotated in Vault, the
|
||||
rotated key is identified by key version which is prefix to ciphertext.
|
||||
|
||||
A new key can be added in the list. Encryption will be done using the first key
|
||||
in the list. Decryption can happen using any of the keys in the list based on
|
||||
the prefix to the encrypted DEK stored in etcd
|
||||
|
||||
#### Authentication Configuration
|
||||
##### Vault Server Authentication
|
||||
|
||||
For the Kubernetes cluster to authenticate the vault server, if TLS is enabled :
|
||||
1. ``ca-cert`` location of x509 certificate to authenticate the vault server eg:
|
||||
``/var/run/kubernetes/ssl/vault.crt``
|
||||
|
||||
##### Client Authentication Choices
|
||||
|
||||
For client authentication, one of following **must** be used: (provider will
|
||||
reject the configuration if parameters for more than one authentication backends
|
||||
are specified )
|
||||
|
||||
###### X509 based authentication
|
||||
1. ``client-cert``: location of x509 certificate to authenticate kubernetes API
|
||||
server to vault server eg. ``/var/run/kubernetes/ssl/valut-client-cert.pem``
|
||||
2. ``client-key`` : location of x509 private key to authenticate kubernetes API
|
||||
server to vault server eg. ``/var/run/kubernetes/ssl/vault-client-key.pem``
|
||||
|
||||
Here's a sample configuration file with ``client-cert``:
|
||||
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- kms:
|
||||
kind: vault
|
||||
apiVersion: v1
|
||||
cache-size: 100
|
||||
config:
|
||||
addr: https://localhost:8200
|
||||
key-names:
|
||||
- kube-secret-enc-key
|
||||
ca-cert:/var/run/kubernetes/ssl/vault.crt
|
||||
client-cert:/var/run/kubernetes/ssl/vault-client-cert.pem
|
||||
client-key:/var/run/kubernetes/ssl/vault-client-key.pem
|
||||
|
||||
###### Vault token based authentication
|
||||
1. ``token`` : limited access vault token required by kubernetes API sever to
|
||||
authenticate itself while making requests to vault eg:
|
||||
8dad1053-4a4e-f359-2eab-d57968eb277f
|
||||
|
||||
Here's a sample configuration file when using a Vault Token for authenticating
|
||||
the Kubernetes cluster as a client to Vault:
|
||||
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- kms:
|
||||
kind: vault
|
||||
apiVersion: v1
|
||||
cache-size: 100
|
||||
config:
|
||||
addr: https://localhost:8200
|
||||
key-names:
|
||||
- kube-secret-enc-key
|
||||
ca-cert:/var/run/kubernetes/ssl/vault.crt
|
||||
token: 8dad1053-4a4e-f359-2eab-d57968eb277f
|
||||
|
||||
###### Vault AppRole based authentication
|
||||
1. ``role-id`` : RoleID of the AppRole
|
||||
2. ``secret-id`` : secret Id only if associated with the appRole.
|
||||
|
||||
Here's a sample configuration file with Vault AppRole
|
||||
kind: EncryptionConfig
|
||||
apiVersion: v1
|
||||
resources:
|
||||
- resources:
|
||||
- secrets
|
||||
providers:
|
||||
- kms:
|
||||
kind: vault
|
||||
apiVersion: v1
|
||||
cache-size: 100
|
||||
config:
|
||||
addr: https://localhost:8200
|
||||
key-names:
|
||||
- kube-secret-enc-key
|
||||
ca-cert: /var/run/kubernetes/ssl/vault.crt
|
||||
role-id: db02de05-fa39-4855-059b-67221c5c2f63
|
||||
|
||||
## Key Generation and rotation
|
||||
The KEK is generated in Vault and rotated using direct API call or CLI to Vault
|
||||
itself. The Key never leaves the vault.
|
||||
|
||||
Note that when a key is rotated, Vault does not allow to choose a different
|
||||
encryption algorithm or key size. If a key for different encryption algorithm or
|
||||
a different key size is desired, new key needs to be generated in Vault and the
|
||||
corresponding key name be added in the configuration. Subsequent encryption will
|
||||
be done using the first key in the list. Decryption can happen using any of the
|
||||
keys in the list based on the prefix to the encrypted DEK.
|
||||
|
||||
## Backward compatibility
|
||||
1. Unencrypted secrets and secrets encrypted using other non-KMS providers will
|
||||
continue to be readable upon adding vault as a new KMS provider.
|
||||
2. If a Vault KMS is added as first provider, the secrets created or modified
|
||||
thereafter will be encrypted by vault provider.
|
||||
|
||||
## Performance
|
||||
1. KMS provider framework uses LRU cache to minimize the requests to KMS for
|
||||
encryption and decryption of DEKs.
|
||||
2. Note that there will be a request to KMS for every cache miss causing a
|
||||
performance impact. Hence, depending on the cache size, there will be a
|
||||
performance impact.
|
||||
3. Response time.
|
||||
4. will depend on choice of encryption algorithm and strength.
|
||||
5. will depend on specific vault configurations like storage backend,
|
||||
authentication mechanism, token polices etc.
|
||||
Loading…
Reference in New Issue