2

It seems pretty straight forward, but I am not able to figure out yet.

In the code such as below -

resp, err := http.Get("API Gateway endpoint url goes here")
if err != nil {
   log.Fatalln(err)
}

I am not sure how I tell http.get to use AWS auth. aws cli is configured the access key and secret on the host. So I do not want to again mention in the code.

Some posts mentioned about signing request. But I am not sure if that's the right way. In light of the AWS SDK in golang, this feels bit low level stuff. I would expect either

  1. There must a way in AWS SDK that encapsulates signing HTTP request etc. and does the job
  2. There must be a way to do this using http inbuild package by "somehow" attaching aws creds.

Any help is much, much appreciated!

Thanks Sandeep

Sandeep
  • 335
  • 1
  • 2
  • 24
  • Do you need to add certain http headers (e.g. `x-api-key`)? – jcfollower Jul 05 '22 at 13:47
  • It would probably help potential responders to know what the context is. E.g., is it for a certain API-Gateway endpoint? Does that API-Gateway project have certain requirements? Is this to trigger an AWS lambda function? ... – jcfollower Jul 05 '22 at 13:52
  • @jcfollower let's just say it's a simple call to an endpoint that's created using api gateway. That is a pretty common use case. A golang client wants to call this api endpoint from a server where aws cli has configured access key and secret. – Sandeep Jul 05 '22 at 14:03
  • I may be wrong, but I doubt that the aws cli access key and secret have anything to do with making a GET request on an API-Gateway endpoint. Does the owner of the API-Gateway endpoint have any documentation for how to access it? – jcfollower Jul 05 '22 at 14:34
  • Have you read through this? https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html – jcfollower Jul 05 '22 at 14:36
  • @jcfollower - yes. – Sandeep Jul 05 '22 at 14:45
  • Does this SO answer help? [edited -- new link] https://stackoverflow.com/a/68487025/856070 – jcfollower Jul 05 '22 at 14:56
  • No. I have mentioned in the question about the same. – Sandeep Jul 05 '22 at 16:51
  • `it's a simple call to an endpoint that's created using api gateway.` - what's the authentication method on the API gateway you set up? – gshpychka Jul 12 '22 at 16:07
  • `There must a way in AWS SDK that encapsulates signing HTTP request etc. and does the job` - there is, the answer linked above refers to `signer.SignHTTP` – gshpychka Jul 12 '22 at 16:11

1 Answers1

1

Some posts mentioned signing requests. But I am not sure if that's the right way

Yes, IAM Auth requires request signing (see docs here and here). The current method is Signature v4. Api Gateway accepts a request if it has the expected headers. "Signing" is the process of adding the right headers:

# signature is derived from your secret key and the request contents.
--header 'Authorization: AWS4-HMAC-SHA256 Credential=AKIASIAXTWO8D5GSN4CS/20220712/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=f2d8478ceff83d5cd0696502cb58a8331304846d11367d74608295c7acbfba0c'
# date prevents third parties from intercepting your request and resubmitting it later
--header 'X-Amz-Date: 20220712T124302Z'

There must a way in AWS SDK that encapsulates signing HTTP request etc. and does the job

For several languages (JS, Java, etc. but not Go), the get-sdk command can generate a SDK client for your Rest API that, among other conveniences, wraps the signature process: client.privateGet(params, body, additionalParams).

There must be a way to do this using http inbuild package by "somehow" attaching aws creds

Using the plain-old SDKs it's a bit more work to add the headers, easily wrappable in a resusable type:

ctx := context.TODO()

// define the request
endpoint := "https://cbi3vltq21.execute-api.us-east-1.amazonaws.com"
u, _ := url.ParseRequestURI(endpoint)
u.Path = "prod/private"
req, _ := http.NewRequest("GET", u.String(), nil)

// get the credentials from the local config files
cfg, _ := config.LoadDefaultConfig(ctx,
  config.WithRegion("us-east-1"),
  config.WithSharedConfigProfile("my-profile"))
creds, _ :=  cfg.Credentials.Retrieve(ctx) 

// hash the request body - hex value used in the signature
hash := sha256.Sum256([]byte("")) // if the request has no body, use the empty string
hexHash := fmt.Sprintf("%x", hash)

// add the Authorization and X-Amz-Date headers to the request
signer := v4.NewSigner()
_ = signer.SignHTTP(ctx, creds, req, hexHash, "execute-api", cfg.Region, time.Now())

// execute the request
client := &http.Client{}
resp, _ := client.Do(req)

H/T to this SO answer.

fedonev
  • 20,327
  • 2
  • 25
  • 34