3
votes

I'm looking to integrade an S3 bucket with an API im developing, I'm running into this error wherever I go -

SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
        status code: 403

I have done the following

  1. Installed SDK & AWS CLI, and AWS configured
  2. Double(triple) checked spelling of key & secret key & bucket permissions
  3. Attempted with credentials document, .env, and even hard coding the values directly
  4. Tested with AWS CLI (THIS WORKS), so I believe I can rule out permissions, keys, as a whole.

I'm testing by trying to list buckets, here is the code taken directly from the AWS documentation-

sess := session.Must(session.NewSessionWithOptions(session.Options{   <--- DEBUGGER SET HERE
        SharedConfigState: session.SharedConfigEnable,
    }))

    svc := s3.New(sess)
    result, err := svc.ListBuckets(nil)
    if err != nil { exitErrorf("Unable to list buckets, %v", err) }

    for _, b := range result.Buckets {
        fmt.Printf("* %s created on %s\n", aws.StringValue(b.Name), aws.TimeValue(b.CreationDate))
    }

Using debugger, I can see the sessions config files as the program runs, the issue is potentially here

config -
       -> credentials 
                     -> creds
                         -> v
                           -> Access Key = ""
                           -> Secret Access Key  = ""
                           -> Token  = ""
                            
                     -> provider
                         ->value
                           -> Access Key With Value
                           -> Secret Access Key With Value
                           -> Token With Value

I personally cannot find any documentation regarding "creds" / "v", and I don't know if this is causing the issue. As I mentioned, I can use the AWS CLI to upload into the bucket, and even when I hard code my access key etc in to the Go SDK I receive this error.

Thank you for any thoughts, greatly appreciated.

2
Try explicitly setting the region.jordanm

2 Answers

3
votes

I just compiled your code and its executing OK ... one of the many ways to supply credentials to your binary is to populate these env vars

export AWS_ACCESS_KEY_ID=AKfoobarT2IJEAU4
export AWS_SECRET_ACCESS_KEY=oa6oT0Xxt4foobarbambazdWFCb
export AWS_REGION=us-west-2

that is all you need when using the env var approach ( your values are available using the aws console browser )

the big picture is to create a wrapper shell script ( bash ) which contains above three lines to populate the env vars to supply credentials then in same shell script execute the golang binary ( typically you compile the golang in some preliminary process ) ... in my case I store the values of my three env vars in encrypted files which the shell script decrypts just before it calls the above export commands

sometimes its helpful to drop kick and just use the aws command line equivalent commands to get yourself into the ballpark ... from a terminal run

aws s3 ls s3://cairo-mombasa-zaire --region  us-west-2

which can also use those same env vars shown above

for completeness here is your code with boilerplate added ... this runs OK and lists out the buckets

package main

import (

    "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/s3manager"

    "fmt"
    "os"
)


func exitErrorf(msg string, args ...interface{}) {
    fmt.Fprintf(os.Stderr, msg+"\n", args...)
    os.Exit(1)
}

func main() {

    region_env_var := "AWS_REGION"

    curr_region := os.Getenv(region_env_var)
    if curr_region == "" {
        exitErrorf("ERROR - failed to get region from env var %v", region_env_var)
    }

    fmt.Println("here is region ", curr_region)


    // Load session from shared config
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))


    svc := s3.New(sess)
    result, err := svc.ListBuckets(nil)
    if err != nil { exitErrorf("Unable to list buckets, %v", err) }

    for _, b := range result.Buckets {
        fmt.Printf("* %s created on %s\n", aws.StringValue(b.Name), aws.TimeValue(b.CreationDate))
    }
}
0
votes

If anyone else happens to have this problem,

The issue was regarding environment variables much like Scott suggest above, however it was due to lacking

export AWS_SDK_LOAD_CONFIG="true"

If this environment variable is not present, then the Golang SDK will not look for a credentials file, along with this, I instantiated environment variables for both my keys which allowed the connection to succeed.

To recap

  • if you're attempting to use the shared credentials folder, you must use the above noted environment variable to enable it.
  • If you're using environment variables, you shouldn't be affected by this problem.