Browse code

Merge pull request #611 from bsapiro/master

basic SSE-KMS support

Florent Viard authored on 2015/09/18 01:36:33
Showing 2 changed files
... ...
@@ -29,6 +29,7 @@ class Config(object):
29 29
     access_token = ""
30 30
     host_base = "s3.amazonaws.com"
31 31
     host_bucket = "%(bucket)s.s3.amazonaws.com"
32
+    kms_key = ""    #can't set this and Server Side Encryption at the same time
32 33
     simpledb_host = "sdb.amazonaws.com"
33 34
     cloudfront_host = "cloudfront.amazonaws.com"
34 35
     verbosity = logging.WARNING
... ...
@@ -155,6 +156,12 @@ class Config(object):
155 155
                     self.secret_key = env_secret_key
156 156
                 else:
157 157
                     self.role_config()
158
+                    
159
+            #TODO check KMS key is valid
160
+            if self.kms_key and self.server_side_encryption == True:
161
+                warning('Cannot have server_side_encryption (S3 SSE) and KMS_key set (S3 KMS). KMS encryption will be used. Please set server_side_encryption to False')
162
+            if self.kms_key and self.signature_v2 == True:
163
+                raise Exception('KMS encryption requires signature v4. Please set signature_v2 to False')
158 164
 
159 165
     def role_config(self):
160 166
         if sys.version_info[0] * 10 + sys.version_info[1] < 26:
... ...
@@ -573,6 +573,11 @@ class S3(object):
573 573
         if self.config.server_side_encryption:
574 574
             headers["x-amz-server-side-encryption"] = "AES256"
575 575
 
576
+        ####inject in kms headers
577
+        if self.config.kms_key:
578
+            headers['x-amz-server-side-encryption'] = 'aws:kms'
579
+            headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
580
+            
576 581
         ## MIME-type handling
577 582
         headers["content-type"] = self.content_type(filename=filename)
578 583
 
... ...
@@ -725,6 +730,11 @@ class S3(object):
725 725
         if self.config.server_side_encryption:
726 726
             headers["x-amz-server-side-encryption"] = "AES256"
727 727
 
728
+        ####inject in kms headers
729
+        if self.config.kms_key:
730
+            headers['x-amz-server-side-encryption'] = 'aws:kms'
731
+            headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
732
+            
728 733
         if extra_headers:
729 734
             headers.update(extra_headers)
730 735
 
... ...
@@ -759,7 +769,12 @@ class S3(object):
759 759
         ## Set server side encryption
760 760
         if self.config.server_side_encryption:
761 761
             headers["x-amz-server-side-encryption"] = "AES256"
762
-
762
+        
763
+        ####inject in kms headers
764
+        if self.config.kms_key:
765
+            headers['x-amz-server-side-encryption'] = 'aws:kms'
766
+            headers['x-amz-server-side-encryption-aws-kms-key-id'] = self.config.kms_key
767
+            
763 768
         if extra_headers:
764 769
             headers.update(extra_headers)
765 770
 
... ...
@@ -1265,7 +1280,8 @@ class S3(object):
1265 1265
             raise S3Error(response)
1266 1266
 
1267 1267
         debug("MD5 sums: computed=%s, received=%s" % (md5_computed, response["headers"]["etag"]))
1268
-        if response["headers"]["etag"].strip('"\'') != md5_hash.hexdigest():
1268
+        ## when using KMS encryption, MD5 etag value will not match
1269
+        if (response["headers"]["etag"].strip('"\'') != md5_hash.hexdigest()) and response["headers"]["x-amz-server-side-encryption"] != 'aws:kms':
1269 1270
             warning("MD5 Sums don't match!")
1270 1271
             if retries:
1271 1272
                 warning("Retrying upload of %s" % (filename))
... ...
@@ -1464,8 +1480,9 @@ class S3(object):
1464 1464
             warning("Reported size (%s) does not match received size (%s)" % (
1465 1465
                 start_position + long(response["headers"]["content-length"]), response["size"]))
1466 1466
         debug("ReceiveFile: Computed MD5 = %s" % response.get("md5"))
1467
+        debug("sse headers : %s" % response["headers"]["x-amz-server-side-encryption"])
1467 1468
         # avoid ETags from multipart uploads that aren't the real md5
1468
-        if '-' not in md5_from_s3 and not response["md5match"]:
1469
+        if ('-' not in md5_from_s3 and not response["md5match"]) and (response["headers"]["x-amz-server-side-encryption"] != 'aws:kms'):
1469 1470
             warning("MD5 signatures do not match: computed=%s, received=%s" % (
1470 1471
                 response.get("md5"), md5_from_s3))
1471 1472
         return response