Skip to content

Instantly share code, notes, and snippets.

@monking
Last active February 7, 2019 21:13
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 monking/7dff8920eb84bdcf2031d5c7eab23a5f to your computer and use it in GitHub Desktop.
Save monking/7dff8920eb84bdcf2031d5c7eab23a5f to your computer and use it in GitHub Desktop.
AWS scripts: authenticate & edit on S3
#!/bin/bash
# https://aws.amazon.com/premiumsupport/knowledge-center/authenticate-mfa-cli/
storage=credentialsFile
while getopts et: flag; do
case $flag in
t) mfaToken="$OPTARG";;
e) storage=env;;
esac
done
[[ ! -f ~/.aws/credentials ]] && {
1>&2 echo "Please run 'aws configure' first, to establish your default key/secret."
return 2
}
[[ -z $AWS_MFA_SERIAL_NUMBER ]] && read -p "MFA serial number: " && export AWS_MFA_SERIAL_NUMBER="$REPLY"
case $storage in
env)
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN
;;
credentialsFile)
if [[ $REPLY =~ ^[Yy]? ]]; then
if [[ ! -f ~/.aws/credentials.perm ]]; then
cp ~/.aws/credentials ~/.aws/credentials.perm
fi
else
1>&2 echo "Authentication has been cancelled."
return 3
fi
;;
esac
[[ -z $mfaToken ]] && read -p "MFA token: " mfaToken
1>&2 echo "confirming token: $mfaToken"
response="$(aws sts get-session-token --serial-number "$AWS_MFA_SERIAL_NUMBER" --token-code "$mfaToken")"
echo "$response" | json &>/dev/null || {
1>&2 echo -e "Invalid response:\n$response"
return 1
}
ACCESS_KEY_ID="$(echo "$response" | json Credentials.AccessKeyId)"
SECRET_ACCESS_KEY="$(echo "$response" | json Credentials.SecretAccessKey)"
SESSION_TOKEN="$(echo "$response" | json Credentials.SessionToken)"
case $storage in
env)
export AWS_ACCESS_KEY_ID="$ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$SECRET_ACCESS_KEY"
export AWS_SESSION_TOKEN="$SESSION_TOKEN"
;;
credentialsFile)
cat > ~/.aws/credentials <<EOF
$(cat ~/.aws/credentials.perm)
[mfa]
aws_access_key_id = $ACCESS_KEY_ID
aws_secret_access_key = $SECRET_ACCESS_KEY
aws_session_token = $SESSION_TOKEN
EOF
1>&2 echo "Credentials updated."
;;
esac
#!/bin/bash
defaultLocalDir=/tmp/edit-on-s3
showHelp() {
1>&2 echo "
OPTIONS:
-u URL The S3 URL of a file. To enable the use of CloudFront URLs, set the S3_URL_BUCKET_MAP environment variable (see below).
-b BUCKET The S3 bucket name.
-k KEY The S3 file key.
-h Show this help.
-l DIR Directory in which to store copies of the files before/after editing. By default, $defaultLocalDir.
ENVIRONMENT:
S3_URL_BUCKET_MAP
Path to a file with urls with bucket names or hostnames, whitespace, and
alias URLs. The first matching row is used.
This would usually be CloudFront CNAMEs. In this case, grab the contents of
the columns \"Origin\" and \"CNAMEs\" from the CloudFront Distributions
table (https://console.aws.amazon.com/cloudfront/home).
Note: any path in the origin (anything following '/') will be prepended
onto the path from the given URL to result in the S3 file key.
"
}
localDir="$defaultLocalDir"
bucket=
key=
while getopts u:b:k:hl: flag; do
case $flag in
u) url="$OPTARG";;
b) bucket="$OPTARG";;
k) key="$OPTARG";;
h) showHelp; exit 0;;
l) localDir="$OPTARG";;
esac
done
if [[ -n $url ]]; then
urlParts=($(echo -n "$url" | perl -pe 's#https?://([^/]+)/([^/]+)(/(.*))?#\1 \2 \4#'))
hostname="${urlParts[0]}"
firstPathSegment="${urlParts[1]}"
restOfPath="${urlParts[2]}"
if [[ $url =~ .s3.amazonaws.com ]]; then
echo "Getting bucket/key from S3 URL:"
bucket="$firstPathSegment"
key="$restOfPath"
elif [[ -s "$S3_URL_BUCKET_MAP" ]]; then
echo "using S3_URL_BUCKET_MAP: $S3_URL_BUCKET_MAP"
while read matchedS3Url aliases; do
if [[ -n $matchedS3Url ]]; then
matchS3Parts=($(echo -n "$matchedS3Url" | perl -pe 's#^([^.]*).s3.amazonaws.com(/(.*))?#\1 \3#'))
bucket="${matchS3Parts[0]}"
originPath="${matchS3Parts[1]}"
[[ -n $originPath && ! $originPath =~ /$ ]] && originPath+="/"
key="${originPath}${firstPathSegment}"
[[ -n $restOfPath ]] && key+="/${restOfPath}"
break
fi
done <<< $(grep -E "(\\s|,)$hostname(\\s|,|\$)" "$S3_URL_BUCKET_MAP")
else
echo "URL is not S3. If you know which S3 bucket it belongs to, populate a file per S3_URL_BUCKET_MAP (see below)."
echo
showHelp
exit 2
fi
fi
if [[ -z $bucket || -z $key ]]; then
echo "Couldn't determine bucket or key."
showHelp
exit 1
else
echo "bucket: $bucket"
echo "key: $key"
fi
time="$(date '+%Y-%m-%d.%H-%M-%S%z')"
localBucketDir="$localDir/$bucket"
mkdir -p "$localBucketDir"
basifiedKey="${key//\//+}"
localPath="$localBucketDir/edit-on-s3.${time}.$basifiedKey"
editableLocalPath="$localBucketDir/edit-on-s3.${time}.edit.$basifiedKey"
[[ -z $EDITOR ]] && EDITOR=vim
s3URI="s3://${bucket}/${key}"
aws --profile=mfa s3 cp "${s3URI}" "${localPath}" &&
cp "${localPath}" "${editableLocalPath}" &&
$EDITOR "${editableLocalPath}"
[[ -s "${editableLocalPath}" ]] &&
[[ -n "$(diff "${localPath}" "${editableLocalPath}")" ]] &&
echo "(DEBUG)" aws --profile=mfa s3 cp "${editableLocalPath}" "${s3URI}" &&
aws --profile=mfa s3 cp "${editableLocalPath}" "${s3URI}" &&
echo "Success!" ||
echo "Either there were no changes to the file, or something went wrong... (apologies for the vague error)"
@monking
Copy link
Author

monking commented Feb 7, 2019

Tested on Mac, with AWS CLI (1.16.90, brew install awscli), and Bash 3.2.57

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment