diff --git a/go.mod b/go.mod index 62dfd23..d08dd5d 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/hashicorp/boundary-plugin-aws go 1.20 +replace github.com/hashicorp/boundary/sdk => github.com/hashicorp/boundary/sdk v0.0.36-0.20230705165757-c7e98a6f1782 + require ( github.com/aws/aws-sdk-go v1.44.80 github.com/aws/aws-sdk-go-v2 v1.17.7 diff --git a/go.sum b/go.sum index 19adea4..46e76ed 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/boundary/sdk v0.0.33 h1:kHaVZ3b9j1QvYlG+vhAgrbXh8/+Rq2qlUIs8fKMQH7k= -github.com/hashicorp/boundary/sdk v0.0.33/go.mod h1:jn9j5mM8v2pOk8aLeJNIszdm7WBf4gRSP68iy8Iu5Q0= +github.com/hashicorp/boundary/sdk v0.0.36-0.20230705165757-c7e98a6f1782 h1:yiMQ/yM0irDm8DYGya+svk8nbcD89N8YkfdS7TzFRB0= +github.com/hashicorp/boundary/sdk v0.0.36-0.20230705165757-c7e98a6f1782/go.mod h1:jn9j5mM8v2pOk8aLeJNIszdm7WBf4gRSP68iy8Iu5Q0= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= diff --git a/plugin/service/storage/plugin.go b/plugin/service/storage/plugin.go index 497870c..5a36f75 100644 --- a/plugin/service/storage/plugin.go +++ b/plugin/service/storage/plugin.go @@ -9,6 +9,7 @@ import ( "context" "crypto/sha256" "encoding/base64" + "fmt" "io" "os" "path" @@ -17,6 +18,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws/retry" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/google/uuid" cred "github.com/hashicorp/boundary-plugin-aws/internal/credential" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/storagebuckets" @@ -714,5 +716,41 @@ func parseAWSErrCode(msg string, err error) error { if retryErr.IsErrorThrottle(err).Bool() { errCode = codes.Unavailable } - return status.Errorf(errCode, "%s: %s", msg, err) + st := status.New(errCode, fmt.Sprintf("%s: %s", msg, err)) + if aerr, ok := err.(awserr.Error); ok { + detail := &pb.ErrorDetail{ + Status: 500, + Code: aerr.Code(), + Message: aerr.Message(), + } + // aws error codes are strings that are more granular than status codes + // https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html + switch aerr.Code() { + case "AccessDenied": + // generic 403 response, who knows, credentials were invalidated, etc + detail.Status = 403 + errCode = codes.Unauthenticated + case "InvalidSecurity": + // these specific credentials aren't valid + fallthrough + case "InvalidAccessKeyId": + // a specific case for an access key being revoked. this is probably + // the one we want to watch out for + fallthrough + case "UnauthorizedAccess": + // standard 401 response, client is no longer authorized and may + // need new credentials + detail.Status = 401 + errCode = codes.Unauthenticated + default: + // we didn't get a code we were expecting, just fallback to previous + // logic. if we need to parse more codes in the future, we can. + } + + var sterr error + if st, sterr = st.WithDetails(detail); sterr != nil { + panic(fmt.Sprintf("Unexpected error while attaching AWS error metadata: %v", sterr)) + } + } + return st.Err() }