Skip to content

Commit

Permalink
Merge pull request #220 from AirHelp/upgrade-aws-sdk-go-to-v2-version
Browse files Browse the repository at this point in the history
feat(treasury): upgrade to aws-sdk-go-v2
  • Loading branch information
tcharewicz authored Aug 29, 2024
2 parents 83cea6b + f00e3c0 commit e412bb3
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 115 deletions.
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

0 comments on commit e412bb3

Please sign in to comment.