Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active March 16, 2021 23:07
Show Gist options
  • Save Integralist/70e455bb56bd5d780c7b01704fc368ed to your computer and use it in GitHub Desktop.
Save Integralist/70e455bb56bd5d780c7b01704fc368ed to your computer and use it in GitHub Desktop.
[AWS CloudFront Signed-Cookie Access] #aws #cloudfront #cookie #planz
#!/usr/bin/env bash
#
# chmod +x ./planz.sh
#
# For usage try:
# ./planz.sh -h
# ./planz.sh help
file=/tmp/planz_credentials
function generate_policy_template {
# <<- is different from << in that you can indent the contents
# but you can only indent using tabs (not spaces)
cat > policy.json <<-EOF
{
"Statement":[
{
"Resource":"https://plan-z.buzzfeed.com/*",
"Condition":{
"DateLessThan":{
"AWS:EpochTime": {{date}}
}
}
}
]
}
EOF
}
function init {
local cookie_ttl_hours="+${1:-2}H" # default to two hours cookie ttl
local CLOUDFRONT_PRIVATE_KEY_CONTAINER=./cloudfront-keypair.tgz.asc
local CLOUDFRONT_PRIVATE_KEY_ID=APKAIT3GGGOSP434T2JQ
local CLOUDFRONT_PRIVATE_KEY="pk-$CLOUDFRONT_PRIVATE_KEY_ID.pem"
if [ ! -f "$CLOUDFRONT_PRIVATE_KEY_CONTAINER" ]; then
echo "You need the AWS CloudFront keypair file: $CLOUDFRONT_PRIVATE_KEY_CONTAINER"
exit 1
fi
rm "$file" 2>/dev/null
rm policy.json 2>/dev/null
rm policy.json.backup 2>/dev/null
generate_policy_template
sed -i ".backup" "s/{{date}}/$(date -u -v "$cookie_ttl_hours" +%s)/" policy.json
# Linux version
# sed -i ".backup" "s/{{date}}/$(date -d "today 1 hour" +%s)/" policy.json
if [ ! -f "./$CLOUDFRONT_PRIVATE_KEY" ]; then
gpg -d "$CLOUDFRONT_PRIVATE_KEY_CONTAINER" | tar -zxv -C ./ --strip-components=3
fi
# shellcheck disable=SC2155,SC2002
export POLICY=$(cat policy.json | tr -d " \t\n\r" | base64 | tr '+=/' '-_~')
# shellcheck disable=SC2155,SC2002
export SIGNATURE=$(cat policy.json | tr -d " \t\n\r" | openssl sha1 -sign $CLOUDFRONT_PRIVATE_KEY | base64 | tr '+=/' '-_~')
{
echo "CLOUDFRONT_PRIVATE_KEY=$CLOUDFRONT_PRIVATE_KEY"
echo "ID=$CLOUDFRONT_PRIVATE_KEY_ID"
echo "POLICY=$POLICY"
echo "SIGNATURE=$SIGNATURE"
} >> "$file"
cat "$file"
}
function web {
cat "$file"
}
function req {
local path=$1
# shellcheck disable=SC2155
local id=$(web | awk 'NR == 2 { print $0 }' | cut -d "=" -f 2)
# shellcheck disable=SC2155
local policy=$(web | awk 'NR == 3 { print $0 }' | cut -d "=" -f 2)
# shellcheck disable=SC2155
local signature=$(web | awk 'NR == 4 { print $0 }' | cut -d "=" -f 2)
curl -v \
-H "Cookie: CloudFront-Policy=$policy" \
-H "Cookie: CloudFront-Signature=$signature" \
-H "Cookie: CloudFront-Key-Pair-Id=$id" \
"https://plan-z.buzzfeed.com$path"
}
if [ "$1" == "clear" ]; then
rm "$file"
fi
if [ "$1" == "init" ]; then
init "$2"
fi
if [ "$1" == "web" ]; then
web
fi
if [ "$1" == "req" ]; then
req "$2"
fi
if [[ "$1" =~ help|-h ]]; then
printf "Usage:\n\t./planz.sh clear\n\t./planz.sh init [cookie_ttl_hours: 2]\n\t./planz.sh web\n\t./planz.sh req /robots.txt\n\t./planz.sh req /robots.txt 1>/dev/null\n"
fi
{
"Statement":[
{
"Resource":"https://your.domain.com/*",
"Condition":{
"DateLessThan":{
"AWS:EpochTime": 1504357200 // some future timestamp
}
}
}
]
}
require "base64"
require "json"
require "openssl"
def cookie_data(resource, expiry)
raw_policy = policy(resource, expiry)
{
"CloudFront-Policy" => safe_base64(raw_policy),
"CloudFront-Signature" => sign(raw_policy),
"CloudFront-Key-Pair-Id" => ENV["CLOUDFRONT_KEY_PAIR_ID"]
}
end
def policy(url, expiry)
{
"Statement"=> [
{
"Resource" => url,
"Condition"=>{
"DateLessThan" =>{"AWS:EpochTime"=> expiry.utc.to_i}
}
}
]
}.to_json.gsub(/\s+/,'')
end
def safe_base64(data)
# equivalent to:
# cat policy.json | tr -d " \t\n\r" | base64 | tr '+=/' '-_~'
# remove all linebreaks/whitespace, base64 encode, strip invalid characters
Base64.strict_encode64(data).tr("+=/", "-_~")
end
def sign(data)
# equivalent to:
# cat policy.json | openssl sha1 -sign ./pk-APKAIT3GGGOSP434T2JQ.pem | base64 | tr '+=/' '-_~'
digest = OpenSSL::Digest::SHA1.new
key = OpenSSL::PKey::RSA.new File.read(ENV["CLOUDFRONT_PRIVATE_KEY"])
result = key.sign digest, data
safe_base64(result)
end
printf "curl -v -o /dev/null "
cookie_data("https://your.domain.com/*", Time.now + (60*60)).each do |k,v|
# printf "Set-Cookie: Domain=domain.com; Path=/; Secure; HttpOnly; %s=%s\n\n", k, v
printf "-H 'Cookie: %s=%s' ", k, v
end
# execute with:
# eval $(ruby signed-cookies.rb) https://your.domain.com/robots.txt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment