@@ -43,11 +43,20 @@ static HeaderMap create_s3_header(string url, string query, string host, string
4343 datetime_now = StrfTimeFormat::Format (timestamp, " %Y%m%dT%H%M%SZ" );
4444 }
4545
46+ // Only some S3 operations supports SSE-KMS, which this "heuristic" attempts to detect.
47+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/specifying-kms-encryption.html#sse-request-headers-kms
48+ bool use_sse_kms = auth_params.kms_key_id .length () > 0 && (method == " POST" || method == " PUT" ) &&
49+ query.find (" uploadId" ) == std::string::npos;
50+
4651 res[" x-amz-date" ] = datetime_now;
4752 res[" x-amz-content-sha256" ] = payload_hash;
4853 if (auth_params.session_token .length () > 0 ) {
4954 res[" x-amz-security-token" ] = auth_params.session_token ;
5055 }
56+ if (use_sse_kms) {
57+ res[" x-amz-server-side-encryption" ] = " aws:kms" ;
58+ res[" x-amz-server-side-encryption-aws-kms-key-id" ] = auth_params.kms_key_id ;
59+ }
5160
5261 string signed_headers = " " ;
5362 hash_bytes canonical_request_hash;
@@ -59,6 +68,9 @@ static HeaderMap create_s3_header(string url, string query, string host, string
5968 if (auth_params.session_token .length () > 0 ) {
6069 signed_headers += " ;x-amz-security-token" ;
6170 }
71+ if (use_sse_kms) {
72+ signed_headers += " ;x-amz-server-side-encryption;x-amz-server-side-encryption-aws-kms-key-id" ;
73+ }
6274 auto canonical_request = method + " \n " + S3FileSystem::UrlEncode (url) + " \n " + query;
6375 if (content_type.length () > 0 ) {
6476 canonical_request += " \n content-type:" + content_type;
@@ -67,6 +79,10 @@ static HeaderMap create_s3_header(string url, string query, string host, string
6779 if (auth_params.session_token .length () > 0 ) {
6880 canonical_request += " \n x-amz-security-token:" + auth_params.session_token ;
6981 }
82+ if (use_sse_kms) {
83+ canonical_request += " \n x-amz-server-side-encryption:aws:kms" ;
84+ canonical_request += " \n x-amz-server-side-encryption-aws-kms-key-id:" + auth_params.kms_key_id ;
85+ }
7086
7187 canonical_request += " \n\n " + signed_headers + " \n " + payload_hash;
7288 sha256 (canonical_request.c_str (), canonical_request.length (), canonical_request_hash);
@@ -130,6 +146,7 @@ void AWSEnvironmentCredentialsProvider::SetAll() {
130146 this ->SetExtensionOptionValue (" s3_session_token" , SESSION_TOKEN_ENV_VAR);
131147 this ->SetExtensionOptionValue (" s3_endpoint" , DUCKDB_ENDPOINT_ENV_VAR);
132148 this ->SetExtensionOptionValue (" s3_use_ssl" , DUCKDB_USE_SSL_ENV_VAR);
149+ this ->SetExtensionOptionValue (" s3_kms_key_id" , DUCKDB_KMS_KEY_ID_ENV_VAR);
133150}
134151
135152S3AuthParams AWSEnvironmentCredentialsProvider::CreateParams () {
@@ -141,6 +158,7 @@ S3AuthParams AWSEnvironmentCredentialsProvider::CreateParams() {
141158 params.secret_access_key = SECRET_KEY_ENV_VAR;
142159 params.session_token = SESSION_TOKEN_ENV_VAR;
143160 params.endpoint = DUCKDB_ENDPOINT_ENV_VAR;
161+ params.kms_key_id = DUCKDB_KMS_KEY_ID_ENV_VAR;
144162 params.use_ssl = DUCKDB_USE_SSL_ENV_VAR;
145163
146164 return params;
@@ -166,6 +184,7 @@ S3AuthParams S3AuthParams::ReadFrom(optional_ptr<FileOpener> opener, FileOpenerI
166184 secret_reader.TryGetSecretKeyOrSetting (" session_token" , " s3_session_token" , result.session_token );
167185 secret_reader.TryGetSecretKeyOrSetting (" region" , " s3_region" , result.region );
168186 secret_reader.TryGetSecretKeyOrSetting (" use_ssl" , " s3_use_ssl" , result.use_ssl );
187+ secret_reader.TryGetSecretKeyOrSetting (" kms_key_id" , " s3_kms_key_id" , result.kms_key_id );
169188 secret_reader.TryGetSecretKeyOrSetting (" s3_url_compatibility_mode" , " s3_url_compatibility_mode" ,
170189 result.s3_url_compatibility_mode );
171190
@@ -202,6 +221,7 @@ unique_ptr<KeyValueSecret> CreateSecret(vector<string> &prefix_paths_p, string &
202221 return_value->secret_map [" endpoint" ] = params.endpoint ;
203222 return_value->secret_map [" url_style" ] = params.url_style ;
204223 return_value->secret_map [" use_ssl" ] = params.use_ssl ;
224+ return_value->secret_map [" kms_key_id" ] = params.kms_key_id ;
205225 return_value->secret_map [" s3_url_compatibility_mode" ] = params.s3_url_compatibility_mode ;
206226
207227 // ! Set redact keys
0 commit comments