Search code examples
amazon-web-servicesgoaws-api-gatewayaws-sdk-gogo-cobra

API Gateway HTTP client request with IAM auth with Go


Hello StackOverflow AWS Gophers,

I'm implementing a CLI with the excellent cobra/viper packages from spf13. We have an Athena database fronted by an API Gateway endpoint, which authenticates with IAM.

That is, in order to interact with its endpoints by using Postman, I have to define AWS Signature as Authorization method, define the corresponding AWS id/secret and then in the Headers there will be X-Amz-Security-Token and others. Nothing unusual, works as expected.

Since I'm new to Go, I was a bit shocked to see that there are no examples to do this simple HTTP GET request with the aws-sdk-go itself... I'm trying to use the shared credentials provider (~/.aws/credentials), as demonstrated for the S3 client Go code snippets from re:Invent 2015:

req := request.New(nil)

How can I accomplish this seemingly easy feat in 2019 without having to resort to self-cooked net/http and therefore having to manually read ~/.aws/credentials or worse, go with os.Getenv and other ugly hacks?

Any Go code samples interacting as client would be super helpful. No Golang Lambda/server examples, please, there's plenty of those out there.


Solution

  • Unfortunately, it seems that the library has been updated since the accepted answer was written and the solution no longer is the same. After some trial and error, this appears to be the more current method of handling the signing (using https://pkg.go.dev/github.com/aws/aws-sdk-go-v2):

    import (
        "context"
        "net/http"
        "time"
    
        "github.com/aws/aws-sdk-go-v2/config"
        "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
    )
    
    func main() {
        // Context is not being used in this example.
        cfg, err := config.LoadDefaultConfig(context.TODO())
    
        if err != nil {
            // Handle error.
        }
    
        credentials, err := cfg.Credentials.Retrieve(context.TODO())
    
        if err != nil {
            // Handle error.
        }
    
        // The signer requires a payload hash. This hash is for an empty payload.
        hash := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
        req, _ := http.NewRequest(http.MethodGet, "api-gw-url", nil)
        signer := v4.NewSigner()
        err = signer.SignHTTP(context.TODO(), credentials, req, hash, "execute-api", cfg.Region, time.Now())
    
        if err != nil {
            // Handle error.
        }
    
        // Use `req`
    }