Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(treasury): upgrade to aws-sdk-go-v2 #220

Merged
merged 3 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

"github.com/AirHelp/treasury/backend/s3"
"github.com/AirHelp/treasury/backend/ssm"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go-v2/aws"
)

const (
Expand Down Expand Up @@ -38,5 +38,5 @@ func New(options Options) (BackendAPI, error) {
case ssmName:
return ssm.New(options.Region, options.AWSConfig)
}
return nil, errors.New("Invalid backend")
return nil, errors.New("invalid backend")
}
40 changes: 18 additions & 22 deletions backend/s3/aws.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,41 @@
package s3

import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3iface"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

// Client with AWS services
type S3ClientInterface interface {
PutObject(context.Context, *s3.PutObjectInput, ...func(*s3.Options)) (*s3.PutObjectOutput, error)
GetObject(context.Context, *s3.GetObjectInput, ...func(*s3.Options)) (*s3.GetObjectOutput, error)
ListObjects(context.Context, *s3.ListObjectsInput, ...func(*s3.Options)) (*s3.ListObjectsOutput, error)
DeleteObject(context.Context, *s3.DeleteObjectInput, ...func(*s3.Options)) (*s3.DeleteObjectOutput, error)
}

type Client struct {
sess *session.Session
S3Svc s3iface.S3API
S3Svc S3ClientInterface
bucket string
}

// New returns clients for AWS services
func New(region, bucket string) (*Client, error) {
if bucket == "" {
return nil, errors.New("S3 bucket name is missing")
}
sessionOpts := session.Options{
SharedConfigState: session.SharedConfigEnable,
}
cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region))

if region != "" {
sessionOpts.Config = aws.Config{Region: aws.String(region)}
}

sess, err := session.NewSessionWithOptions(sessionOpts)
if err != nil {
return nil, fmt.Errorf("Failed to create AWS session. Error: %s", err)
return &Client{}, errors.Join(
fmt.Errorf("unable to load SDK config with region %s", region),
err,
)
}

s3Svc := s3.New(sess)

return &Client{
sess: sess,
S3Svc: s3Svc,
bucket: bucket,
}, nil
S3Svc: s3.NewFromConfig(cfg),
}, err
}
28 changes: 13 additions & 15 deletions backend/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ package s3

import (
"bytes"
"context"
"fmt"

"github.com/AirHelp/treasury/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
s3Types "github.com/aws/aws-sdk-go-v2/service/s3/types"
)

