Last active
October 9, 2019 04:47
-
-
Save RichardBronosky/4cdd0b462f6fc6a8700d1d6b7650e363 to your computer and use it in GitHub Desktop.
A wrapper around https://github.com/remind101/assume-role that feeds in the MFA and caches.
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
:<<'DOCS' | |
* This script is a wrapper around https://github.com/remind101/assume-role that feeds | |
in the MFA and caches the token. | |
* Either: Place this file at ~/.aws/assume-role use it in ~/.bash_profile with: | |
[[ -f ~/.aws/assume-role ]] && source ~/.aws/assume-role | |
* Or: You can copy-paste the next 5 lines to get and use this script: | |
curl -sLo ~/.aws/assume-role https://gist.githubusercontent.com/RichardBronosky/4cdd0b462f6fc6a8700d1d6b7650e363/raw/assume-role | |
cat >> ~/.bash_profile <<'EOF' | |
[[ -f ~/.aws/assume-role ]] && source ~/.aws/assume-role | |
EOF | |
* Requires TOTP-Generator python package https://pypi.org/project/TOTP-Generator/ | |
* This offers adequate security because it uses https://pypi.org/project/keyring/#what-is-python-keyring-lib | |
* To install TOTP-Generator: | |
[[ -x $(which pip3) ]] || brew install python # get Python3/pip only if you don't have it | |
pip3 install totp-generator | |
totp_generator -a | |
* The functions below assume the name of the service to be: aws | |
* The TOTP secret is your MFA secret that is usually only shown as a QR Code | |
* You may have to remove your existing MFA and generate another as follows: | |
IAM > Users > username > Security credentials (tab) > Assigned MFA device | |
\- Manage > Remove | |
\- Manage > Virtual MFA device > Show secret key | |
DOCS | |
# A wrapper around assume-role that passes in MFA and caches env vars to /tmp/aws-role-*.sh | |
# If the 2nd arg is a `-` the cached env vars are used. | |
# If no arguments are passed, the profiles are listed. | |
ar(){ | |
local service=aws | |
if [[ ${#} < 1 ]]; then | |
cat <<'EOF' | |
Usage: ar <profile> [-] [env] | |
Passing the "-" end causes this script to use your cached token rather than requesting a new one. | |
It's faster, but more importantly allows you to use for-loops without getting errors due to using | |
"one time passwords" more than once, as a consequence of the speed. | |
Passing literal "env" (with or without "-") causes output to be given in envFile format that is | |
appropriate for VSCode launch.json and `npm i dotenv`. This is done without sourcing the temp | |
file. | |
EOF | |
# Show all roles/profiles in ~/.aws/config | |
awk -F '[:/ ]' '/^ *;/{next} /^.profile/{gsub("]",""); printf("\nprofile: %s\n", $2)} /role_arn/{printf(" account: %s\n role: %s\n", $5, $7)}' ~/.aws/config | |
local brk=1 | |
if [[ -n ${ASSUMED_ROLE:-} ]]; then | |
[[ brk -eq 0 ]] || echo | |
echo "Current role: ${ASSUMED_ROLE}" | |
brk=0 | |
fi | |
local account="$(aws sts get-caller-identity --query Account --output text 2>/dev/null)" | |
[[ brk -eq 0 ]] || echo | |
brk=0 | |
if [[ -n "${account}" ]]; then | |
echo "Current account: ${account}" | |
else | |
echo "error: Credentials have expired." | |
fi | |
return 1 | |
fi | |
local role=${1} | |
local temp=/tmp/aws-role-${role} | |
# Skip updating the temp file if `-` is passed as arg 2 | |
if [[ ${2:-} == - ]]; then | |
shift | |
else | |
totp_generator -s ${service} | \ | |
assume-role -duration 12h ${role} \ | |
1>${temp}.1 \ | |
2>${temp}.2 | |
local status=${?} | |
if ( exit ${status} ); then | |
mv ${temp}.1 ${temp}.sh | |
rm -f ${temp}.2 | |
else | |
cat ${temp}.2 | sed 's/MFA code: //' | |
[[ ${DEBUG:-0} -eq 0 ]] && rm -f ${temp}.[12] | |
echo "ar failed" | |
return 128 | |
fi | |
fi | |
# If `env` is passed as arg 2 (or 3 when arg 2 is -) output var definitions in env file format `KEY=value` | |
if [[ ${2:-} == env ]]; then | |
sed -E '/^[[:space:]]*export/!d; s/[[:space:]]*export[[:space:]]*//; s/"//g' < ${temp}.sh | |
else | |
source ${temp}.sh | |
export ASSUMED_ACCOUNT="$(aws sts get-caller-identity --query Account --output text)" | |
fi | |
} | |
# copies MFA to clipboard and outputs it | |
# optionally takes an argument to override the default service of `aws` | |
mfa(){ | |
local service=${1:-aws} | |
local secs=$(date +%-S) | |
if [[ -n ${NOCOPY:-} ]]; then | |
copy(){ cat; } | |
else | |
copy(){ pbcopy; pbpaste; } | |
fi | |
if [[ -n ${NOERR:-} ]]; then | |
err(){ cat; } | |
else | |
err(){ cat >/dev/stderr; } | |
fi | |
((secs=30-$secs)); [[ $secs -eq 0 ]] && ((secs=30)); [[ $secs -lt 0 ]] && ((secs=30+$secs)) | |
totp_generator -s $service | copy | |
echo "Expires in: $secs" | err | |
} | |
unaws(){ | |
unset ASSUMED_ROLE ASSUMED_ACCOUNT AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECURITY_TOKEN AWS_SESSION_TOKEN | |
} | |
export -f ar mfa unaws | |
# vim: ft=sh et sw=2 ts=2 sts=2 |
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
# This creates a macOS application binary (named MFA) that can be triggered via Spotlight. | |
# Here are 2 options for how to create the binary: | |
# | |
# 1. | |
# At the Terminal, run: | |
# osacompile -o /Applications/MFA.app mfa_copied.applescript | |
# | |
# 2. | |
# Open with Script Editor and Export as Application with the name MFA in the /Applications folder | |
# Yes, this is a convoluted way to display a notification, but osacompiled apps can't display notifications | |
do shell script " | |
msg=\"$(NOERR=1 bash -l -c mfa)\" | |
osascript -e 'display notification \"'\"$msg\"'\" with title \"MFA\" subtitle \"has been sent to your clipboard\" sound name \"Glass\"' | |
" |
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
# This creates a macOS application binary (named MFA) that can be triggered via Spotlight. | |
# Here are 2 options for how to create the binary: | |
# | |
# 1. | |
# At the Terminal, run: | |
# osacompile -o /Applications/MFA.app mfa_typed.applescript | |
# | |
# 2. | |
# Open with Script Editor and Export as Application with the name MFA in the /Applications folder | |
# Yes, this is a convoluted way to display a notification, but osacompiled apps can't display notifications | |
do shell script " | |
bash -l -c 'sleep 1; type_totp.py; sleep 15' | |
" |
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 python3 | |
from pynput.keyboard import Controller | |
from totp_generator.core_utils import KeyringTotpGenerator | |
keyboard = Controller() | |
keyring_generator = KeyringTotpGenerator() | |
keyboard.type(keyring_generator.get_totp_code('aws')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Currently uses a duration of
12h
for everything. I'm tempted to detect bad durations withgrep 'durationSeconds.*failed'
and extract the maximum duration withawk '{print $NF}'
and cache it to a new file. Then I'd use those values if present.