Building a Secure AWS REST Request

2 min read
Simon Coope
Simon Coope

Table of Contents

Recently I've been working to create a bash script that can be used to make a curl request to AWS. Something I thought would be trivial ended up being quite fun to work on, the results of which can be seen in the bash script I've put into Github.

This post covers what's needed and why in a HTTP request to an AWS service. So I'll just do a brief TLDR below.


Basically, there's a process you need to follow to create an AWS Signature (V4), which is as follows:

  1. Create a Canonical Request - This is the structured request you are going to make including the HTTP verb, content type, host and request timestamp (X-Amz-Date).

  2. Hash the Canonical Request - We then create a SHA256 hash of the request text. This is used in the next step of creating a string for signing.

  3. Create a String for Signing - Now we create a string that is going to be signed. This string contains the details about the request including the timestamp (this has to be the same as in the canonical request), date, region, service (i.e. execute-api if using API Gateway) and the hash of the canonical request.

  4. Generate Signing Key - Now we derive a signing key from our AWS secret access key. We build the key up by concatenating the HMAC of the request date, region, service and type (i.e. aws4_request).

  5. Sign the String - Now we use the signing key created in the previous step to sign the string created in step 3.

  6. Create the Authorization Header - Finally we generate the authorization header by using the request information and signed string created previously in the relevant place in the header text below:

AWS4-HMAC-SHA256 Credential=ACCESS_KEY_ID/REQUEST_DATE/REQUEST_REGION/REQUEST_SERVICE/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=SIGNED_STRING

CURL Request

The CURL request can now be made in the script as follows and the with following headers:

curl -X GET $Url --http1.1 \
-H "Authorization: AUTHORIZATION_HEADER" \
-H "Content-Type: CONTENT_TYPE" \


If you're running into problems using the bash script I created please try the following:

  • System Date/Time - Remember we're generating a timestamp for the request, which will be validated in the AWS region. Therefore, if you're not in that timezone please ensure your system date/time is set accordingly.

  • CURL Errors - If you get curl errors try forcing it to us http1.1 as opposed to http2.0.