Encryption
Encryption is enabled on a per volume basis using the
storageos.com/encryption
label (for more information see Encrypted
Volumes).
Ondat encrypts volumes on disk using AES-256 in XTS-AES mode with 512 bit keys as recommended by NIST, with encryption keys being derived using HKDF.
Keys and Initialisation vectors are generated using the crypto/rand package.
Key | Size | Usage |
---|---|---|
Volume | 512 bits random data | Used by XTS-AES to encrypt and decrypt disk blocks |
Namespace | 256 bits random data | Used to encrypt Volume keys |
Initialisation Vector | 256 bits random data | Used as ‘salt’ when encrypting volume keys with namespace keys |
The components required to derive the encryption key are stored in a Kubernetes secret. By default these secrets are stored in the namespace that Ondat is installed into. As Kubernetes secrets are only base64 encoded, it is recommend to encrypt secrets at rest. Alternatively a KMS such as HashiCorp Vault can be used.
Each namespace has its own key that is created when the namespace is
initialized. The namespace keys are stored as Kubernetes secrets named
ns-key.{Namespace Name}
. The namespace key secrets are created in whatever
namespace Ondat is installed into.
In the example below there are two ns-key
secrets in the storageos
namespace because a Ondat volume has been provisioned in the default
and
mongo
namespaces. A ns-key
is created for a namespace regardless of whether
an encrypted volume exists in the namespace or not.
$ kubectl get secrets -n kube-system | grep ns-key
ns-key.default Opaque 1 4d
ns-key.mongo Opaque 1 5h
A volume is encrypted with a volume key that is a randomly generated 512 bit key. Rather than storing the volume key, Ondat stores an encrypted version of the volume key, called the volume user key, which is generated by encrypting the volume key with a 256 bit namespace key and 256 bit initialization vector. Each namespace has a unique key and a unique initialization vector is generated for each volume.
The volume key is discarded to avoid the key that encrypts user data being compromised. Whenever the volume needs to be decrypted the volume key is derived by decrypting the volume user key using the namespace key and initialisation vector that are stored.
In order to check that the volume key has been correctly derived, a key digest of the volume key is stored to verify the derived volume key is identical to the original key.
Ultimately this means that the volume user key, initialisation vector, a digest of the volume key and the namespace key are stored in a Kubernetes secret. See Encrypted Volumes for best practices regarding backing up Ondat secrets.