Last active
May 17, 2022 12:32
-
-
Save kennwhite/223615b1b34b4f6c7d59 to your computer and use it in GitHub Desktop.
Minimalist, bash-only utility script to push a file to S3 bucket. AWS ID & Key can be passed via environment or on command line. Only dependency is openssl tools (usually default). Name is an homage to Joe Stump.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# Upload a file to the Amazon S3 service | |
# Usage: | |
# neckbeard-push FILE S3_BUCKET [-a ACL_POLICY] [-i AWS_ACCESS_ID] [-k AWS_SECRET_KEY] [-d debug] [-l write verbose session log] | |
# Note: If option -l is requested, curl_session.log contains SSL handshake *and* plaintext AWS keys | |
# | |
# Ex 1: neckbeard-push foo.log my-bucket -a public-read (with env vars: $AWS_ACCESS_ID & $AWS_SECRET_KEY) | |
# Ex 2: neckbeard-push foo.log my-bucket -a private -i AKIXXXXX -k aBcDeFgHxxx -d | |
# | |
# If credentials not supplied, depends on being set via env (eg: export AWS_ACCESS_ID="AKIXXXXXXX"): | |
# $AWS_ACCESS_ID | |
# $AWS_SECRET_KEY | |
# | |
# Output: URL of the newly uploaded file on success, HTTP error code (typically 403) on failure | |
# Returns: 0 on success 1 on failure | |
# Exit on error | |
set -e | |
# See for additional endpoints: http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region | |
s3_endpoint=s3-external-1.amazonaws.com # For geo-aware: s3.amazonaws.com | |
script="${0##*/}" | |
# Expects: authorize $string_to_sign $secret_key $access_id | |
authorize() { | |
local signature=$( printf "$1" | hmac_sha1 "$2" | base64 ) | |
printf "AWS $3:$signature" | |
} | |
# Expects: hmac_sha1 $hmac_key, with string piped | |
hmac_sha1() { | |
openssl dgst -binary -sha1 -hmac "$1" | |
} | |
base64() { | |
openssl enc -base64 | |
} | |
bin_md5() { | |
openssl dgst -binary -md5 | |
} | |
# Parse parameters | |
[ $# -eq 0 ] && printf "ERROR: No arguments passed. Use: $script -h for help. \n" && exit 1 | |
file="$1" | |
bucket="$2" | |
usage="USAGE: $script FILE S3_BUCKET \ | |
[-a ACL_POLICY <private>] [-i AWS_ACCESS_ID] [-k AWS_SECRET_KEY] [-d debug] [-l write verbose session log] \n\ | |
Ex: $script kitty.jpg mybucket -a public-read -d \n" | |
options=$@; args=($options) | |
index=0; for arg in $options ; do (( index++ )) | |
case $arg in | |
-h) printf "$usage" && exit 1 ;; | |
-d) debug=1 ;; | |
-l) trace="--trace curl_session.log" && printf "NOTICE: *Plain text* session log written: curl_session.log \n" ;; | |
-a) acl="${args[index]}" ;; | |
-i) access_id="${args[index]}" ;; | |
-k) secret_key="${args[index]}" ;; | |
-?) printf "WARNING: Unknown parameter '$arg' ${args[index]} \n" ;; | |
esac | |
done | |
# If not provided (or blank), default to constants or env variables | |
acl=${acl:-"private"} | |
trace=${trace:-""} | |
access_id=${access_id:-$AWS_ACCESS_ID} | |
secret_key=${secret_key:-$AWS_SECRET_KEY} | |
object_name="${file##*/}" | |
content_md5="$( bin_md5 < "$file" | base64 )" | |
content_type='binary/octet-stream' | |
# Date/time format in POSIX (C) locale and style | |
utc_date="$( LC_TIME=C && date '+%a, %d %h %Y %T %z' )" | |
url="https://$bucket.$s3_endpoint/$object_name" | |
string_to_sign="PUT\n$content_md5\n$content_type\n$utc_date\nx-amz-acl:$acl\n/$bucket/$object_name" | |
authorization=$( authorize "$string_to_sign" "$secret_key" "$access_id" ) | |
[ $debug ] && printf \ | |
'DEBUG:\n File\t%s\n Bucket\t%s\n Id\t%s\n Key\t%s\n ACL\t%s\n Date\t%s\n Req\t%s\n Auth\t%s\n URL\t%s\n\n' \ | |
"$file" "$bucket" "$access_id" "$secret_key" "$acl" "$utc_date" "$string_to_sign" "$authorization" "$url" | |
# Ignore .curlrc, silent, show errors only on fail, no progress bar, upload $file with header auth | |
curl -qsSf -T "$file" $trace \ | |
-H "Authorization: $authorization" \ | |
-H "x-amz-acl: $acl" \ | |
-H "Date: $utc_date" \ | |
-H "Content-MD5: $content_md5" \ | |
-H "Content-Type: $content_type" \ | |
"$url" && printf "$url \n" && exit 0 || \ | |
printf "Error: Failed to PUT: $file on requested URL: $url (use -d to debug)\n" && exit 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment