doc: add security documentation to provide some background info (#7028)
This commit adds some documentation about the design of the SSE-C and SSE-S3 implementation. It describes how the Minio server encrypt objects and manages keys.master
parent
e8791ae274
commit
b28661b673
@ -0,0 +1,248 @@ |
|||||||
|
# Minio Security Overview [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) |
||||||
|
|
||||||
|
## Server-Side Encryption |
||||||
|
|
||||||
|
Minio supports two different types of server-side encryption ([SSE](#sse)): |
||||||
|
- **SSE-C**: The Minio server en/decrypts an object with a secret key provided by the S3 client |
||||||
|
as part of the HTTP request headers. Therefore, [SSE-C](#ssec) requires TLS/HTTPS. |
||||||
|
- **SSE-S3**: The Minio server en/decrypts an object with a secret key managed by a KMS. |
||||||
|
Therefore, Minio requires a valid KMS configuration for [SSE-S3](#sses3). |
||||||
|
|
||||||
|
### Server-Side Encryption - Preliminaries |
||||||
|
|
||||||
|
#### Secret Keys |
||||||
|
|
||||||
|
The Minio server uses an unique, randomly generated secret key per object also known as, |
||||||
|
Object Encryption Key ([OEK](#oek)). Neither the client-provided SSE-C key nor the KMS-managed |
||||||
|
key is directly used to en/decrypt an object. Instead, the OEK is stored as part of the object |
||||||
|
metadata next to the object in an encrypted form. To en/decrypt the OEK another secret key is |
||||||
|
needed also known as, Key Encryption Key ([KEK](#kek)). |
||||||
|
|
||||||
|
The Minio server runs a key-derivation algorithm to generate the KEK using a pseudo-random |
||||||
|
function ([PRF](#prf)): |
||||||
|
`KEK := PRF(EK, IV, context_values)` where |
||||||
|
- [EK](#ek): is the external key. In case of SSE-C this is the client-provided key. In case of SSE-S3 |
||||||
|
this is secret key generated by the KMS. For further details see |
||||||
|
[SSE-C](#Server-Side-Encryption-with-client-provided-Keys) or |
||||||
|
[SSE-S3](#Server-Side-Encryption-with-a-KMS). |
||||||
|
- [IV](#iv): is a randomly generated initialization vector. It is public and part of the |
||||||
|
object metadata. |
||||||
|
- `context_values`: are values like the bucket and object name and other information which should be |
||||||
|
cryptographically bound to the KEK. |
||||||
|
|
||||||
|
To summarize for any encrypted object there exists (at least) three different keys: |
||||||
|
1. [OEK](#oek): A secret and unique key used to encrypted the object, stored in an encrypted form as |
||||||
|
part of the object metadata and only loaded to RAM in plaintext during en/decrypting the object. |
||||||
|
2. [KEK](#kek): A secret and unique key used to en/decrypt the OEK and never stored anywhere. |
||||||
|
It is(re-)generated whenever en/decrypting an object using an external secret key and public |
||||||
|
parameters. |
||||||
|
3. [EK](#ek): An external secret key - either the SSE-C client-provided key or a secret key |
||||||
|
generated by the KMS. |
||||||
|
|
||||||
|
#### Content Encryption |
||||||
|
|
||||||
|
The Minio server uses an authenticated encryption scheme ([AEAD](#aead)) to en/decrypt and |
||||||
|
authenticate the object content. The AEAD is combined with some state to build a |
||||||
|
*Secure Channel*. A *Secure Channel* is a cryptographic construction that ensures confidentiality |
||||||
|
and integrity of the processed data. In particular the *Secure Channel* splits the plaintext content |
||||||
|
into fixed size chunks and en/decrypts each chunk separately using an unique key-nonce combination. |
||||||
|
|
||||||
|
``` |
||||||
|
plaintext := chunk_0 || chunk_1 || chunk_2 || ... |
||||||
|
| | | |
||||||
|
| | | |
||||||
|
AEAD <- key, nonce + 0 AEAD <- key, nonce + 1 AEAD <- key, nonce + 2 ... |
||||||
|
| | | |
||||||
|
| | | |
||||||
|
ciphertext := sealed_chunk_0 || sealed_chunk_1 || sealed_chunk_2 || ... |
||||||
|
``` |
||||||
|
<center>Figure 1 - Secure Channel construction</center> |
||||||
|
|
||||||
|
In case of a S3 multi-part operation each part is en/decrypted with the scheme shown in |
||||||
|
Figure 1. However, for each part an unique secret key is derived from the OEK and the part |
||||||
|
number using a PRF. So in case of multi-part not the OEK but the output of `PRF(OEK, part_id)` |
||||||
|
is used as secret key. |
||||||
|
|
||||||
|
#### Cryptographic Primitives |
||||||
|
|
||||||
|
The SSE schemes described in [Secret Keys](#Secret-Keys) and [Content Encryption](#Content-Encryption) |
||||||
|
are generic over the cryptographic primitives. However, the Minio server uses the following |
||||||
|
cryptographic primitive implementations: |
||||||
|
- [PRF](#prf): HMAC-SHA-256 |
||||||
|
- [AEAD](#aead): AES-256-GCM if the CPU supports AES-NI, ChaCha20-Poly1305 otherwise. |
||||||
|
More specifically AES-256-GCM is only selected for X86-64 CPUs with AES-NI extension. |
||||||
|
|
||||||
|
Further any secret key (apart from the KMS-generated ones) is 256 bits long. The KMS-generated keys |
||||||
|
may be 256 bits but this depends on the KMS capabilities and configuration. |
||||||
|
|
||||||
|
The *Secure Channel* splits the object content into chunks of a fixed size of `65536` bytes. The last |
||||||
|
chunk may be smaller to avoid adding additional overhead and is treated specially to prevent truncation |
||||||
|
attacks. The nonce value is 96 bits long and generated randomly per object / multi-part part. The |
||||||
|
*Secure Channel* supports plaintexts up to `65536 * 2^32 = 256 TiB`. |
||||||
|
|
||||||
|
#### Randomness |
||||||
|
|
||||||
|
The Minio server generates unique keys and other cryptographic values using a cryptographically |
||||||
|
secure pseudo-random number generator ([CSPRNG](#csprng)). However, in the context of SSE, |
||||||
|
the Minio server does not require that the CSPRNG generates values that are indistinguishable |
||||||
|
from truly random bit strings. Instead, it is sufficient if the generated values are unique - which |
||||||
|
is a weaker requirement. Nevertheless other parts - for example the TLS-stack - may require that |
||||||
|
CSPRNG-generated values are indistinguishable from truly random bit strings. |
||||||
|
|
||||||
|
### Server-Side Encryption with client-provided Keys |
||||||
|
|
||||||
|
SSE-C allows an S3 client to en/decrypt an object at the Minio server. Therefore the S3 client |
||||||
|
sends a secret key as part of the HTTP request. This secret key is **never** stored by the |
||||||
|
Minio server and only resides in RAM during the en/decryption process. |
||||||
|
|
||||||
|
Minio does not assume or require that the client-provided key is unique. It may be used for |
||||||
|
multiple objects or buckets. Especially a single client-provided key may be used for all |
||||||
|
objects - even though all objects must be treated as compromised if that key is ever compromised. |
||||||
|
|
||||||
|
#### Key rotation |
||||||
|
|
||||||
|
S3 clients can change the client-provided key of an existing object. Therefore an S3 client |
||||||
|
must perform a S3 COPY operation where the copy source and destination are equal. Further the |
||||||
|
COPY request headers must contain the current and the new client key: |
||||||
|
- `X-Amz-Server-Side-Encryption-Customer-Key`: Base64 encoded new key. |
||||||
|
- `X-Amz-Copy-Source-Server-Side-Encryption-Customer-Key`: Base64 encoded current key. |
||||||
|
|
||||||
|
Such a special COPY request is also known as S3 SSE-C key rotation. |
||||||
|
|
||||||
|
### Server-Side Encryption with a KMS |
||||||
|
|
||||||
|
SSE-S3 allows an S3 client to en/decrypt an object at the Minio server using a KMS. The Minio |
||||||
|
server only assumes that the KMS provides two services: |
||||||
|
1. `GenerateKey`: Takes a key ID and generates a new data key from a master key referenced by |
||||||
|
the key ID. It returns the new data key in two different forms: The plain data key |
||||||
|
and the data key encrypted using the master key. |
||||||
|
2. `DecryptKey`: Takes a key ID and an encrypted data key and returns the plain data key - the |
||||||
|
decryption of the encrypted data key using the master key referenced by the key ID - |
||||||
|
on success or an error otherwise. |
||||||
|
|
||||||
|
More details about supported KMS implementations and configuration can be found at the [KMS guide](https://github.com/minio/minio/blob/master/docs/kms/README.md). |
||||||
|
|
||||||
|
The Minio server requests a new data key from the KMS for each uploaded object and uses that data key |
||||||
|
as EK. Additionally it stores the encrypted form of the data key and the master key ID as part |
||||||
|
of the object metadata. The plain data only resides in RAM during the en/decryption process. |
||||||
|
The Minio server does not store any SSE-related key at the KMS. Instead the KMS is treated as trusted |
||||||
|
component that performs key sealing/unsealing operations to build a key hierarchy: |
||||||
|
|
||||||
|
``` |
||||||
|
CMK (master key) |
||||||
|
| |
||||||
|
+-----------------------------------+-----------------------------------+ |
||||||
|
| | | |
||||||
|
+-------+----------------+ +-------+----------------+ ... |
||||||
|
| EK_1 | EK_1_encrypted | | EK_2 | EK_2_encrypted | |
||||||
|
+---+----------+---------+ +---+----------+---------+ |
||||||
|
| | | | |
||||||
|
| | | | |
||||||
|
+---+---+ | +---+---+ | |
||||||
|
| KEK_1 | | | KEK_2 | | |
||||||
|
+---+---+ | +---+---+ | |
||||||
|
| | | | |
||||||
|
| | | | |
||||||
|
+---+---+ | +---+---+ | |
||||||
|
| OEK_1 | | | OEK_2 | | |
||||||
|
+---+---+ | +---+---+ | |
||||||
|
| | |
||||||
|
| | |
||||||
|
| | |
||||||
|
+---------+---------+ +---------+---------+ |
||||||
|
| object_metadata_1 | | object_metadata_2 | |
||||||
|
+-------------------+ +-------------------+ |
||||||
|
``` |
||||||
|
<center>Figure 2 - KMS key hierarchy</center> |
||||||
|
|
||||||
|
|
||||||
|
#### Key rotation - Basic Operation |
||||||
|
|
||||||
|
The Minio server supports key rotation for SSE-S3 encrypted objects. Therefore, an S3 client |
||||||
|
must perform a S3 COPY operation where the copy source and destination are equal and the SSE-S3 HTTP |
||||||
|
header is set. The minio server decrypts the OEK using the current encrypted data key and the |
||||||
|
master key ID of the object metadata. If this succeeds, the server requests a new data key |
||||||
|
from the KMS using the master key ID of the **current Minio KMS configuration** and re-wraps the |
||||||
|
*OEK* with a new *KEK* derived from the new data key / EK: |
||||||
|
|
||||||
|
``` |
||||||
|
object metadata KMS |
||||||
|
| | |
||||||
|
| +----------------+ 1a | +-------+ |
||||||
|
|-------------------->| EK_1_encrypted |-----------|->| CMK_1 | |
||||||
|
| +----------------+ | +---+---+ |
||||||
|
| | | |
||||||
|
| +---------------+ +------+ 1b | | |
||||||
|
|------------->| OEK_encrypted | | EK_1 |<---|------+ |
||||||
|
| +-------+-------+ +------+ | |
||||||
|
| \ / | |
||||||
|
| \___ 2 ___/ | |
||||||
|
| \___/ | |
||||||
|
| | | |
||||||
|
| +--+--+ | |
||||||
|
| | OEK | | +-------+ |
||||||
|
| +--+--+ | | CMK_2 | |
||||||
|
| | | +---+---+ |
||||||
|
| | | | |
||||||
|
| 5 +----------------+ |4 +------+ 3a | | |
||||||
|
|<------| OEK_encrypted' |<----+-------| EK_2 |<---|------+ |
||||||
|
| +----------------+ +------+ | | |
||||||
|
| +----------------+ 3b | | |
||||||
|
|<-------------------| EK_2_encrypted |<-----------|------+ |
||||||
|
| +----------------+ | |
||||||
|
| | |
||||||
|
|
||||||
|
|
||||||
|
1a) Send encrypted data key and master key ID to KMS. |
||||||
|
1b) Receive decrypted data key. |
||||||
|
2) Decrypt encrypted object key with the KEK derived from the data key. |
||||||
|
3a) Receive new plain data key from the KMS using the master key ID of the server config. |
||||||
|
3b) Receive encrypted form of the data key from the KMS. |
||||||
|
4) Derive a new KEK from the new data key and re-encrypt the OEK with it. |
||||||
|
5) Store the encrypted OEK encrypted data key and master key ID in object metadata. |
||||||
|
``` |
||||||
|
<center>Figure 3 - KMS data key rotation</center> |
||||||
|
|
||||||
|
#### Key rotation - Extensions |
||||||
|
|
||||||
|
The basic SSE-S3 key rotation operation can be used to build more powerful key management |
||||||
|
operations. The following options are possible to perform manually but do not have fully |
||||||
|
functional API's at this time. |
||||||
|
|
||||||
|
1. **Master key migration**: The [SSE-S3 key rotation](#Key-rotation---Basic-Operation) can be performed |
||||||
|
on multiple/all objects to move them from one to another master key. |
||||||
|
2. **Secure object erasure**: The [SSE-S3 key rotation](#Key-rotation---Basic-Operation) can be applied |
||||||
|
to one/multiple objects with a randomly generated master key which is |
||||||
|
not stored at the KMS. That leads to an encrypted data key which can |
||||||
|
never be decrypted anymore. |
||||||
|
3. **Periodical key migration**: The [SSE-S3 key rotation](#Key-rotation---Basic-Operation) can be |
||||||
|
invoked after a certain time period to migrate one or more objects |
||||||
|
from one master key to another. |
||||||
|
|
||||||
|
#### Secure Erasure and Locking |
||||||
|
|
||||||
|
The Minio server requires an available KMS to en/decrypt SSE-S3 encrypted objects. Therefore it |
||||||
|
is possible to erase or lock some or all encrypted objects. For example in case of a detected attack |
||||||
|
or other emergency situations the following actions can be taken: |
||||||
|
- Seal the KMS such that it cannot be accessed by Minio server anymore. That will lock **all** |
||||||
|
SSE-S3 encrypted objects protected by master keys stored on the KMS. All these objects |
||||||
|
can not be decrypted as long as the KMS is sealed. |
||||||
|
- Seal/Unmount one/some master keys. That will lock all SSE-S3 encrypted objects protected by |
||||||
|
these master keys. All these objects can not be decrypted as long as the key(s) are sealed. |
||||||
|
- Delete one/some master keys. From a security standpoint, this is equal to erasing all SSE-S3 |
||||||
|
encrypted objects protected by these master keys. All these objects are lost forever as they cannot |
||||||
|
be decrypted. Especially deleting all master keys at the KMS is equivalent to secure erasing all |
||||||
|
SSE-S3 encrypted objects. |
||||||
|
|
||||||
|
## Acronyms |
||||||
|
|
||||||
|
- <a name="aead"></a>**AEAD**: Authenticated Encryption with Associated Data |
||||||
|
- <a name="csprng"></a>**CSPRNG**: Cryptographically Secure Pseudo Random Number Generator |
||||||
|
- <a name="ek"></a>**EK**: External Key |
||||||
|
- <a name="iv"></a>**IV**: Initialization Vector |
||||||
|
- <a name="kek"></a>**KEK**: Key Encryption Key |
||||||
|
- <a name="oek"></a>**OEK**: Object Encryption Key |
||||||
|
- <a name="prf"></a>**PRF**: Pseudo Random Function |
||||||
|
- <a name="sse"></a>**SSE**: Server-Side Encryption |
||||||
|
- <a name="ssec"></a>**SSE-C**: Server-Side Encryption with client-provided Keys |
||||||
|
- <a name="sses3"></a>**SSE-S3**: Server-Side Encryption with a KMS |
Loading…
Reference in new issue