Skip to content

Instantly share code, notes, and snippets.

@coisme
Created June 6, 2023 08:19
Show Gist options
  • Save coisme/a47f9ceed259bc7e2c6142d1bf690d4b to your computer and use it in GitHub Desktop.
Save coisme/a47f9ceed259bc7e2c6142d1bf690d4b to your computer and use it in GitHub Desktop.
Signed request sample for API Gateway
#!/bin/zsh
#
# Signed request sample script for API Gateway
#
# @Author: Osamu Koizumi
#
# Official Document:
# Create a signed AWS API request
# https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html
#
# Prerequisites:
# - Create an API Gateway resource by following this page:
# https://qiita.com/ita-k/items/5d6e8ceaf3f0a970b594
# and get the following parameters.
# * Access Key ID
# * Secret Access Key
# * Invoke URL (incl. host, service, region, and stage name.)
#
# Tested on:
# macOS 13.3.1
# OpenSSL 3.0.0 7 sep 2021 (Library: OpenSSL 3.0.0 7 sep 2021)
# curl 7.87.0
# User setting
#
# From IAM console
AWS_ACCESS_KEY="YOUR_ACCESS_KEY"
AWS_SECRET_ACCESS_KEY="YOUR_SECRET_ACCESS_KEY"
# From API Gateway Invoke URL
HOST="**********.execute-api.ap-northeast-1.amazonaws.com"
SERVICE="execute-api"
REGION="ap-northeast-1"
STAGE_NAME="test"
# Enable debug print: 1 - enable, other values - disable
DEBUG=0
#
# Step 1: Create a canonical request
#
PAYLOAD=""
CURRENT_DATETIME=`date -u +'%Y%m%dT%H%M%SZ'`
HTTP_METHOD="GET"
CANONICAL_URI="/${STAGE_NAME}"
CANONICAL_QUERY_STRING=""
CANONICAL_HEADERS="host:${HOST}
x-amz-date:${CURRENT_DATETIME}
"
SIGNED_HEADERS="host;x-amz-date"
HASHED_PAYLOAD=`echo -n ${PAYLOAD} \
| openssl dgst -sha256 -hex \
| sed 's/^.* //'`
CANONICAL_REQUEST="${HTTP_METHOD}
${CANONICAL_URI}
${CANONICAL_QUERY_STRING}
${CANONICAL_HEADERS}
${SIGNED_HEADERS}
${HASHED_PAYLOAD}"
if [[ ${DEBUG} -eq 1 ]] then
echo "=== Canonical request ==="
echo "${CANONICAL_REQUEST}"
echo "=== /Canonical request ==="
fi
#
# Step 2: Create a hash of the canonical request
#
HASHED_CANONICAL_REQUEST=`echo -n "${CANONICAL_REQUEST}" \
| openssl dgst -sha256 -hex \
| sed 's/^.* //'`
#
# Step 3: Create a string to sign
#
CURRENT_DATE=`echo -n ${CURRENT_DATETIME} | awk -F'T' '{print $1}'`
ALGORITHM="AWS4-HMAC-SHA256"
REQUEST_DATETIME=${CURRENT_DATETIME}
CREDENTIAL_SCOPE="${CURRENT_DATE}/${REGION}/${SERVICE}/aws4_request"
STRING_TO_SIGN="${ALGORITHM}
${REQUEST_DATETIME}
${CREDENTIAL_SCOPE}
${HASHED_CANONICAL_REQUEST}"
if [[ ${DEBUG} -eq 1 ]] then
echo "=== String to sign ==="
echo "${STRING_TO_SIGN}"
echo "=== /String to sign ==="
echo
fi
#
# Step 4: Calculate the signature
#
K_DATE=`echo -n "${CURRENT_DATE}" \
| openssl dgst -sha256 -hex -hmac "AWS4${AWS_SECRET_ACCESS_KEY}" \
| sed 's/^.* //'`
K_REGION=`echo -n "${REGION}" \
| openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${K_DATE}" \
| sed 's/^.* //'`
K_SERVICE=`echo -n "${SERVICE}" \
| openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${K_REGION}" \
| sed 's/^.* //'`
K_SIGNING=`echo -n "aws4_request" \
| openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${K_SERVICE}" \
| sed 's/^.* //'`
SIGNATURE=`echo -n "${STRING_TO_SIGN}" \
| openssl dgst -sha256 -hex -mac HMAC -macopt "hexkey:${K_SIGNING}" \
| sed 's/^.* //'`
if [[ ${DEBUG} -eq 1 ]] then
echo "=== Signature ==="
echo "signature: ${SIGNATURE}"
echo "=== /Signature ==="
fi
#
# Step 5: Add the signature to the request
#
# Without signature
# Expected result:
# {"message":"Missing Authentication Token"}
echo "Request without signature (fail)"
curl -X GET "https://${HOST}/${STAGE_NAME}"
echo "\n"
# With signature
# Expected result (depends on implementation of Lambda function):
# {"statusCode": 200, "body": "\"Hello from Lambda!\""}
echo "Request with signature (success)"
curl -X GET \
-H "Host: ${HOST}" \
-H "X-Amz-Date: ${CURRENT_DATETIME}" \
-H \
"Authorization: AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY}/"\
"${CREDENTIAL_SCOPE}, SignedHeaders=${SIGNED_HEADERS},"\
"Signature=${SIGNATURE}" \
"https://${HOST}/${STAGE_NAME}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment