mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
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.
This commit is contained in:
parent
e8791ae274
commit
b28661b673
248
docs/security/README.md
Normal file
248
docs/security/README.md
Normal file
@ -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
Block a user