add key-rotation for SSE-S3 objects (#6755)

This commit adds key-rotation for SSE-S3 objects.
To execute a key-rotation a SSE-S3 client must
 - specify the `X-Amz-Server-Side-Encryption: AES256` header
   for the destination
 - The source == destination for the COPY operation.

Fixes #6754
master
Andreas Auernhammer 6 years ago committed by kannappanr
parent a9cda850ca
commit d07fb41fe8
  1. 24
      cmd/encryption-v1.go
  2. 25
      cmd/object-handlers.go

@ -156,6 +156,30 @@ func rotateKey(oldKey []byte, newKey []byte, bucket, object string, metadata map
sealedKey = objectKey.Seal(extKey, sealedKey.IV, crypto.SSEC.String(), bucket, object) sealedKey = objectKey.Seal(extKey, sealedKey.IV, crypto.SSEC.String(), bucket, object)
crypto.SSEC.CreateMetadata(metadata, sealedKey) crypto.SSEC.CreateMetadata(metadata, sealedKey)
return nil return nil
case crypto.S3.IsEncrypted(metadata):
if globalKMS == nil {
return errKMSNotConfigured
}
keyID, kmsKey, sealedKey, err := crypto.S3.ParseMetadata(metadata)
if err != nil {
return err
}
oldKey, err := globalKMS.UnsealKey(keyID, kmsKey, crypto.Context{bucket: path.Join(bucket, object)})
if err != nil {
return err
}
var objectKey crypto.ObjectKey
if err = objectKey.Unseal(oldKey, sealedKey, crypto.S3.String(), bucket, object); err != nil {
return err
}
newKey, encKey, err := globalKMS.GenerateKey(globalKMSKeyID, crypto.Context{bucket: path.Join(bucket, object)})
if err != nil {
return err
}
sealedKey = objectKey.Seal(newKey, crypto.GenerateIV(rand.Reader), crypto.S3.String(), bucket, object)
crypto.S3.CreateMetadata(metadata, globalKMSKeyID, encKey, sealedKey)
return nil
} }
} }

@ -829,19 +829,24 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
return return
} }
} }
// AWS S3 implementation requires us to only rotate keys
// when/ both keys are provided and destination is same // If src == dst and either
// otherwise we proceed to encrypt/decrypt. // - the object is encrypted using SSE-C and two different SSE-C keys are present
if sseCopyC && sseC && cpSrcDstSame { // - the object is encrypted using SSE-S3 and the SSE-S3 header is present
// Get the old key which needs to be rotated. // than execute a key rotation.
oldKey, err = ParseSSECopyCustomerRequest(r.Header, srcInfo.UserDefined) if cpSrcDstSame && ((sseCopyC && sseC) || (sseS3 && sseCopyS3)) {
if err != nil { if sseCopyC && sseC {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) oldKey, err = ParseSSECopyCustomerRequest(r.Header, srcInfo.UserDefined)
return if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return
}
} }
for k, v := range srcInfo.UserDefined { for k, v := range srcInfo.UserDefined {
encMetadata[k] = v encMetadata[k] = v
} }
// In case of SSE-S3 oldKey and newKey aren't used - the KMS manages the keys.
if err = rotateKey(oldKey, newKey, srcBucket, srcObject, encMetadata); err != nil { if err = rotateKey(oldKey, newKey, srcBucket, srcObject, encMetadata); err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return return
@ -914,7 +919,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// metadataOnly is true indicating that we are not overwriting the object. // metadataOnly is true indicating that we are not overwriting the object.
// if encryption is enabled we do not need explicit "REPLACE" metadata to // if encryption is enabled we do not need explicit "REPLACE" metadata to
// be enabled as well - this is to allow for key-rotation. // be enabled as well - this is to allow for key-rotation.
if !isMetadataReplace(r.Header) && srcInfo.metadataOnly && !crypto.SSEC.IsEncrypted(srcInfo.UserDefined) { if !isMetadataReplace(r.Header) && srcInfo.metadataOnly && !crypto.IsEncrypted(srcInfo.UserDefined) {
// If x-amz-metadata-directive is not set to REPLACE then we need // If x-amz-metadata-directive is not set to REPLACE then we need
// to error out if source and destination are same. // to error out if source and destination are same.
writeErrorResponse(w, ErrInvalidCopyDest, r.URL) writeErrorResponse(w, ErrInvalidCopyDest, r.URL)

Loading…
Cancel
Save