github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/bucket/encryption/bucket-sse-config.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package sse
    19  
    20  import (
    21  	"encoding/xml"
    22  	"errors"
    23  	"io"
    24  	"net/http"
    25  	"strings"
    26  
    27  	"github.com/minio/minio/internal/crypto"
    28  	xhttp "github.com/minio/minio/internal/http"
    29  )
    30  
    31  const (
    32  	// AES256 is used with SSE-S3
    33  	AES256 Algorithm = "AES256"
    34  	// AWSKms is used with SSE-KMS
    35  	AWSKms Algorithm = "aws:kms"
    36  )
    37  
    38  // Algorithm - represents valid SSE algorithms supported; currently only AES256 is supported
    39  type Algorithm string
    40  
    41  // UnmarshalXML - Unmarshals XML tag to valid SSE algorithm
    42  func (alg *Algorithm) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    43  	var s string
    44  	if err := d.DecodeElement(&s, &start); err != nil {
    45  		return err
    46  	}
    47  
    48  	switch s {
    49  	case string(AES256):
    50  		*alg = AES256
    51  	case string(AWSKms):
    52  		*alg = AWSKms
    53  	default:
    54  		return errors.New("Unknown SSE algorithm")
    55  	}
    56  
    57  	return nil
    58  }
    59  
    60  // MarshalXML - Marshals given SSE algorithm to valid XML
    61  func (alg *Algorithm) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    62  	return e.EncodeElement(string(*alg), start)
    63  }
    64  
    65  // EncryptionAction - for ApplyServerSideEncryptionByDefault XML tag
    66  type EncryptionAction struct {
    67  	Algorithm   Algorithm `xml:"SSEAlgorithm,omitempty"`
    68  	MasterKeyID string    `xml:"KMSMasterKeyID,omitempty"`
    69  }
    70  
    71  // Rule - for ServerSideEncryptionConfiguration XML tag
    72  type Rule struct {
    73  	DefaultEncryptionAction EncryptionAction `xml:"ApplyServerSideEncryptionByDefault"`
    74  }
    75  
    76  const xmlNS = "http://s3.amazonaws.com/doc/2006-03-01/"
    77  
    78  // BucketSSEConfig - represents default bucket encryption configuration
    79  type BucketSSEConfig struct {
    80  	XMLNS   string   `xml:"xmlns,attr,omitempty"`
    81  	XMLName xml.Name `xml:"ServerSideEncryptionConfiguration"`
    82  	Rules   []Rule   `xml:"Rule"`
    83  }
    84  
    85  // ParseBucketSSEConfig - Decodes given XML to a valid default bucket encryption config
    86  func ParseBucketSSEConfig(r io.Reader) (*BucketSSEConfig, error) {
    87  	var config BucketSSEConfig
    88  	err := xml.NewDecoder(r).Decode(&config)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	// Validates server-side encryption config rules
    94  	// Only one rule is allowed on AWS S3
    95  	if len(config.Rules) != 1 {
    96  		return nil, errors.New("only one server-side encryption rule is allowed at a time")
    97  	}
    98  
    99  	for _, rule := range config.Rules {
   100  		switch rule.DefaultEncryptionAction.Algorithm {
   101  		case AES256:
   102  			if rule.DefaultEncryptionAction.MasterKeyID != "" {
   103  				return nil, errors.New("MasterKeyID is allowed with aws:kms only")
   104  			}
   105  		case AWSKms:
   106  			keyID := rule.DefaultEncryptionAction.MasterKeyID
   107  			if keyID == "" {
   108  				return nil, errors.New("MasterKeyID is missing with aws:kms")
   109  			}
   110  			spaces := strings.HasPrefix(keyID, " ") || strings.HasSuffix(keyID, " ")
   111  			if spaces {
   112  				return nil, errors.New("MasterKeyID contains unsupported characters")
   113  			}
   114  		}
   115  	}
   116  
   117  	if config.XMLNS == "" {
   118  		config.XMLNS = xmlNS
   119  	}
   120  	return &config, nil
   121  }
   122  
   123  // ApplyOptions ask for specific features to be enabled,
   124  // when bucketSSEConfig is empty.
   125  type ApplyOptions struct {
   126  	AutoEncrypt bool
   127  }
   128  
   129  // Apply applies the SSE bucket configuration on the given HTTP headers and
   130  // sets the specified SSE headers.
   131  //
   132  // Apply does not overwrite any existing SSE headers. Further, it will
   133  // set minimal SSE-KMS headers if autoEncrypt is true and the BucketSSEConfig
   134  // is nil.
   135  func (b *BucketSSEConfig) Apply(headers http.Header, opts ApplyOptions) {
   136  	if crypto.Requested(headers) {
   137  		return
   138  	}
   139  	if b == nil {
   140  		if opts.AutoEncrypt {
   141  			headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS)
   142  		}
   143  		return
   144  	}
   145  
   146  	switch b.Algo() {
   147  	case xhttp.AmzEncryptionAES:
   148  		headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionAES)
   149  	case xhttp.AmzEncryptionKMS:
   150  		headers.Set(xhttp.AmzServerSideEncryption, xhttp.AmzEncryptionKMS)
   151  		headers.Set(xhttp.AmzServerSideEncryptionKmsID, b.KeyID())
   152  	}
   153  }
   154  
   155  // Algo returns the SSE algorithm specified by the SSE configuration.
   156  func (b *BucketSSEConfig) Algo() Algorithm {
   157  	for _, rule := range b.Rules {
   158  		return rule.DefaultEncryptionAction.Algorithm
   159  	}
   160  	return ""
   161  }
   162  
   163  // KeyID returns the KMS key ID specified by the SSE configuration.
   164  // If the SSE configuration does not specify SSE-KMS it returns an
   165  // empty key ID.
   166  func (b *BucketSSEConfig) KeyID() string {
   167  	for _, rule := range b.Rules {
   168  		return strings.TrimPrefix(rule.DefaultEncryptionAction.MasterKeyID, crypto.ARNPrefix)
   169  	}
   170  	return ""
   171  }