Store AWS CLI and MFA Credentials In The Mac OS Keychain App
I lock my AWS accounts down with MFA. Using the command line tools and SDKs require generating new credentials every 36 hours. To get them, I run the following command:
mfa 012345
The command itself is a function in my private .zshrc file. It looks like this:
######################################################################
# AWS MFA Updater
function mfa () {
if [ "$1" ]
then
if [ "$2" ]
then
echo "You passed too many arguments"
else
export AWS_TOKEN=[CURRENT_TOKEN] && security add-generic-password -a [LOCAL_USERNAME] -s [NAME_FOR_MFA_STORAGE] -U -w $(aws sts --profile [AWS_CREDENTIALS_PROFILE] get-session-token --duration-seconds 129600 --serial-number [MFA_SERIAL_NUMBER] --token-code $AWS_TOKEN | jq -c '. | {Version: 1,AccessKeyId: .Credentials.AccessKeyId, SecretAccessKey: .Credentials.SecretAccessKey, SessionToken: .Credentials.SessionToken }')
fi
else
echo "You need to pass an argument"
fi
}
export AWS_TOKEN=[CURRENT_TOKEN] && security add-generic-password -a [LOCAL_USERNAME] -s [NAME_FOR_MFA_STORAGE] -U -w $(aws sts --profile [AWS_CREDENTIALS_PROFILE] get-session-token --duration-seconds 129600 --serial-number [MFA_SERIAL_NUMBER] --token-code $AWS_TOKEN | jq -c '. | {Version: 1,AccessKeyId: .Credentials.AccessKeyId, SecretAccessKey: .Credentials.SecretAccessKey, SessionToken: .Credentials.SessionToken }')
The only value I change each time is CURRENT_TOKEN
with the current six digit token from my MFA device.
To use the code
The values I change out are:
CURRENT_TOKEN
with the current six digit tokenLOCAL_USERNAME
my machine username (e.g. alan)NAME_FOR_MFA_STORAGE
a key name to use to store the credentials underAWS_CREDENTIALS_PROFILE
MFA_SERIAL_NUMBER
you'll get this from your IAM user page where you setup the MFA device. Looks something like: "arn:aws:iam::0123456789:mfa/AccountName"
One Time Initial Setup
Add Profiles To AWS Credentials
Add these to your ~/.aws/credentials
file
[default]
credential_process = security find-generic-password -w -a MAC_USERNAME -s AWS-ACCOUNT-MFA
[AWS-ACCOUNT]
credential_process = security find-generic-password -w -a MAC_USERNAME -s AWS-ACCOUNT-NON-MFA
Store Non-MFA Credentails
Make a json file called credentails.json
with the format with your non-mfa credentails
{
"Version": 1,
"AccessKeyId": "YOUR NON-MFA ACCESS KEY",
"SecretAccessKey": "YOUR NON-MFA SECRET KEY"
}
Push those credentials to Keychain Access with:
security add-generic-password -a MAC_USERNAME -s AWS-ACCOUNT-NON-MFA -U -w "$(jq -c . credentials.json)"
Generating Tokens
Every time you need to update the tokens, use this with your current AWS_TOKEN
number:
That updates the credentials that are setup for your default aws profile in the credentials file. Test it with:
aws s3 ls
Notes:
- You can totally put this in a command line function in your bash/zsh profile. (I just haven't done that yet)
- I use the
[default]
profile for the mfa credentials since that's what I use for everything except updating the mfa token. You can, of course, use whatever profile you'd like. - The reason to put the initial credentials inside a json file instead of entering them directly on the command line is to prevent them from showing up in your command line history
- The
AWS-ACCOUNT-MFA
andAWS-ACCOUNT-NON-MFA
are key names you can change to whatever you want. - You'll need to update
arn:aws:iam::123456789:mfa/AWS-ACCOUNT
with your account MFA token ID (which is found on your IAM page for setting up MFA devices) - The
AWS-ACCOUNT
in the profile and the command to get the token can be changed as long as you do it in both places.
Draft stuff
This assumes you have an account setup that lets you use the default access/secret credentials along with an MFA token to pull a set of temporary mfa credentials.
You'll setup two sets of credentials in they Keychain Access app. The first is for the main crednetials that you'll use to get the MFA. The second is the MFA credentials that will be refreshed by the command
Setup a basic account and store the credentials like this. This is for the account that can use generate MFA credentails for itself. TKTKTK Get the permission needed to allow for this.
TKTKTKTK. Show how to do this without putting the text on the command line so it's not in the command line history.
security add-generic-password -a USERNAME -s KEYNAME -U -w '{ "Version": 1, "AccessKeyId": "your AWS secret access key", "SecretAccessKey": "your AWS secret access key" }'
Then update your ~/.aws/credentails
file with:
[default]
credential_process = security find-generic-password -w -a USERNAME -s KEYNAME
You need an account setup with basic access keys that can get the mfa keys.
Get your MFA credentials with:
TKTKTK
Store your temporary credentials in Keychain Access with
security add-generic-password -a USERNAME -s KEYNAME -U -w '{ "Version": 1, "AccessKeyId": "an AWS access key", "SecretAccessKey": "your AWS secret access key", "SessionToken": "the AWS session token for temporary credentials" }'
Then, add this to your ~/.aws/credentials
file:
[mfa_access]
credential_process = security find-generic-password -w -a USERNAME -s KEYNAME
NOTE: you can't use -w
without the password on the command line to prompt for it because the prompt apparently doesn't allow you to input a long enough line to accommodate the JSON.
So, in order to do this from the command line, you'll need to input the data from the command itself. That ends up putting the credentials in your command line history which isn't great. Should work on getting another process to set it.
Tried this, but it didn't work, there's probably a way to do it though where you read from a file instead of putting the credentials on the command line
security add-generic-password -a alans -s KEYNAME -U -w '`cat ~/Desktop/_work.json`'
TODO: Named profile
[mfa] aws_access_key_id = example-access-key-as-in-returned-output aws_secret_access_key = example-secret-access-key-as-in-returned-output aws_session_token = example-session-Token-as-in-returned-output