const (
// http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html
s3ACL = "private"
// http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html
s3ServerSideEncryption = "aws:kms"
// ApplicatonMetaKey is used as a Key for s3 object's metadata and tag
ApplicatonMetaKey = "Application"
// EnvironmentMetaKey is used as a Key for s3 object's metadata and tag
Expand All @@ -35,18 +33,18 @@ func (c *Client) PutObject(object *types.PutObjectInput) error {
params := &s3.PutObjectInput{
Bucket: aws.String(c.bucket),
Key: aws.String(object.Key),
ACL: aws.String(s3ACL),
ACL: s3Types.ObjectCannedACLPrivate,
Body: bytes.NewReader([]byte(object.Value)),
Metadata: map[string]*string{
ApplicatonMetaKey: aws.String(object.Application),
EnvironmentMetaKey: aws.String(object.Environment),
Metadata: map[string]string{
ApplicatonMetaKey: object.Application,
EnvironmentMetaKey: object.Environment,
},
ServerSideEncryption: aws.String(s3ServerSideEncryption),
ServerSideEncryption: s3Types.ServerSideEncryptionAwsKms,
SSEKMSKeyId: aws.String("alias/" + object.Environment),
Tagging: aws.String(tags),
}

_, err := c.S3Svc.PutObject(params)
_, err := c.S3Svc.PutObject(context.Background(), params)

return err
}
Expand All @@ -61,7 +59,7 @@ func (c *Client) GetObject(object *types.GetObjectInput) (*types.GetObjectOutput
Key: aws.String(object.Key),
}

resp, err := c.S3Svc.GetObject(params)
resp, err := c.S3Svc.GetObject(context.Background(), params)
if err != nil {
return nil, err
}
Expand All @@ -78,7 +76,7 @@ func (c *Client) GetObjects(object *types.GetObjectsInput) (*types.GetObjectsOup
Prefix: aws.String(object.Prefix),
}

resp, err := c.S3Svc.ListObjects(params)
resp, err := c.S3Svc.ListObjects(context.Background(), params)
if err != nil {
return nil, err
}
Expand All @@ -99,6 +97,6 @@ func (c *Client) DeleteObject(object *types.DeleteObjectInput) error {
Bucket: aws.String(c.bucket),
Key: aws.String(object.Key),
}
_, err := c.S3Svc.DeleteObject(params)
_, err := c.S3Svc.DeleteObject(context.Background(), params)
return err
}
33 changes: 15 additions & 18 deletions backend/ssm/aws.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
package ssm

import (
"context"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go/service/ssm/ssmiface"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/ssm"
)

type SSMClientInterface interface {
GetParameter(context.Context, *ssm.GetParameterInput, ...func(*ssm.Options)) (*ssm.GetParameterOutput, error)
PutParameter(context.Context, *ssm.PutParameterInput, ...func(*ssm.Options)) (*ssm.PutParameterOutput, error)
GetParametersByPath(context.Context, *ssm.GetParametersByPathInput, ...func(*ssm.Options)) (*ssm.GetParametersByPathOutput, error)
DeleteParameter(context.Context, *ssm.DeleteParameterInput, ...func(*ssm.Options)) (*ssm.DeleteParameterOutput, error)
}

// Client with AWS services
type Client struct {
svc ssmiface.SSMAPI
svc SSMClientInterface
}

// New returns clients for AWS services
func New(region string, awsConfig aws.Config) (*Client, error) {
if region != "" {
awsConfig = *awsConfig.WithRegion(region)
}

sess, err := session.NewSessionWithOptions(session.Options{
Config: awsConfig,
})
cfg, err := config.LoadDefaultConfig(context.Background(), config.WithRegion(region))
if err != nil {
return nil, fmt.Errorf("Failed to create AWS session. Error: %s", err)
return nil, fmt.Errorf("failed to load AWS configuration. Error: %s", err)
}

// Create a SSM client with additional configuration
svc := ssm.New(sess)

return &Client{
svc: svc,
svc: ssm.NewFromConfig(cfg),
}, nil
}
2 changes: 1 addition & 1 deletion backend/ssm/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"

"github.com/AirHelp/treasury/backend/ssm"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go-v2/aws"
)

