Skip to content

Instantly share code, notes, and snippets.

@danvas
Last active November 28, 2023 20:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danvas/db2f1a4109b9acdb2d3715be71072cb9 to your computer and use it in GitHub Desktop.
Save danvas/db2f1a4109b9acdb2d3715be71072cb9 to your computer and use it in GitHub Desktop.
Signing AWS API requests

Signing AWS API requests

Implentation of calculating a signature for signing AWS API requests. Specifically, this script invalidates all files (/*) in a Cloudfront distribution via a signed API request.

To run it, edit the .sh file by settting AWS_ACCESS_KEY, AWS_SECRET_KEY, and DISTRIBUTION_ID with your values, and source the file in a shell:

source signedAWSRequest.sh

This script uses openssl, xxd, and other standard UNIX commands (such as awk).

If you would like invalidate a single file, then change the path value in the Path element (currently it's set to /*). You can find more information on how to calculate the required signature here: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html#signing-request-intro

AWS_ACCESS_KEY=<your access key>
AWS_SECRET_KEY=<your secret key>
AWS_REGION="us-east-1" # Note: When requesting from Cloudfront, region must be set to us-east-1
DISTRIBUTION_ID=<cloudfront distribution ID>
ALGORITHM="AWS4-HMAC-SHA256"
# Create a timestamp for the X-Amz-Date header
amz_date=$(date -u +'%Y%m%dT%H%M%SZ')
# Create a date for the Authorization header
datestamp=$(echo -en $amz_date | cut -c1-8)
# Generate the canonical request
cf_resource=/2020-05-31/distribution/$DISTRIBUTION_ID/invalidation
payload="<InvalidationBatch xmlns=\"http://cloudfront.amazonaws.com/doc/2020-05-31/\"><CallerReference>cli-${amz_date}</CallerReference><Paths><Quantity>1</Quantity><Items><Path>/*</Path></Items></Paths></InvalidationBatch>"
hashed_payload=$(echo -en "$payload" | openssl dgst -sha256 -binary | xxd -p -c 0)
canonical_request="POST\n${cf_resource}\n\nhost:cloudfront.amazonaws.com\nx-amz-content-sha256:${hashed_payload}\nx-amz-date:${amz_date}\n\nhost;x-amz-content-sha256;x-amz-date\n${hashed_payload}"
hashed_canonical_request=$(echo -en "$canonical_request" | openssl sha256 | awk '{print $2}')
# echo "Canonical Request:\n${canonical_request}\n(hash: ${hashed_canonical_request})\n==========================\n"
# Generate the string to sign
STRING_TO_SIGN=$ALGORITHM$'\n'$amz_date$'\n'$datestamp/$AWS_REGION/cloudfront/aws4_request$'\n'$hashed_canonical_request
# Generate the signature
k_date=$(echo -n "${datestamp}" | openssl sha256 -hmac "AWS4${AWS_SECRET_KEY}" -binary)
k_region=$(echo -n "${AWS_REGION}" | openssl sha256 -hmac "${k_date}" -binary)
k_service=$(echo -n "cloudfront" | openssl sha256 -hmac "${k_region}" -binary)
k_signing=$(echo -n "aws4_request" | openssl sha256 -hmac "${k_service}" -binary)
signature=$(echo -en "${STRING_TO_SIGN}" | openssl sha256 -hmac "${k_signing}" | awk '{print $2}')
echo curl -v "https://cloudfront.amazonaws.com${cf_resource}" \
-H "\"x-amz-date: $amz_date\"" \
-H "\"x-amz-content-sha256: $hashed_payload\"" \
-H "\"Authorization: $ALGORITHM Credential=$AWS_ACCESS_KEY/$datestamp/$AWS_REGION/cloudfront/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=$signature\"" \
--data "\"${payload}\""
curl "https://cloudfront.amazonaws.com${cf_resource}" \
-H "x-amz-date: $amz_date" \
-H "x-amz-content-sha256: $hashed_payload" \
-H "Authorization: $ALGORITHM Credential=$AWS_ACCESS_KEY/$datestamp/$AWS_REGION/cloudfront/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=$signature" \
--data "$payload"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment