diff --git a/CHANGELOG.md b/CHANGELOG.md index a7555030..25c26433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re - [#145](https://github.com/thanos-io/objstore/pull/145) Include content length in the response of Get and GetRange. ### Fixed +- [#141](https://github.com/thanos-io/objstore/pull/142) S3: Fix missing encryption configuration for `Bucket.Exists()` and `Bucket.Attributes()` calls. - [#153](https://github.com/thanos-io/objstore/pull/153) Metrics: Fix `objstore_bucket_operation_duration_seconds_*` for `get` and `get_range` operations. - [#117](https://github.com/thanos-io/objstore/pull/117) Metrics: Fix `objstore_bucket_operation_failures_total` incorrectly incremented if context is cancelled while reading object contents. - [#115](https://github.com/thanos-io/objstore/pull/115) GCS: Fix creation of bucket with GRPC connections. Also update storage client to `v1.40.0`. diff --git a/providers/s3/s3.go b/providers/s3/s3.go index 58590486..294ad735 100644 --- a/providers/s3/s3.go +++ b/providers/s3/s3.go @@ -513,7 +513,14 @@ func (b *Bucket) GetRange(ctx context.Context, name string, off, length int64) ( // Exists checks if the given object exists. func (b *Bucket) Exists(ctx context.Context, name string) (bool, error) { - _, err := b.client.StatObject(ctx, b.name, name, minio.StatObjectOptions{}) + sse, err := b.getServerSideEncryption(ctx) + if err != nil { + return false, err + } + + _, err = b.client.StatObject(ctx, b.name, name, minio.StatObjectOptions{ + ServerSideEncryption: sse, + }) if err != nil { if b.IsObjNotFoundErr(err) { return false, nil @@ -576,7 +583,14 @@ func (b *Bucket) Upload(ctx context.Context, name string, r io.Reader) error { // Attributes returns information about the specified object. func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { - objInfo, err := b.client.StatObject(ctx, b.name, name, minio.StatObjectOptions{}) + sse, err := b.getServerSideEncryption(ctx) + if err != nil { + return objstore.ObjectAttributes{}, err + } + + objInfo, err := b.client.StatObject(ctx, b.name, name, minio.StatObjectOptions{ + ServerSideEncryption: sse, + }) if err != nil { return objstore.ObjectAttributes{}, err } diff --git a/providers/s3/s3_e2e_test.go b/providers/s3/s3_e2e_test.go index ac9ec261..f3bb0d0f 100644 --- a/providers/s3/s3_e2e_test.go +++ b/providers/s3/s3_e2e_test.go @@ -6,13 +6,18 @@ package s3_test import ( "bytes" "context" + "io" + "path/filepath" "strings" "testing" "github.com/efficientgo/core/testutil" "github.com/efficientgo/e2e" + e2edb "github.com/efficientgo/e2e/db" "github.com/go-kit/log" + "github.com/minio/minio-go/v7/pkg/encrypt" + "github.com/thanos-io/objstore/exthttp" "github.com/thanos-io/objstore/providers/s3" "github.com/thanos-io/objstore/test/e2e/e2ethanos" ) @@ -54,3 +59,57 @@ func BenchmarkUpload(b *testing.B) { testutil.Ok(b, bkt.Upload(ctx, "test", strings.NewReader(str))) } } + +func TestSSECencryption(t *testing.T) { + ctx := context.Background() + e, err := e2e.NewDockerEnvironment("e2e-ssec", e2e.WithLogger(log.NewNopLogger())) + testutil.Ok(t, err) + t.Cleanup(e2ethanos.CleanScenario(t, e)) + + const bucket = "sse-c-encryption" + m := e2ethanos.NewMinio(e, "sse-c-encryption", bucket) + testutil.Ok(t, e2e.StartAndWaitReady(m)) + + cfg := s3.Config{ + Bucket: bucket, + AccessKey: e2edb.MinioAccessKey, + SecretKey: e2edb.MinioSecretKey, + Endpoint: m.Endpoint("https"), + Insecure: false, + HTTPConfig: exthttp.HTTPConfig{ + TLSConfig: exthttp.TLSConfig{ + CAFile: filepath.Join(m.Dir(), "certs", "CAs", "ca.crt"), + CertFile: filepath.Join(m.Dir(), "certs", "public.crt"), + KeyFile: filepath.Join(m.Dir(), "certs", "private.key"), + }, + }, + SSEConfig: s3.SSEConfig{ + Type: string(encrypt.SSEC), + EncryptionKey: "testdata/encryption_key", + }, + BucketLookupType: s3.AutoLookup, + } + + bkt, err := s3.NewBucketWithConfig( + log.NewNopLogger(), + cfg, + "test-ssec", + nil, + ) + testutil.Ok(t, err) + + upload := "secret content" + testutil.Ok(t, bkt.Upload(ctx, "encrypted", strings.NewReader(upload))) + + exists, err := bkt.Exists(ctx, "encrypted") + testutil.Ok(t, err) + if !exists { + t.Fatalf("upload failed") + } + + r, err := bkt.Get(ctx, "encrypted") + testutil.Ok(t, err) + b, err := io.ReadAll(r) + testutil.Ok(t, err) + testutil.Equals(t, upload, string(b)) +} diff --git a/providers/s3/testdata/encryption_key b/providers/s3/testdata/encryption_key new file mode 100644 index 00000000..70c059ee --- /dev/null +++ b/providers/s3/testdata/encryption_key @@ -0,0 +1 @@ +suchSecretVeryCryptographicKeyZ