Skip to content

Instantly share code, notes, and snippets.

@poornas
Last active October 17, 2018 01:48
Show Gist options
  • Save poornas/adabb4f2fdf883615cb0fb7f07d258d7 to your computer and use it in GitHub Desktop.
Save poornas/adabb4f2fdf883615cb0fb7f07d258d7 to your computer and use it in GitHub Desktop.
SSE implementation considerations

ETag

For objects created by the PUT Object, POST Object, or Copy operation, AWS returns MD5(object) for SSE-S3 encrypted objects and random ETag for SSE-C encrypted objects

To preserve security guarantees, we must not store MD5(object) in plaintext as ETag.Hence the ETag has to be stored in encrypted form as Encrypt(ETag = MD5(object)). However since APIs like ListObject do not require SSE-C key but return ETag information, this forces Minio server to also store encrypted MD5Sum for SSE-S3 and SSE-C, but return random ETag for SSE-C, and MD5(object) for SSE-S3.

In the gateway for double encryption scenario, to maintain compatibility X-Minio-Internal-ETag needs to be maintained with Encrypt(ETag = MD5(object)), and ETag set at the backend needs to be discarded and return Decrypt(Metadata['X-Minio-Internal-ETag']).

For server side copy operations, the encrypted ETag of original object MD5 needs to be decrypted correctly and re-encrypted with the target side key.

Custom format for double encryption

Double encryption requires a custom backend format due to S3 multipart API limitations. The SSE options are passed in the metadata in NewMultipart operation, but this is not available during the UploadPart and CompleteMultipart operations. In the case of SSE-S3 , the UploadPart operations would not have encryption metadata set during NewMultipart upload as the S3 spec does not require any SSE headers and the per object encryption key generated by the KMS are not available during UploadPart call .

Further, the CompleteMultipart API does not return the part sizes of individual parts committed and concatenated to the final object. Part sizes of the individual parts need to be known to perform decryption at the gateway to return the original content to application. S3 Spec allows each part to be of any size between 5MB and 5GB with the exception of the very last part which could be under 5MB.Hence the gateway implementation needs to store the encrypted part size at the gateway in the metadata. As there is no way to modify the metadata subsequent to the upload, this makes it necessary to maintain metadata and individual parts as separate objects in the backend under object/.minio/dare.meta (metadata file) and object/.minio/uploadID/partN for the individual uploaded parts.

Some limitations arising from double encryption implementation

  • Since encryption adds an overhead of 32 bytes for each 64KB block size, the per object max upload size of 5GB (As per S3 Spec) needs to be revised down to accomodate encryption overhead.For example, an encryption overhead of 2MB is added for an upload of 5GB. This is a constraint only for objects encrypted at gateway and backend.

  • Delete/Put operations are not atomic because of the custom format.

  • When minio is run in gateway mode with minio fs/xl backend, the custom format (i.e. storing content in file path obj/.minio/*) will not allow uploading obj/ if obj already exists. This is due to minio server using filesystem as object store whereas s3 does not.Since the custom double encryption uses path obj/.minio/*, minio server returns "Access denied" if another object exists with same prefix. It will not pose an issue for gateway s3 backend, however we will need to fail with meaningful error for minio server.

Sample Format of dare.meta

{
  "version": "1.0.0",
  "format": "gw",
  "stat": {
    "size": 10490913,
    "modTime": "2018-09-26T17:46:21.540191857Z"
  },
  "etag": "",
  "meta": {
    "X-Minio-Internal-Encrypted-Multipart": "",
    "X-Minio-Internal-Server-Side-Encryption-Iv": "v2he43TxZzyzBUQKRHjwj3NUOah7CdBbrBevywvcrb4=",
    "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Key-Id": "my-minio-key",
    "X-Minio-Internal-Server-Side-Encryption-S3-Kms-Sealed-Key": "dmF1bHQ6djE6NFJYMktsd1B5M0VzNGdsYWhESVpWS3l4L2tXdTg3dDlmRjlVT0RTdTh4Z3p6RUxJeHpma2l0TEE5V0JTQXZPeFFCS3JrTVRRVTlyTloyQTQ=",
    "X-Minio-Internal-Server-Side-Encryption-S3-Sealed-Key": "IAAfAI3WcdgimS+WmeNVu9R/iQnb0uGdahjefRxZyar3SDQ/26qnoqHMInoHJDWQN8mBJEOJJ5VZAZquuMelRg==",
    "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm": "DAREv2-HMAC-SHA256",
    "content-type": "application/octet-stream",
    "etag": "780e2b3d0b5ceeb0e94de9603ca950e7-3"
  },
  "parts": [
    {
      "number": 1,
      "name": "ssec-l-dest1/.minio/bc0b0f2c-6248-4588-90b9-d80c7ea81253/1",
      "etag": "d0cd7c9c2f0aa5050865b67aac57c1b6",
      "size": 5245440
    },
    {
      "number": 2,
      "name": "ssec-l-dest1/.minio/bc0b0f2c-6248-4588-90b9-d80c7ea81253/2",
      "etag": "6fcca7b09941ba0f376c728bbc2443a6",
      "size": 5245440
    },
    {
      "number": 3,
      "name": "ssec-l-dest1/.minio/bc0b0f2c-6248-4588-90b9-d80c7ea81253/3",
      "etag": "b16356de55592868a17e700e0fe7dc89",
      "size": 33
    }
  ]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment