diff --git a/CHANGELOG.md b/CHANGELOG.md index 05aafa7b..270f6d4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ We use *breaking :warning:* to mark changes that are not backward compatible (re - [#43](https://github.com/thanos-io/objstore/pull/43) filesystem: abort filesystem bucket operations if the context has been cancelled - [#44](https://github.com/thanos-io/objstore/pull/44) Add new metric to count total number of fetched bytes from bucket - [#50](https://github.com/thanos-io/objstore/pull/50) Add Huawei Cloud OBS Object Storage Support +- [#59](https://github.com/thanos-io/objstore/pull/59) Adding method `IsCustomerManagedKeyError` on the bucket interface. ### Changed - [#38](https://github.com/thanos-io/objstore/pull/38) *: Upgrade minio-go version to `v7.0.45`. diff --git a/inmem.go b/inmem.go index ac36e7f4..aee4aec6 100644 --- a/inmem.go +++ b/inmem.go @@ -207,6 +207,11 @@ func (b *InMemBucket) IsObjNotFoundErr(err error) bool { return errors.Is(err, errNotFound) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *InMemBucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *InMemBucket) Close() error { return nil } // Name returns the bucket name. diff --git a/objstore.go b/objstore.go index cc6034d5..fb9b0bac 100644 --- a/objstore.go +++ b/objstore.go @@ -85,6 +85,9 @@ type BucketReader interface { // IsObjNotFoundErr returns true if error means that object is not found. Relevant to Get operations. IsObjNotFoundErr(err error) bool + // IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. + IsCustomerManagedKeyError(err error) bool + // Attributes returns information about the specified object. Attributes(ctx context.Context, name string) (ObjectAttributes, error) } @@ -603,6 +606,10 @@ func (b *metricBucket) IsObjNotFoundErr(err error) bool { return b.bkt.IsObjNotFoundErr(err) } +func (b *metricBucket) IsCustomerManagedKeyError(err error) bool { + return b.bkt.IsCustomerManagedKeyError(err) +} + func (b *metricBucket) Close() error { return b.bkt.Close() } diff --git a/prefixed_bucket.go b/prefixed_bucket.go index 130f14d4..41448011 100644 --- a/prefixed_bucket.go +++ b/prefixed_bucket.go @@ -74,6 +74,11 @@ func (p *PrefixedBucket) IsObjNotFoundErr(err error) bool { return p.bkt.IsObjNotFoundErr(err) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (p *PrefixedBucket) IsCustomerManagedKeyError(err error) bool { + return p.bkt.IsCustomerManagedKeyError(err) +} + // Attributes returns information about the specified object. func (p PrefixedBucket) Attributes(ctx context.Context, name string) (ObjectAttributes, error) { return p.bkt.Attributes(ctx, conditionalPrefix(p.prefix, name)) diff --git a/providers/azure/azure.go b/providers/azure/azure.go index 23e66169..a5f41ed1 100644 --- a/providers/azure/azure.go +++ b/providers/azure/azure.go @@ -235,6 +235,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return bloberror.HasCode(err, bloberror.BlobNotFound) || bloberror.HasCode(err, bloberror.InvalidURI) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *Bucket) getBlobReader(ctx context.Context, name string, httpRange blob.HTTPRange) (io.ReadCloser, error) { level.Debug(b.logger).Log("msg", "getting blob", "blob", name, "offset", httpRange.Offset, "length", httpRange.Count) if name == "" { diff --git a/providers/bos/bos.go b/providers/bos/bos.go index 5c5117cb..2a9b5cae 100644 --- a/providers/bos/bos.go +++ b/providers/bos/bos.go @@ -287,6 +287,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return false } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *Bucket) getRange(_ context.Context, bucketName, objectKey string, off, length int64) (io.ReadCloser, error) { if len(objectKey) == 0 { return nil, errors.Errorf("given object name should not empty") diff --git a/providers/cos/cos.go b/providers/cos/cos.go index 9a406301..36ecead5 100644 --- a/providers/cos/cos.go +++ b/providers/cos/cos.go @@ -364,6 +364,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { } } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *Bucket) Close() error { return nil } type objectInfo struct { diff --git a/providers/filesystem/filesystem.go b/providers/filesystem/filesystem.go index 3206b91e..8ccd33b1 100644 --- a/providers/filesystem/filesystem.go +++ b/providers/filesystem/filesystem.go @@ -258,6 +258,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return os.IsNotExist(errors.Cause(err)) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *Bucket) Close() error { return nil } // Name returns the bucket name. diff --git a/providers/gcs/gcs.go b/providers/gcs/gcs.go index 947e641a..8b107c83 100644 --- a/providers/gcs/gcs.go +++ b/providers/gcs/gcs.go @@ -188,6 +188,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return errors.Is(err, storage.ErrObjectNotExist) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + func (b *Bucket) Close() error { return b.closer.Close() } diff --git a/providers/obs/obs.go b/providers/obs/obs.go index f0433708..1bc58aef 100644 --- a/providers/obs/obs.go +++ b/providers/obs/obs.go @@ -327,6 +327,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return false } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + // Attributes returns information about the specified object. func (b *Bucket) Attributes(ctx context.Context, name string) (objstore.ObjectAttributes, error) { output, err := b.client.GetObjectMetadata(&obs.GetObjectMetadataInput{ diff --git a/providers/oci/oci.go b/providers/oci/oci.go index aaf9fbe5..2be3210a 100644 --- a/providers/oci/oci.go +++ b/providers/oci/oci.go @@ -225,6 +225,11 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return false } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} + // ObjectSize returns the size of the specified object. func (b *Bucket) ObjectSize(ctx context.Context, name string) (uint64, error) { response, err := getObject(ctx, *b, name, "") diff --git a/providers/oss/oss.go b/providers/oss/oss.go index e8e73b56..08fcf1e3 100644 --- a/providers/oss/oss.go +++ b/providers/oss/oss.go @@ -378,3 +378,8 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { } return false } + +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(_ error) bool { + return false +} diff --git a/providers/s3/s3.go b/providers/s3/s3.go index 729ee7eb..6bc2b644 100644 --- a/providers/s3/s3.go +++ b/providers/s3/s3.go @@ -98,6 +98,9 @@ const ( // Storage class header. amzStorageClass = "X-Amz-Storage-Class" + + // amzKmsKeyAccessDeniedErrorMessage is the error message returned by s3 when the permissions to the KMS key is revoked. + amzKmsKeyAccessDeniedErrorMessage = "The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access." ) var DefaultConfig = Config{ @@ -144,7 +147,7 @@ type Config struct { } // SSEConfig deals with the configuration of SSE for Minio. The following options are valid: -// kmsencryptioncontext == https://docs.aws.amazon.com/kms/latest/developerguide/services-s3.html#s3-encryption-context +// KMSEncryptionContext == https://docs.aws.amazon.com/kms/latest/developerguide/services-s3.html#s3-encryption-context type SSEConfig struct { Type string `yaml:"type"` KMSKeyID string `yaml:"kms_key_id"` @@ -538,6 +541,12 @@ func (b *Bucket) IsObjNotFoundErr(err error) bool { return minio.ToErrorResponse(errors.Cause(err)).Code == "NoSuchKey" } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Bucket) IsCustomerManagedKeyError(err error) bool { + errResponse := minio.ToErrorResponse(errors.Cause(err)) + return errResponse.Code == "AccessDenied" && errResponse.Message == amzKmsKeyAccessDeniedErrorMessage +} + func (b *Bucket) Close() error { return nil } // getServerSideEncryption returns the SSE to use. diff --git a/providers/swift/swift.go b/providers/swift/swift.go index f30c655d..c24d03fd 100644 --- a/providers/swift/swift.go +++ b/providers/swift/swift.go @@ -290,6 +290,11 @@ func (c *Container) IsObjNotFoundErr(err error) bool { return errors.Is(err, swift.ObjectNotFound) } +// IsCustomerManagedKeyError returns true if the permissions for key used to encrypt the object was revoked. +func (b *Container) IsCustomerManagedKeyError(_ error) bool { + return false +} + // Upload writes the contents of the reader as an object into the container. func (c *Container) Upload(_ context.Context, name string, r io.Reader) (err error) { size, err := objstore.TryToGetSize(r) diff --git a/testing.go b/testing.go index d750142a..4e41b278 100644 --- a/testing.go +++ b/testing.go @@ -308,3 +308,7 @@ func (d *delayingBucket) IsObjNotFoundErr(err error) bool { // No delay for a local operation. return d.bkt.IsObjNotFoundErr(err) } + +func (d *delayingBucket) IsCustomerManagedKeyError(err error) bool { + return d.bkt.IsCustomerManagedKeyError(err) +} diff --git a/tracing.go b/tracing.go index 56f18ebe..9f09df66 100644 --- a/tracing.go +++ b/tracing.go @@ -101,6 +101,10 @@ func (t TracingBucket) IsObjNotFoundErr(err error) bool { return t.bkt.IsObjNotFoundErr(err) } +func (t TracingBucket) IsCustomerManagedKeyError(err error) bool { + return t.bkt.IsCustomerManagedKeyError(err) +} + func (t TracingBucket) WithExpectedErrs(expectedFunc IsOpFailureExpectedFunc) Bucket { if ib, ok := t.bkt.(InstrumentedBucket); ok { return TracingBucket{bkt: ib.WithExpectedErrs(expectedFunc)}