21 January 2020
My work involves elevated access to computers, including Amazon Web Services (AWS) accounts.
Our security team requires multi-factor authentication (MFA) for elevated access. For command-line access using MFA, I use the awscli’s aws sts get-session-token
function. This grants AWS security credentials that are valid for a few hours.
I do this multiple times each day, so I made a quick utility script: sessioner
.
To set up my credentials, I run the following commands:
. sessioner.sh -e development -t <development_token_value>
. sessioner.sh -e testing -t <testing_token_value>
. sessioner.sh -e production -t <production_token_value>
The token values come from an MFA device.
This code has 5 parts. Let’s take a look…
The first step is to parse the inputs.
The script needs 2 parameters: the AWS profile (-e
or --env
) and MFA token code (-t
or --token
).
# inputs needed - environment (ENV) and code (TOKEN)
echo $@
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-e|--env)
ENV="$2"
shift # past argument
shift # past value
;;
-t|--token)
TOKEN="$2"
shift # past argument
shift # past value
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
The second step is to create a few variables; the MFA device serial number, and the AWS profilename with elevated permissions.
Let’s say I’m connecting to AWS accounts 111111111111
and 222222222222
for development and testing. Inside each is an IAM user with elevated access called DevTheAlmighty
.
if [ "${ENV}" = "development" ]; then
SERIAL='arn:aws:iam::111111111111:mfa/DevTheAlmighty'
fi
if [ "${ENV}" = "testing" ]; then
SERIAL='arn:aws:iam::222222222222:mfa/DevTheAlmighty'
fi
PROFILENAME="$ENV"mfa
Inside my AWS credentials, I have 2 configurations for each AWS account. I use the development
profile to get credentials for the developmentmfa
profile. The former has limited permissions; it can only retrieve permissions for the latter.
[development]
region = us-east-1
[developmentmfa]
region = us-east-1
I get temporary credentials via aws sts get-session-token, which returns a JSON object. I run the command and save the results to a variable.
echo "Configuring $ENV with token $TOKEN"
CREDJSON="$(aws sts get-session-token --serial-number $SERIAL --profile $ENV --token-code $TOKEN)"
#echo $CREDJSON
Jq navigates through the JSON on the command line, and then sed removes the "
character.
One line of code assigns an access_key
, secret_key
, or session_token
value to a variable.
ACCESSKEY="$(echo $CREDJSON | jq '.Credentials.AccessKeyId' | sed 's/"//g')"
SECRETKEY="$(echo $CREDJSON | jq '.Credentials.SecretAccessKey' | sed 's/"//g')"
SESSIONTOKEN="$(echo $CREDJSON | jq '.Credentials.SessionToken' | sed 's/"//g')"
aws configure set sets credentials for the higher-permissions profile.
aws configure set aws_access_key_id $ACCESSKEY --profile $PROFILENAME
aws configure set aws_secret_access_key $SECRETKEY --profile $PROFILENAME
aws configure set aws_session_token $SESSIONTOKEN --profile $PROFILENAME
Has my script worked? I run a simple check: listing all the S3 buckets I can see. Their names are familiar and distinctive, so I immediately know which AWS account I’m using.
aws s3 ls / --profile $PROFILENAME
I’ve put my code on GitHub, since no piece of code is ever done. I’ll add functionality over time, as I need to.
Happy coding!