Repository: iterative/dvc

Issue:
Support provision of Client Keys for SSE-C Server Side Encryption
Hey! I'm using dvc[s3]==2.3.0 with python 3.8 to version files to a minIO s3 instance.
Server Side Encryption with Client provided keys (SSE-C, see: [Amazon Doc](https://docs.aws.amazon.com/AmazonS3/latest/userguide/specifying-s3-c-encryption.html) and [minIO Doc](https://docs.min.io/minio/baremetal/security/encryption/server-side-encryption-sse-c.html#encrypt-an-object-using-sse-c)) should be used but currently it isn't possible to specify the client key, so `dvc push` (and `dvc pull`) will fail when only setting `sse = AES256` since there is no KMS configured.

This could possibly be solved by extending the config with e.g. a key named `sse-customer-key-md5` that will be set to the S3 header field `X-Amz-Server-Side-Encryption-Customer-Key-MD5`. Example:

```
['remote "test-remote"']
    url = s3://test-remote/
    endpointurl = https://localhost:9000
    access_key_id = minio
    secret_access_key = minio123
    sse = AES256
    sse-customer-key-md5 = c2VjcmV0ZW5jcnlwdGlvbmtleWNoYW5nZW1lMTIzNBo=
```


Discussion:
I would like some help/opinions here. I was able to successfully get this working with dvc. However, the key that is required to encrypt the data needs to be a raw 32 byte key. I guess the underlying libraries (either boto3 or s3fs.. not sure since I did not have time to explore their source code exhaustively) take care of converting the key to base64 and include the relevant headers to the API requests. The library also takes of computing the md5 hash of the key so we do not need to add that explicitly in the config. A working example for SSE-C has been posted in the [this stackoverflow thread](https://stackoverflow.com/questions/37833243/boto3-client-error-server-side-encryption-with-customer-provided-key-is-incompa)

So we can either accept the key as a binary file and take the file path as a parameter. Something like below (I am using same example configuration above for consistency.)
```
['remote "test-remote"']
    url = s3://test-remote/
    endpointurl = https://localhost:9000
    access_key_id = minio
    secret_access_key = minio123
    sse-customer-key = /path/to/binary/key/file
```
or, we can accept the base64 encoded key which then we will decode to binary again in the code

```
['remote "test-remote"']
    url = s3://test-remote/
    endpointurl = https://localhost:9000
    access_key_id = minio
    secret_access_key = minio123
    sse-customer-key = c2VjcmV0ZW5jcnlwdGlvbmtleWNoYW5nZW1lMTIzNBo=     # base64 encoded 32 byte key
```

If there is any other way possible is also appreciated.
My vote is for the second approach, providing the base64 representation in the config. It's what the docs describe, and it's closer to the AWS CLI and SDK syntax. It looks like you could provide a binary file in the AWS CLI (https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html), but this seems less supported than passing the base64 string.

Resolving patch:
diff --git a/dvc/config_schema.py b/dvc/config_schema.py
--- a/dvc/config_schema.py
+++ b/dvc/config_schema.py
@@ -152,6 +152,8 @@ class RelPath(str):
                     "ssl_verify": Any(Bool, str),
                     "sse": str,
                     "sse_kms_key_id": str,
+                    "sse_customer_algorithm": str,
+                    "sse_customer_key": str,
                     "acl": str,
                     "grant_read": str,
                     "grant_read_acp": str,


Test patch: