Eén van de eerste dingen waar AWS op hamert bij het aanmaken van een account is het activeren van Multi Factor Authentication. Middels een policy is het ook af te dwingen bij IAM users. En da’s fijn voor Console toegang. Edoch… CLI access is met MFA niet altijd even makkelijk. Tenzij…
Tenzij een tijdelijke sessie wordt opgezet middels aws sts get-session-token --serial-number arn-of-the-mfa-device --token-code code-from-token
zoals hier uitgelegd wordt. De verkregen output kan dan weer als variable gezet worden in je shell zodat daarna naar hartewens aws
commando’s zijn af te vuren voor ongeveer 12 uur.
Maar dat kan natuurlijk makkelijker. Ik maakte al gebruik van een handige profile switcher, gepost door Carl Nordenfelt de deze blog.jayway.com. Naast de al bestaande aliassen zoals Carl beschreven heeft, heb ik twee aliassen toegevoegd aan ~/.bash_profile:
alias awsmfa='_awsMFA'
alias mfatl='_mfaTimeLeft'
MFA Checken / zetten
Met de eerste is te controleren of voor een profiel al een MFA sessie is opgezet. De syntax is eenvoudig:
awsmfa <profielnaam>
De functie die hiermee aangeroepen wordt controleert eerst of het desbetreffende IAM account MFA heeft geconfigureerd. Da’s mamelijk best handig om door te kunnen gaan. Vervolgens wordt gecontroleerd of er al een sessie actief is door te kijken wat de resterende sessietijd is. Mocht deze tijd groter zijn dan 0 seconden, wordt het bestaande mfa_profiel geladen middels functie _awsSwitchProfile. Indien de sessietijd verstreken of afwezig is, zal om een MFA token gevraagd worden en zal een nieuwe sessie worden opgezet. De verkregen variabelen worden in een mfa_profiel gestopt, waarna dit profiel geladen zal worden.
Resterende tijd
Een sessie heeft een levensduur tussen de 15 minuten en 36 uur, met 12 uur als default. In onderstaand script hanteer ik de default, maar mocht je deze liever aangepast willen hebben, voeg dan de optie --duration-seconds <seconden>
toe met je voorkeurstijd in seconden aan het aws sts get-session-token
commando in de variable sts_info. Eenmaal een sessie opgezet is de resteren tijd op te vragen met het volgende:
mfatl
Prompt
Om het helemaal mooi te maken kunnen een aantal variabelen in de prompt verwerkt worden:
PS1='\h:\W \u\[\e[1;34m\].${AWS_PROFILE}\[\e[1;33m\].${AWS_REGION}\[\e[1;32m\].$(mfatl)\[\e[00m\]\$ '
Het script
Hieronder het oorspronkelijke sessie-switch script van Carl met her en der wat aanpassingen en uitgebreidingen van mijzelf. Have fun!
$ cat ~/._awsAliases
#!/bin/bash
function _awsListAll() {
credentialFileLocation=${AWS_SHARED_CREDENTIALS_FILE};
if [ -z $credentialFileLocation ]; then
credentialFileLocation=~/.aws/credentials
fi
while read line; do
if [[ $line == "["* ]]; then echo "$line"; fi;
done < $credentialFileLocation;
mfaFileLocation=~/.aws/mfa
};
function _awsSwitchProfile() {
if [ -z $1 ]; then echo "Usage: awsp profilename"; return; fi
exists="$(aws configure get aws_access_key_id --profile $1)"
if [[ -n $exists ]]; then
export AWS_DEFAULT_PROFILE=$1;
export AWS_PROFILE=$1;
export AWS_REGION=$(aws configure get region --profile $1);
## Export STS_EXP to speed up _mfaTimeLeft, even when empty.
export STS_EXP=$(aws configure get aws_session_token_exiration --profile $1)
echo "..Switched to AWS Profile: $1";
#aws configure list
fi
};
function _mfaTimeLeft() {
if [ ! -z $1 ]; then
STS_EXP=$1
fi
if [[ -n $STS_EXP ]];then
current_date=$(date -u +%s)
expiration_date=$(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" ${STS_EXP} +%s)
time_left="$(((expiration_date-current_date)/60))"
#time_left="$(((expiration_date-current_date)))"
else
time_left=""
fi
echo "$time_left"
};
function _awsMFA() {
if [ -z $1 ]; then echo "..Usage: awsmmfa profilename"; return; fi
## Strip MFA from $1, as only normal profile names are expected.
if [[ $1 == *"mfa_"* ]];then
profile=$(echo $1| awk -F "mfa_" '{print $2}')
else
profile=$1
fi
## check existence of requested profile
exists="$(aws configure get aws_access_key_id --profile ${profile})"
if [[ -n $exists ]]; then
## get MFA ARN from AWS
mfa_info=$(aws iam list-mfa-devices --profile ${profile})
## verify account has mfa setup:
if [[ -n $mfa_info ]]; then
## Create new mfa profile for profilename
mfa_user=$(echo "$mfa_info"|awk -F '["]' '/UserName/{print $4}')
mfa_arn=$(echo "$mfa_info"|awk -F '["]' '/SerialNumber/{print $4}')
mfa_profile=$(echo "mfa_${profile}")
## get expiration date from configfile
sts_expire=$(aws configure get aws_session_token_exiration --profile $mfa_profile)
## calculate time_left (see top of file)
time_left=$(_mfaTimeLeft $sts_expire )
if [[ $time_left -gt "0" ]];then
## if > 0 switch profile to mfa_profile
echo "..Existing token is present and still valid"
else
## create / update aws config mfa_profile
## read MFA token
echo "..No valid token found"
echo "..Please enter MFA token for user ${mfa_user}:"
read mfa_token
## use token to get STS token. Note duration ranges from 900 to 129600 seconds, defaults to 43200 (12hours)
#sts_info=$(aws sts get-session-token --serial-number ${mfa_arn} --token-code ${mfa_token} --duration-seconds 900 --profile ${profile})
sts_info=$(aws sts get-session-token --serial-number ${mfa_arn} --token-code ${mfa_token} --profile ${profile})
## validate success
if [[ -n $sts_info ]]; then
aws configure set mfa_user ${mfa_user} --profile $mfa_profile
aws configure set region $(aws configure get region --profile ${profile}) --profile $mfa_profile
aws configure set aws_access_key_id $(echo "$sts_info" | awk -F '["]' '/AccessKeyId/{print $4}') --profile $mfa_profile
aws configure set aws_secret_access_key $(echo "$sts_info" | awk -F '["]' '/SecretAccessKey/{print $4}') --profile $mfa_profile
aws configure set aws_session_token $(echo "$sts_info" | awk -F '["]' '/SessionToken/{print $4}') --profile $mfa_profile
aws configure set aws_session_token_exiration $(echo "$sts_info" | awk -F '["]' '/Expiration/{print $4}') --profile $mfa_profile
fi
fi
## Time to set MFA profile:
_awsSwitchProfile $mfa_profile
else
echo "..No MFA setup for ${profile}!"
return
fi
else
echo "..Config ${profile} does not exist!"
fi
}