github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/storage/bucket/sse_bucket_client.go (about) 1 package bucket 2 3 import ( 4 "context" 5 "io" 6 7 "github.com/minio/minio-go/v7/pkg/encrypt" 8 "github.com/pkg/errors" 9 "github.com/thanos-io/thanos/pkg/objstore" 10 "github.com/thanos-io/thanos/pkg/objstore/s3" 11 12 cortex_s3 "github.com/cortexproject/cortex/pkg/storage/bucket/s3" 13 ) 14 15 // TenantConfigProvider defines a per-tenant config provider. 16 type TenantConfigProvider interface { 17 // S3SSEType returns the per-tenant S3 SSE type. 18 S3SSEType(userID string) string 19 20 // S3SSEKMSKeyID returns the per-tenant S3 KMS-SSE key id or an empty string if not set. 21 S3SSEKMSKeyID(userID string) string 22 23 // S3SSEKMSEncryptionContext returns the per-tenant S3 KMS-SSE key id or an empty string if not set. 24 S3SSEKMSEncryptionContext(userID string) string 25 } 26 27 // SSEBucketClient is a wrapper around a objstore.BucketReader that configures the object 28 // storage server-side encryption (SSE) for a given user. 29 type SSEBucketClient struct { 30 userID string 31 bucket objstore.Bucket 32 cfgProvider TenantConfigProvider 33 } 34 35 // NewSSEBucketClient makes a new SSEBucketClient. The cfgProvider can be nil. 36 func NewSSEBucketClient(userID string, bucket objstore.Bucket, cfgProvider TenantConfigProvider) *SSEBucketClient { 37 return &SSEBucketClient{ 38 userID: userID, 39 bucket: bucket, 40 cfgProvider: cfgProvider, 41 } 42 } 43 44 // Close implements objstore.Bucket. 45 func (b *SSEBucketClient) Close() error { 46 return b.bucket.Close() 47 } 48 49 // Upload the contents of the reader as an object into the bucket. 50 func (b *SSEBucketClient) Upload(ctx context.Context, name string, r io.Reader) error { 51 if sse, err := b.getCustomS3SSEConfig(); err != nil { 52 return err 53 } else if sse != nil { 54 // If the underlying bucket client is not S3 and a custom S3 SSE config has been 55 // provided, the config option will be ignored. 56 ctx = s3.ContextWithSSEConfig(ctx, sse) 57 } 58 59 return b.bucket.Upload(ctx, name, r) 60 } 61 62 // Delete implements objstore.Bucket. 63 func (b *SSEBucketClient) Delete(ctx context.Context, name string) error { 64 return b.bucket.Delete(ctx, name) 65 } 66 67 // Name implements objstore.Bucket. 68 func (b *SSEBucketClient) Name() string { 69 return b.bucket.Name() 70 } 71 72 func (b *SSEBucketClient) getCustomS3SSEConfig() (encrypt.ServerSide, error) { 73 if b.cfgProvider == nil { 74 return nil, nil 75 } 76 77 // No S3 SSE override if the type override hasn't been provided. 78 sseType := b.cfgProvider.S3SSEType(b.userID) 79 if sseType == "" { 80 return nil, nil 81 } 82 83 cfg := cortex_s3.SSEConfig{ 84 Type: sseType, 85 KMSKeyID: b.cfgProvider.S3SSEKMSKeyID(b.userID), 86 KMSEncryptionContext: b.cfgProvider.S3SSEKMSEncryptionContext(b.userID), 87 } 88 89 sse, err := cfg.BuildMinioConfig() 90 if err != nil { 91 return nil, errors.Wrapf(err, "unable to customise S3 SSE config for tenant %s", b.userID) 92 } 93 94 return sse, nil 95 } 96 97 // Iter implements objstore.Bucket. 98 func (b *SSEBucketClient) Iter(ctx context.Context, dir string, f func(string) error, options ...objstore.IterOption) error { 99 return b.bucket.Iter(ctx, dir, f, options...) 100 } 101 102 // Get implements objstore.Bucket. 103 func (b *SSEBucketClient) Get(ctx context.Context, name string) (io.ReadCloser, error) { 104 return b.bucket.Get(ctx, name) 105 } 106 107 // GetRange implements objstore.Bucket. 108 func (b *SSEBucketClient) GetRange(ctx context.Context, name string, off, length int64) (io.ReadCloser, error) { 109 return b.bucket.GetRange(ctx, name, off, length) 110 } 111 112 // Exists implements objstore.Bucket. 113 func (b *SSEBucketClient) Exists(ctx context.Context, name string) (bool, error) { 114 return b.bucket.Exists(ctx, name) 115 } 116 117 // IsObjNotFoundErr implements objstore.Bucket. 118 func (b *SSEBucketClient) IsObjNotFoundErr(err error) bool { 119 return b.bucket.IsObjNotFoundErr(err) 120 } 121 122 // Attributes implements objstore.Bucket. 123 func (b *SSEBucketClient) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { 124 return b.bucket.Attributes(ctx, name) 125 } 126 127 // ReaderWithExpectedErrs implements objstore.Bucket. 128 func (b *SSEBucketClient) ReaderWithExpectedErrs(fn objstore.IsOpFailureExpectedFunc) objstore.BucketReader { 129 return b.WithExpectedErrs(fn) 130 } 131 132 // WithExpectedErrs implements objstore.Bucket. 133 func (b *SSEBucketClient) WithExpectedErrs(fn objstore.IsOpFailureExpectedFunc) objstore.Bucket { 134 if ib, ok := b.bucket.(objstore.InstrumentedBucket); ok { 135 return &SSEBucketClient{ 136 userID: b.userID, 137 bucket: ib.WithExpectedErrs(fn), 138 cfgProvider: b.cfgProvider, 139 } 140 } 141 142 return b 143 }