Update: Good news Windows users! You can now use this AWSume script on Windows too.
Here at Trek10, we work with many clients, and thus work with multiple AWS accounts on a regular (daily) basis. We needed a way to make managing all our different accounts easier. We create a standard Trek10 administrator role in our clients’ accounts that we can assume. For security we require that the role assumer have multifactor authentication enabled.
This works fine when accessing these accounts via the AWS console, but quickly becomes cumbersome when using the AWS CLI or SDKs.
The AWS CLI has support for automatically assuming a role based on a profiles you can setup in your
~/.aws/config file. Once you setup the profiles, you can run a command using the profile. Something like this
aws s3 ls --profile profile-for-that-one-account. The CLI will prompt you for your mfa token and assume the role for you. It also caches the credentials for you so you don’t have to keep entering your mfa token if you run multiple commands. This works well except for two things, the SDKs don’t look in the CLI credential cache, and you have to specify the profile everytime you run a command (or set the AWSDEFAULTPROFILE environment variable).
Another issue I have is that often I do development work inside a virtual machine, and the aws config files aren’t available. I could of course volume in my
.aws directory, but it’s a pain to do that for every new VM I setup.
The Solution - AWSume
I wrote a script to leverage the fact that the CLI will assume a role and cache the credentials for you. The script reads the credentials from the CLI cache and writes them into environment variables. This way the CLI will default to using them without specifying the profile and the SDKs will also pickup the creds from the environment variables. It also has an option to print the export statements to easily copy them into a VM or SSH session.
# ~/.aws/config [profile internal-admin] role_arn = arn:aws:iam::<my aws account id>/role/admin-role mfa_serial = arn:aws:iam::<my aws account id>:mfa/joel source_profile = joel [profile client1-admin] role_arn = arn:aws:iam::<client #1 account id>/role/admin-role mfa_serial = arn:aws:iam::<your aws account id>:mfa/joel source_profile = joel [profile client2-admin] role_arn = arn:aws:iam::<client #2 account id>/role/admin-role mfa_serial = arn:aws:iam::<your aws account id>:mfa/joel source_profile = joel
# ~/.aws/credential [default] aws_access_key_id = AKIAIOIEUFSN9EXAMPLE aws_secret_access_key = wJalrXIneUATF/K7MDENG/jeuFHEnfEXAMPLEKEY [joel] aws_access_key_id = AKIAIOSFODNN7EXAMPLE aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Notice that the
source_profile in the
config matches the profile in the
credentials. To protect against accidents I’ve set my default profile to access keys for our sandbox account.
#!/bin/bash if [[ -z $1 ]]; then echo Missing profile name echo echo Usage: . assume profile-name [show] echo else aws s3 ls --profile $1 > /dev/null if [[ $? -eq 0 ]]; then cachedCreds=`ls ~/.aws/cli/cache/$1*` token=$(python -c 'import json,sys,fileinput; obj=json.loads(fileinput.input().readline()); creds = obj["Credentials"] print creds["SessionToken"] + "" ' $cachedCreds) id=$(python -c 'import json,sys,fileinput; obj=json.loads(fileinput.input().readline()); creds = obj["Credentials"] print creds["AccessKeyId"] + "" ' $cachedCreds) key=$(python -c 'import json,sys,fileinput; obj=json.loads(fileinput.input().readline()); creds = obj["Credentials"] print creds["SecretAccessKey"] + "" ' $cachedCreds) if [[ "$2" == "show" ]]; then echo "export AWS_SESSION_TOKEN=$token" echo "export AWS_SECRET_ACCESS_KEY=$key" echo "export AWS_ACCESS_KEY_ID=$id" fi export AWS_SESSION_TOKEN=$token export AWS_SECRET_ACCESS_KEY=$key export AWS_ACCESS_KEY_ID=$id fi fi
aws s3 lswith the profile you specify as a parameter
- If there is no error use an inline python script to parse the cached credential json file
- Export the appropriate variables
- If the show option is provided, print the export statements
This script is known to run in bash and zsh on OSX. YMMV on other operating systems and shells.
Remember, you will need to source the script to get the environment variables to stick. To do this in a typical shell, you need to prepend a
. to your command. For convenience I named the script
awsume, put the it in
/usr/local/bin and set an alias
alias awsume='. awsume'.