mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-06 08:15:48 -04:00
s3proxy: add intial implementation
INSECURE! The proxy intercepts GetObject and PutObject. A manual deployment guide is included. The decryption only relies on a hardcoded, static key. Do not use with sensitive data; testing only. * Ticket to track ranged GetObject: AB#3466.
This commit is contained in:
parent
957f8ad203
commit
a7ceda37ea
13 changed files with 1233 additions and 0 deletions
116
s3proxy/internal/s3/s3.go
Normal file
116
s3proxy/internal/s3/s3.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
/*
|
||||
Package s3 implements a very thin wrapper around the AWS S3 client.
|
||||
It only exists to enable stubbing of the AWS S3 client in tests.
|
||||
*/
|
||||
package s3
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
)
|
||||
|
||||
// Client is a wrapper around the AWS S3 client.
|
||||
type Client struct {
|
||||
s3client *s3.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new AWS S3 client.
|
||||
func NewClient(region string) (*Client, error) {
|
||||
// Use context.Background here because this context will not influence the later operations of the client.
|
||||
// The context given here is used for http requests that are made during client construction.
|
||||
// Client construction happens once during proxy setup.
|
||||
clientCfg, err := config.LoadDefaultConfig(
|
||||
context.Background(),
|
||||
config.WithRegion(region),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading AWS S3 client config: %w", err)
|
||||
}
|
||||
|
||||
client := s3.NewFromConfig(clientCfg)
|
||||
|
||||
return &Client{client}, nil
|
||||
}
|
||||
|
||||
// GetObject returns the object with the given key from the given bucket.
|
||||
// If a versionID is given, the specific version of the object is returned.
|
||||
func (c Client) GetObject(ctx context.Context, bucket, key, versionID, sseCustomerAlgorithm, sseCustomerKey, sseCustomerKeyMD5 string) (*s3.GetObjectOutput, error) {
|
||||
getObjectInput := &s3.GetObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &key,
|
||||
}
|
||||
if versionID != "" {
|
||||
getObjectInput.VersionId = &versionID
|
||||
}
|
||||
if sseCustomerAlgorithm != "" {
|
||||
getObjectInput.SSECustomerAlgorithm = &sseCustomerAlgorithm
|
||||
}
|
||||
if sseCustomerKey != "" {
|
||||
getObjectInput.SSECustomerKey = &sseCustomerKey
|
||||
}
|
||||
if sseCustomerKeyMD5 != "" {
|
||||
getObjectInput.SSECustomerKeyMD5 = &sseCustomerKeyMD5
|
||||
}
|
||||
|
||||
return c.s3client.GetObject(ctx, getObjectInput)
|
||||
}
|
||||
|
||||
// PutObject creates a new object in the given bucket with the given key and body.
|
||||
// Various optional parameters can be set.
|
||||
func (c Client) PutObject(ctx context.Context, bucket, key, tags, contentType, objectLockLegalHoldStatus, objectLockMode, sseCustomerAlgorithm, sseCustomerKey, sseCustomerKeyMD5 string, objectLockRetainUntilDate time.Time, metadata map[string]string, body []byte) (*s3.PutObjectOutput, error) {
|
||||
// The AWS Go SDK has two versions. V1 does not set the Content-Type header.
|
||||
// V2 always sets the Content-Type header. We use V2.
|
||||
// The s3 API sets an object's content-type to binary/octet-stream if
|
||||
// it receives a request without a Content-Type header set.
|
||||
// Since a client using V1 may depend on the Content-Type binary/octet-stream
|
||||
// we have to explicitly emulate the S3 API behavior, if we receive a request
|
||||
// without a Content-Type.
|
||||
if contentType == "" {
|
||||
contentType = "binary/octet-stream"
|
||||
}
|
||||
|
||||
contentMD5 := md5.Sum(body)
|
||||
encodedContentMD5 := base64.StdEncoding.EncodeToString(contentMD5[:])
|
||||
|
||||
putObjectInput := &s3.PutObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &key,
|
||||
Body: bytes.NewReader(body),
|
||||
Tagging: &tags,
|
||||
Metadata: metadata,
|
||||
ContentMD5: &encodedContentMD5,
|
||||
ContentType: &contentType,
|
||||
ObjectLockLegalHoldStatus: types.ObjectLockLegalHoldStatus(objectLockLegalHoldStatus),
|
||||
}
|
||||
if sseCustomerAlgorithm != "" {
|
||||
putObjectInput.SSECustomerAlgorithm = &sseCustomerAlgorithm
|
||||
}
|
||||
if sseCustomerKey != "" {
|
||||
putObjectInput.SSECustomerKey = &sseCustomerKey
|
||||
}
|
||||
if sseCustomerKeyMD5 != "" {
|
||||
putObjectInput.SSECustomerKeyMD5 = &sseCustomerKeyMD5
|
||||
}
|
||||
|
||||
// It is not allowed to only set one of these two properties.
|
||||
if objectLockMode != "" && !objectLockRetainUntilDate.IsZero() {
|
||||
putObjectInput.ObjectLockMode = types.ObjectLockMode(objectLockMode)
|
||||
putObjectInput.ObjectLockRetainUntilDate = &objectLockRetainUntilDate
|
||||
}
|
||||
|
||||
return c.s3client.PutObject(ctx, putObjectInput)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue