Skip to content

Instantly share code, notes, and snippets.

@robert-claypool
Last active November 20, 2015 07:52
Show Gist options
  • Save robert-claypool/fe0cba631684ee5be5d0 to your computer and use it in GitHub Desktop.
Save robert-claypool/fe0cba631684ee5be5d0 to your computer and use it in GitHub Desktop.
This script prints a signed URL for HTTP GET'ting a file from AWS CloudFront
#!/bin/bash
#================================================================
# HEADER
#================================================================
#% SYNOPSIS
#+ ${script_name} [-h] [-o[file]] input_date path
#%
#% DESCRIPTION
#% This script prints a signed URL for HTTP GET'ting a file
#% from AWS CloudFront https://sendr.example.com
#%
#% OPTIONS
#% -o [file], --output=[file] File to save the resulting URL (default=results.txt)
#% -h, --help Print this help
#%
#% EXAMPLES
#% ${script_name} -o result.txt "29 Feb 2017" "/path/to/file.txt"
#%
#================================================================
# END_OF_HEADER
#================================================================
# Define usage variables and the function.
script_headsize=$(head -200 ${0} |grep -n "^# END_OF_HEADER" | cut -f1 -d:)
script_name="$(basename ${0})"
usage() { head -${script_headsize:-99} ${0} | grep -e "^#[%+-]" | sed -e "s/^#[%+-]//g" -e "s/\${script_name}/${script_name}/g" ; }
# Set a default output.
output_file="results.txt"
# Do we have an option to handle?
case "$1" in
-h|--help)
usage
exit 0
;;
-o|--output)
output_file=$2
shift 2
;;
*)
break
;;
esac
# Begin the script itself...
# The input date is mostly a free format human readable date string
# such as "29 Feb 2017", see http://gnu.org/software/coreutils/date
# We convert it to seconds since the epoch, 1970-01-01 00:00:00 UTC
# Warning that a date like "Feb 29 2017" will get converted into
# "Sun Mar 1 20:17:00 CST 2015" (where 2015 is the current year)!
input_date=$1
expiration_seconds=$(date --date "$input_date" +%s)
# build the web address
host="https://sendr.example.com"
path=$2 # This should begin with a slash, e.g. "/path/to/file.txt" or just "/file.txt" if it's at the root.
url=$host$path
# Our custom policy does not limit by IP, but we could add that.
# See http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html
policy="{\"Statement\":[{\"Resource\":\"$url\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":$expiration_seconds}}}]}"
# The signature is our policy - hashed, signed, and base64 encoded.
# Since the signature is passed as a query string parameter, we also replace +=/ because they are invalid query string characters.
# "tr -d '\n\r'" takes out the trailing newline which screws up the signature Amazon will be looking for.
signature=$(echo "$policy" | tr -d '\n\r' | openssl sha1 -sign privatekey.pem | openssl base64 | tr -- '+=/' '-_~')
# The trusted account for this CloudFront distribution must have a CloudFront public/private keypair.
# The following ID tells Amazon which keypair to use when checking the 'Signature' query string parameter.
keypair_id="MYKEYID"
# Now we build the URL and just save it out to a text file.
# Amazon will check the expiration inside our encrypted policy file against the 'Expires' query string parameter to validate stuff.
# If you don't pass the 'Expires' parameter, then you have to base64 encode the entire policy and pass that instead.
# We use 'Expires' because it's shorter and less to calculate.
echo $input_date >> $output_file
echo $path >> $output_file
echo $policy >> $output_file
echo "$url?Expires=$expiration_seconds&Signature=$signature&Key-Pair-Id=$keypair_id" | tr -d ' \n\r' >> $output_file
echo "" >> $output_file # Add a newline because it was stripped with 'tr' in the line above.
echo "--------------------------------------------------------" >> $output_file
echo "done"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment