From 1391669d7f222349a6f6ed8e4a12faf6bcc6ba79 Mon Sep 17 00:00:00 2001 From: Sienna Satterwhite Date: Mon, 19 Aug 2024 14:34:08 -0600 Subject: [PATCH] added credential provider example Signed-off-by: Sienna Satterwhite --- go/credentialprovider/Makefile | 2 + go/credentialprovider/go.mod | 24 +++++ go/credentialprovider/go.sum | 30 ++++++ go/credentialprovider/main.go | 162 +++++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 go/credentialprovider/Makefile create mode 100644 go/credentialprovider/go.mod create mode 100644 go/credentialprovider/go.sum create mode 100644 go/credentialprovider/main.go diff --git a/go/credentialprovider/Makefile b/go/credentialprovider/Makefile new file mode 100644 index 0000000..2acb89d --- /dev/null +++ b/go/credentialprovider/Makefile @@ -0,0 +1,2 @@ +run: + go run main.go diff --git a/go/credentialprovider/go.mod b/go/credentialprovider/go.mod new file mode 100644 index 0000000..81c7c61 --- /dev/null +++ b/go/credentialprovider/go.mod @@ -0,0 +1,24 @@ +module github.com/localstack/localstack-aws-sdk-examples + +go 1.22.5 + +require ( + github.com/aws/aws-sdk-go v1.55.5 + github.com/aws/aws-sdk-go-v2 v1.30.4 + github.com/aws/aws-sdk-go-v2/config v1.27.28 + github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4 +) + +require ( + github.com/aws/aws-sdk-go-v2/credentials v1.17.28 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 // indirect + github.com/aws/smithy-go v1.20.4 // indirect +) diff --git a/go/credentialprovider/go.sum b/go/credentialprovider/go.sum new file mode 100644 index 0000000..6c5bada --- /dev/null +++ b/go/credentialprovider/go.sum @@ -0,0 +1,30 @@ +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= +github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= +github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4 h1:FXPO72iKC5YmYNEANltl763bUj8A6qT20wx8Jwvxlsw= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.4/go.mod h1:7idt3XszF6sE9WPS1GqZRiDJOxw4oPtlRBXodWnCGjU= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= diff --git a/go/credentialprovider/main.go b/go/credentialprovider/main.go new file mode 100644 index 0000000..fced4af --- /dev/null +++ b/go/credentialprovider/main.go @@ -0,0 +1,162 @@ +package main + +import ( + "context" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/service/sqs" +) + +const ( + AwsLocalEndpoint = "http://localhost:4566" + AwsLocalCredentialsName = "AwsLocalCredentials" //nolint:gosec + AwsLocalDefaultRegion = "us-east-1" + AwsLocalAccountId = "000000000000" //nolint:gosec + AwsLocalAccessKey = "test" //nolint:gosec + AwsLocalSecret = "test" //nolint:gosec +) + +var ( + ErrorAwsLocalCredentialsEmpty = "awslocal credentials are empty" //nolint:gosec +) + +// NewAwsLocalConfig returns a new [aws.Config] object configured to connect to LocalStack. +func NewAwsLocalConfig(ctx context.Context, accountId, endpoint, region, key, secret string, optFns ...func(*config.LoadOptions) error) aws.Config { + // load the opts + opts := []func(*config.LoadOptions) error{ + config.WithRegion(region), + config.WithCredentialsProvider(NewAwsLocalCredentialsProvider(key, secret, accountId)), + } + opts = append(opts, optFns...) + + cfg, err := config.LoadDefaultConfig(ctx, opts...) + if err != nil { + panic(err) + } + + cfg.BaseEndpoint = aws.String(endpoint) + return cfg +} + +// NewDefaultAwsLocalConfig returns a new default [aws.Config] object configured to connect to the default LocalStack. +func NewDefaultAwsLocalConfig() aws.Config { + cfg, err := config.LoadDefaultConfig(context.TODO(), + config.WithRegion(AwsLocalDefaultRegion), + config.WithCredentialsProvider(NewDefaultAwsLocalCredentialsProvider())) + if err != nil { + panic(err) + } + cfg.BaseEndpoint = aws.String(AwsLocalEndpoint) + return cfg +} + +// NewAwsLocalSQS returns a new [sqs.Client] object configured to connect to LocalStack +func NewAwsLocalSQS(cfg aws.Config) *sqs.Client { + return sqs.NewFromConfig(cfg, func(o *sqs.Options) { + o.BaseEndpoint = aws.String(AwsLocalEndpoint) + }) +} + +// to ensure AwsLocalCredentialsProvider implements the [aws.CredentialsProvider] interface +var _ aws.CredentialsProvider = (*AwsLocalCredentialsProvider)(nil) + +// A AwsLocalCredentialsProvider is a static credentials provider that returns the same credentials, +// designed for use with LocalStack +type AwsLocalCredentialsProvider struct { + Value aws.Credentials +} + +// NewDefaultAwsLocalCredentialsProvider returns an AwsLocalCredentialsProvider +// initialized with the default AwsLocal credentials. +func NewDefaultAwsLocalCredentialsProvider() AwsLocalCredentialsProvider { + return NewAwsLocalCredentialsProvider(AwsLocalAccessKey, AwsLocalSecret, AwsLocalAccountId) +} + +// NewAwsLocalCredentialsProvider return a StaticCredentialsProvider initialized with the AWS credentials passed in. +func NewAwsLocalCredentialsProvider(key, secret, accountId string) AwsLocalCredentialsProvider { + return AwsLocalCredentialsProvider{ + Value: aws.Credentials{ + AccessKeyID: key, + SecretAccessKey: secret, + AccountID: accountId, + SessionToken: "", + CanExpire: false, + }, + } +} + +// Retrieve returns the credentials or error if the credentials are invalid. +func (s AwsLocalCredentialsProvider) Retrieve(_ context.Context) (aws.Credentials, error) { + v := s.Value + if v.AccessKeyID == "" || v.SecretAccessKey == "" { + return aws.Credentials{ + Source: AwsLocalCredentialsName, + }, &AwsLocalCredentialsEmptyError{} + } + + if len(v.Source) == 0 { + v.Source = AwsLocalCredentialsName + } + + return v, nil +} + +func (s AwsLocalCredentialsProvider) IsExpired() bool { + return false +} + +// AwsLocalCredentialsEmptyError is emitted when the AwsLocal credentials are empty. +type AwsLocalCredentialsEmptyError struct{} + +func (*AwsLocalCredentialsEmptyError) Error() string { + return ErrorAwsLocalCredentialsEmpty +} + +func main() { + // build the client + sqsClient := NewAwsLocalSQS(NewDefaultAwsLocalConfig()) + + // create a new queue + queueResp, err := sqsClient.CreateQueue(context.TODO(), &sqs.CreateQueueInput{ + QueueName: aws.String("test-queue"), + }) + if err != nil { + panic(err) + } + + // print the queue URL + println("Queue URL:", *queueResp.QueueUrl) + + // send a message to the queue + sendResp, err := sqsClient.SendMessage(context.TODO(), &sqs.SendMessageInput{ + QueueUrl: queueResp.QueueUrl, + MessageBody: aws.String("Hello, world!"), + }) + if err != nil { + panic(err) + } + + // print the message ID + println("Message ID:", *sendResp.MessageId) + + // receive a message from the queue + receiveResp, err := sqsClient.ReceiveMessage(context.TODO(), &sqs.ReceiveMessageInput{ + QueueUrl: queueResp.QueueUrl, + }) + if err != nil { + panic(err) + } + + // print the message body + for _, message := range receiveResp.Messages { + println("Message Body:", *message.Body) + } + + // delete the queue + _, err = sqsClient.DeleteQueue(context.TODO(), &sqs.DeleteQueueInput{ + QueueUrl: queueResp.QueueUrl, + }) + if err != nil { + panic(err) + } +}