func TestNew(t *testing.T) {
Expand Down
34 changes: 18 additions & 16 deletions backend/ssm/ssm.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package ssm

import (
"context"
"errors"

"github.com/AirHelp/treasury/types"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ssm"
ssmtypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
)

const defaultParameterType = "SecureString"
Expand All @@ -17,34 +19,34 @@ func (c *Client) PutObject(object *types.PutObjectInput) error {
if object.Key == "" {
return errors.New("The key name is not valid.")
}
// https://docs.aws.amazon.com/sdk-for-go/api/service/ssm/#PutParameterInput
// https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/ssm#PutParameterInput
putParameterInput := &ssm.PutParameterInput{
KeyId: aws.String("alias/" + object.Environment),
// we decided to use path based keys without `/` at the begining
// we decided to use path based keys without `/` at the beginning
// so we need to add it here
Name: aws.String("/" + object.Key),
Type: aws.String(defaultParameterType),
Type: ssmtypes.ParameterType(defaultParameterType),
Value: aws.String(object.Value),
Overwrite: aws.Bool(true),
}

// PutParameter returns Version of the parameter
// shall we validate this version?
_, err := c.svc.PutParameter(putParameterInput)
_, err := c.svc.PutParameter(context.Background(), putParameterInput)
return err
}

// GetObject returns a secret for given key
func (c *Client) GetObject(object *types.GetObjectInput) (*types.GetObjectOutput, error) {
params := &ssm.GetParameterInput{
// we decided to use path based keys without `/` at the begining
// we decided to use path based keys without `/` at the beginning
// so we need to add it here
Name: aws.String("/" + object.Key),
// Retrieve all parameters in a hierarchy with their value decrypted.
WithDecryption: aws.Bool(true),
}

resp, err := c.svc.GetParameter(params)
resp, err := c.svc.GetParameter(context.Background(), params)
if err != nil {
return nil, err
}
Expand All @@ -55,21 +57,21 @@ func (c *Client) GetObject(object *types.GetObjectInput) (*types.GetObjectOutput
// GetObjects returns key value map for given pattern/prefix
func (c *Client) GetObjects(object *types.GetObjectsInput) (*types.GetObjectsOuput, error) {
var nextToken *string
var parameters []*ssm.Parameter
var parameters []ssmtypes.Parameter
for {
// https://docs.aws.amazon.com/sdk-for-go/api/service/ssm/#SSM.GetParametersByPath
// https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/ssm#GetParametersByPathInput
getParametersByPathInput := &ssm.GetParametersByPathInput{
Path: aws.String("/" + object.Prefix),
// Retrieve all parameters in a hierarchy with their value decrypted.
WithDecryption: aws.Bool(true),
MaxResults: aws.Int64(10),
MaxResults: aws.Int32(10),
NextToken: nextToken,
}

// we're only interested with GetParametersByPathOutput.Parameters
// Parameters []*Parameter `type:"list"`
// Parameters []Parameter `type:"list"`
// See also, https://docs.aws.amazon.com/goto/WebAPI/ssm-2014-11-06/Parameter
resp, err := c.svc.GetParametersByPath(getParametersByPathInput)
resp, err := c.svc.GetParametersByPath(context.Background(), getParametersByPathInput)
if err != nil {
return nil, err
}
Expand All @@ -90,7 +92,7 @@ func (c *Client) GetObjects(object *types.GetObjectsInput) (*types.GetObjectsOup
return &types.GetObjectsOuput{Secrets: keyValuePairs}, nil
}

// unShash removes 1st char from a string
// unSlash removes 1st char from a string
// GetParametersByPath from SSM returns key path with "/" at the beginning
// but we don't need it :)
func unSlash(input string) string {
Expand All @@ -102,10 +104,10 @@ func unSlash(input string) string {

func (c *Client) DeleteObject(object *types.DeleteObjectInput) error {
params := &ssm.DeleteParameterInput{
// we decided to use path based keys without `/` at the begining
// we decided to use path based keys without `/` at the beginning
// so we need to add it here
Name: aws.String("/" + object.Key),
}
_, err := c.svc.DeleteParameter(params)
_, err := c.svc.DeleteParameter(context.Background(), params)
return err
}
2 changes: 1 addition & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package client

import (
"github.com/AirHelp/treasury/backend"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go-v2/aws"
)

const (
Expand Down
4 changes: 2 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package client
import (
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go-v2/aws"
)

func TestNew(t *testing.T) {
Expand All @@ -24,7 +24,7 @@ func TestNew(t *testing.T) {
},
{
name: "add aws config",
args: args{options: &Options{AWSConfig: aws.Config{Region: aws.String("eu-west-1")}}},
args: args{options: &Options{AWSConfig: aws.Config{Region: "eu-west-1"}}},
want: &Client{},
wantErr: false,
},
Expand Down
20 changes: 7 additions & 13 deletions client/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@ package client
import (
"github.com/AirHelp/treasury/types"
"github.com/AirHelp/treasury/utils"
"github.com/aws/aws-sdk-go/aws/awserr"
s3Types "github.com/aws/aws-sdk-go-v2/service/s3/types"

"bytes"
"compress/gzip"
b64 "encoding/base64"
"errors"
"io/ioutil"
)

const (
noSuchKey = "NoSuchKey"
noSuchParameter = "ParameterNotFound"
)

// Write secret to Treasure
func (c *Client) Write(key, secret string, force bool) error {
environment, application, err := utils.FindEnvironmentApplicationName(key)
Expand All @@ -25,14 +21,12 @@ func (c *Client) Write(key, secret string, force bool) error {

if !force {
secretObject, err := c.Read(key)

if err != nil {
if aerr, ok := err.(awserr.Error); ok {
// in this case 404 is ok for us
// so we'd proceed if 404 occurs
if aerr.Code() != noSuchKey && aerr.Code() != noSuchParameter {
return err
}
} else {
var nsk *s3Types.NoSuchKey
var nf *s3Types.NotFound

if !errors.As(err, &nsk) && !errors.As(err, &nf) {
return err
}
} else if secret == secretObject.Value {
Expand Down
Loading