diff --git a/cmd/bucket-encryption.go b/cmd/bucket-encryption.go index bd71c2104..d1f2d0e1a 100644 --- a/cmd/bucket-encryption.go +++ b/cmd/bucket-encryption.go @@ -53,7 +53,7 @@ func validateBucketSSEConfig(r io.Reader) (*bucketsse.BucketSSEConfig, error) { return nil, err } - if len(encConfig.Rules) == 1 && encConfig.Rules[0].DefaultEncryptionAction.Algorithm == bucketsse.AES256 { + if len(encConfig.Rules) == 1 { return encConfig, nil } diff --git a/cmd/bucket-encryption_test.go b/cmd/bucket-encryption_test.go index 867a879be..3d5ff48d4 100644 --- a/cmd/bucket-encryption_test.go +++ b/cmd/bucket-encryption_test.go @@ -19,7 +19,6 @@ package cmd import ( "bytes" - "errors" "testing" ) @@ -47,12 +46,12 @@ func TestValidateBucketSSEConfig(t *testing.T) { aws:kms - arn:aws:kms:us-east-1:1234/5678example + my-key `, - expectedErr: errors.New("Unsupported bucket encryption configuration"), - shouldPass: false, + expectedErr: nil, + shouldPass: true, }, } diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 651eed362..42ddb58be 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -992,12 +992,8 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h var objectEncryptionKey crypto.ObjectKey // Check if bucket encryption is enabled - if _, err = globalBucketSSEConfigSys.Get(bucket); err == nil || globalAutoEncryption { - // This request header needs to be set prior to setting ObjectOptions - if !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) - } - } + sseConfig, _ := globalBucketSSEConfigSys.Get(bucket) + sseConfig.Apply(r.Header, globalAutoEncryption) // get gateway encryption options var opts ObjectOptions diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index c4739ac03..012f3fe47 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -960,11 +960,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re } // Check if bucket encryption is enabled - _, err = globalBucketSSEConfigSys.Get(dstBucket) - // This request header needs to be set prior to setting ObjectOptions - if (globalAutoEncryption || err == nil) && !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) - } + sseConfig, _ := globalBucketSSEConfigSys.Get(dstBucket) + sseConfig.Apply(r.Header, globalAutoEncryption) var srcOpts, dstOpts ObjectOptions srcOpts, err = copySrcOpts(ctx, r, srcBucket, srcObject) @@ -1566,11 +1563,8 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req } // Check if bucket encryption is enabled - _, err = globalBucketSSEConfigSys.Get(bucket) - // This request header needs to be set prior to setting ObjectOptions - if (globalAutoEncryption || err == nil) && !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) - } + sseConfig, _ := globalBucketSSEConfigSys.Get(bucket) + sseConfig.Apply(r.Header, globalAutoEncryption) actualSize := size if objectAPI.IsCompressionSupported() && isCompressible(r.Header, object) && size > 0 { @@ -1885,11 +1879,8 @@ func (api objectAPIHandlers) PutObjectExtractHandler(w http.ResponseWriter, r *h } // Check if bucket encryption is enabled - _, err = globalBucketSSEConfigSys.Get(bucket) - // This request header needs to be set prior to setting ObjectOptions - if (globalAutoEncryption || err == nil) && !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) - } + sseConfig, _ := globalBucketSSEConfigSys.Get(bucket) + sseConfig.Apply(r.Header, globalAutoEncryption) retPerms := isPutActionAllowed(ctx, getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectRetentionAction) holdPerms := isPutActionAllowed(ctx, getRequestAuthType(r), bucket, object, r, iampolicy.PutObjectLegalHoldAction) @@ -2076,11 +2067,8 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r } // Check if bucket encryption is enabled - _, err = globalBucketSSEConfigSys.Get(bucket) - // This request header needs to be set prior to setting ObjectOptions - if (globalAutoEncryption || err == nil) && !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) - } + sseConfig, _ := globalBucketSSEConfigSys.Get(bucket) + sseConfig.Apply(r.Header, globalAutoEncryption) // Validate storage class metadata if present if sc := r.Header.Get(xhttp.AmzStorageClass); sc != "" { diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index db042d6bb..bfe56e7c5 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -1201,10 +1201,8 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { } // Check if bucket encryption is enabled - _, err = globalBucketSSEConfigSys.Get(bucket) - if (globalAutoEncryption || err == nil) && !crypto.SSEC.IsRequested(r.Header) { - r.Header.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) - } + sseConfig, _ := globalBucketSSEConfigSys.Get(bucket) + sseConfig.Apply(r.Header, globalAutoEncryption) // Require Content-Length to be set in the request size := r.ContentLength diff --git a/pkg/bucket/encryption/bucket-sse-config.go b/pkg/bucket/encryption/bucket-sse-config.go index f47a5f1d7..bfb287554 100644 --- a/pkg/bucket/encryption/bucket-sse-config.go +++ b/pkg/bucket/encryption/bucket-sse-config.go @@ -21,6 +21,10 @@ import ( "encoding/xml" "errors" "io" + "net/http" + + "github.com/minio/minio/cmd/crypto" + xhttp "github.com/minio/minio/cmd/http" ) const ( @@ -107,6 +111,49 @@ func ParseBucketSSEConfig(r io.Reader) (*BucketSSEConfig, error) { if config.XMLNS == "" { config.XMLNS = xmlNS } - return &config, nil } + +// Apply applies the SSE bucket configuration on the given HTTP headers and +// sets the specified SSE headers. +// +// Apply does not overwrite any existing SSE headers. Further, it will +// set minimal SSE-KMS headers if autoEncrypt is true and the BucketSSEConfig +// is nil. +func (b *BucketSSEConfig) Apply(headers http.Header, autoEncrypt bool) { + if _, ok := crypto.IsRequested(headers); ok { + return + } + if b == nil { + if autoEncrypt { + headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) + } + return + } + + switch b.Algorithm() { + case xhttp.AmzEncryptionAES: + headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES) + case xhttp.AmzEncryptionKMS: + headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS) + headers.Set(xhttp.AmzServerSideEncryptionKmsID, b.KeyID()) + } +} + +// Algorithm returns the SSE algorithm specified by the SSE configuration. +func (b *BucketSSEConfig) Algorithm() SSEAlgorithm { + for _, rule := range b.Rules { + return rule.DefaultEncryptionAction.Algorithm + } + return "" +} + +// KeyID returns the KMS key ID specified by the SSE configuration. +// If the SSE configuration does not specify SSE-KMS it returns an +// empty key ID. +func (b *BucketSSEConfig) KeyID() string { + for _, rule := range b.Rules { + return rule.DefaultEncryptionAction.MasterKeyID + } + return "" +}