Skip to content

Commit

Permalink
blob/s3blob: Add additional safety when specifying the encryption type
Browse files Browse the repository at this point in the history
Updates the EncryptionType field of s3blob.Options to use the AWS type. An error is thrown at initialisation time if an invalid value is provided for the ssetype parameter
  • Loading branch information
tristan-newmann committed Dec 1, 2023
1 parent 2017a81 commit b4dae37
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 25 deletions.
4 changes: 0 additions & 4 deletions aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ func ConfigFromURLParams(q url.Values) (*aws.Config, error) {
}
cfg.S3ForcePathStyle = aws.Bool(b)
case "awssdk":
case "ssetype":
case "kmskeyid":
// ignore, should be handled before this
default:
return nil, fmt.Errorf("unknown query parameter %q", param)
Expand Down Expand Up @@ -200,8 +198,6 @@ func V2ConfigFromURLParams(ctx context.Context, q url.Values) (awsv2.Config, err
case "profile":
opts = append(opts, awsv2cfg.WithSharedConfigProfile(value))
case "awssdk":
case "ssetype":
case "kmskeyid":
// ignore, should be handled before this
default:
return awsv2.Config{}, fmt.Errorf("unknown query parameter %q", param)
Expand Down
67 changes: 46 additions & 21 deletions blob/s3blob/s3blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"strings"

s3managerv2 "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
s3v2 "github.com/aws/aws-sdk-go-v2/service/s3"
typesv2 "github.com/aws/aws-sdk-go-v2/service/s3/types"
Expand All @@ -88,6 +81,12 @@ import (
"gocloud.dev/gcerrors"
"gocloud.dev/internal/escape"
"gocloud.dev/internal/gcerr"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
)

const defaultPageSize = 1000
Expand Down Expand Up @@ -144,32 +143,58 @@ type URLOpener struct {
Options Options
}

const (
SSETypeParamKey = "ssetype"
KMSKeyIdParamKey = "kmskeyid"
)

func IsValidServerSideEncryptionType(value string) bool {
// Surely there is a better way to get the values
for _, v := range typesv2.ServerSideEncryptionAes256.Values() {
if string(v) == value {
return true
}
}
return false
}

// OpenBucketURL opens a blob.Bucket based on u.
func (o *URLOpener) OpenBucketURL(ctx context.Context, u *url.URL) (*blob.Bucket, error) {
q := u.Query()

if sseType := q.Get(SSETypeParamKey); sseType != "" {
q.Del(SSETypeParamKey)

if !IsValidServerSideEncryptionType(sseType) {
return nil, fmt.Errorf("ssetype invalid %v", sseType)
}

o.Options.EncryptionType = typesv2.ServerSideEncryption(sseType)
}

if kmsKeyID := u.Query().Get(KMSKeyIdParamKey); kmsKeyID != "" {
q.Del(KMSKeyIdParamKey)
o.Options.KMSEncryptionID = kmsKeyID
}

if o.UseV2 {
cfg, err := gcaws.V2ConfigFromURLParams(ctx, u.Query())
cfg, err := gcaws.V2ConfigFromURLParams(ctx, q)
if err != nil {
return nil, fmt.Errorf("open bucket %v: %v", u, err)
}
clientV2 := s3v2.NewFromConfig(cfg)

o.Options.EncryptionType = u.Query().Get("ssetype")
o.Options.KMSEncryptionID = u.Query().Get("kmskeyid")

return OpenBucketV2(ctx, clientV2, u.Host, &o.Options)
}
configProvider := &gcaws.ConfigOverrider{
Base: o.ConfigProvider,
}
overrideCfg, err := gcaws.ConfigFromURLParams(u.Query())
overrideCfg, err := gcaws.ConfigFromURLParams(q)
if err != nil {
return nil, fmt.Errorf("open bucket %v: %v", u, err)
}
configProvider.Configs = append(configProvider.Configs, overrideCfg)

o.Options.EncryptionType = u.Query().Get("ssetype")
o.Options.KMSEncryptionID = u.Query().Get("kmskeyid")

return OpenBucket(ctx, configProvider, u.Host, &o.Options)
}

Expand All @@ -183,7 +208,7 @@ type Options struct {
// EncryptionType sets the encryption type headers when making write or
// copy calls. This is required if the bucket has a restrictive bucket
// policy that enforces a specific encryption type
EncryptionType string
EncryptionType typesv2.ServerSideEncryption

// KMSEncryptionID sets the kms key id header for write or copy calls.
// This is required when a bucket policy enforces the use of a specific
Expand Down Expand Up @@ -386,7 +411,7 @@ type bucket struct {
clientV2 *s3v2.Client
useLegacyList bool

encryptionType string
encryptionType typesv2.ServerSideEncryption
kmsKeyId string
}

Expand Down Expand Up @@ -997,7 +1022,7 @@ func (b *bucket) NewTypedWriter(ctx context.Context, key string, contentType str
reqV2.ContentMD5 = aws.String(base64.StdEncoding.EncodeToString(opts.ContentMD5))
}
if b.encryptionType != "" {
reqV2.ServerSideEncryption = typesv2.ServerSideEncryption(b.encryptionType)
reqV2.ServerSideEncryption = b.encryptionType
}
if b.kmsKeyId != "" {
reqV2.SSEKMSKeyId = aws.String(b.kmsKeyId)
Expand Down Expand Up @@ -1076,7 +1101,7 @@ func (b *bucket) NewTypedWriter(ctx context.Context, key string, contentType str
req.ContentMD5 = aws.String(base64.StdEncoding.EncodeToString(opts.ContentMD5))
}
if b.encryptionType != "" {
req.ServerSideEncryption = aws.String(b.encryptionType)
req.ServerSideEncryption = aws.String(string(b.encryptionType))
}
if b.kmsKeyId != "" {
req.SSEKMSKeyId = aws.String(b.kmsKeyId)
Expand Down Expand Up @@ -1119,7 +1144,7 @@ func (b *bucket) Copy(ctx context.Context, dstKey, srcKey string, opts *driver.C
Key: aws.String(dstKey),
}
if b.encryptionType != "" {
input.ServerSideEncryption = typesv2.ServerSideEncryption(b.encryptionType)
input.ServerSideEncryption = b.encryptionType
}
if b.kmsKeyId != "" {
input.SSEKMSKeyId = aws.String(b.kmsKeyId)
Expand All @@ -1146,7 +1171,7 @@ func (b *bucket) Copy(ctx context.Context, dstKey, srcKey string, opts *driver.C
Key: aws.String(dstKey),
}
if b.encryptionType != "" {
input.ServerSideEncryption = aws.String(b.encryptionType)
input.ServerSideEncryption = aws.String(string(b.encryptionType))
}
if b.kmsKeyId != "" {
input.SSEKMSKeyId = aws.String(b.kmsKeyId)
Expand Down
2 changes: 2 additions & 0 deletions blob/s3blob/s3blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,8 @@ func TestOpenBucketFromURL(t *testing.T) {
{"s3://mybucket?awssdk=v2", false},
// OK, use KMS Server Side Encryption
{"s3://mybucket?ssetype=aws:kms&kmskeyid=arn:aws:us-east-1:12345:key/1-a-2-b", false},
// Invalid ssetype
{"s3://mybucket?ssetype=aws:notkmsoraes&kmskeyid=arn:aws:us-east-1:12345:key/1-a-2-b", true},
// Invalid parameter together with a valid one.
{"s3://mybucket?profile=main&param=value", true},
// Invalid parameter.
Expand Down

0 comments on commit b4dae37

Please sign in to comment.