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