Reputation: 18790
How do I type in the MFA code when using the AWS CLI? I have checked the documentation page of IAM http://docs.aws.amazon.com/cli/latest/reference/iam/index.html.
I have the MFA-Devices already enabled under my username.
aws iam list-mfa-devices --user-name X
returns
{
"MFADevices": [
{
"UserName": "X",
"SerialNumber": "arn:aws:iam::+++:mfa/X",
"EnableDate": "2016-01-13T23:15:43Z"
}
]
}
Upvotes: 80
Views: 98782
Reputation: 2776
A Bourne-like shell function (only tested on bash) that will set up STS for you:
aws_clear_vars ()
{
unset AWS_SESSION_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_EXPIRY AWS_EC2_METADATA_DISABLED aws_response
}
aws_2fa ()
{
aws_clear_vars;
export AWS_EC2_METADATA_DISABLED=true;
mfacode="$1";
if [ -z "$mfacode" ]; then
echo "Error: Please pass MFA code as parameter" 1>&2;
return 1;
fi;
profile=${AWS_PROFILE:-default};
role=$(aws configure get role_arn);
mfa_serial=$(aws configure get mfa_serial);
duration_seconds=$(aws configure get duration_seconds);
if [ -n "$duration_seconds" ]; then
extra_params=(--duration-seconds $duration_seconds);
fi;
if [ -n "$mfa_serial" ]; then
if [ -n "$role" ]; then
aws_response=$(env -u AWS_PROFILE aws sts assume-role --role-arn "$role" "${extra_params[@]}" --role-session-name aws-cli --serial-number "$mfa_serial" --token-code "$mfacode");
else
aws_response="$(aws sts get-session-token "${extra_params[@]}" --token-code "$mfacode" --serial-number "$mfa_serial")";
fi;
if [ $? -eq 0 ]; then
export AWS_ACCESS_KEY_ID="$(echo "$aws_response" | jq .Credentials.AccessKeyId -r)";
export AWS_SECRET_ACCESS_KEY="$(echo "$aws_response" | jq .Credentials.SecretAccessKey -r)";
export AWS_SESSION_TOKEN="$(echo "$aws_response" | jq .Credentials.SessionToken -r)";
export AWS_SESSION_EXPIRY="$(echo "$aws_response" | jq .Credentials.Expiration -r)";
echo "Got a session. Valid until $AWS_SESSION_EXPIRY";
else
echo "Error getting session!" 1>&2;
echo "$aws_response" 1>&2;
return 2;
fi;
else
echo "Error: Please ensure that mfa_serial is present in your ~/.aws/config for the relevant profile" 1>&2;
return 1;
fi
}
aws_clear_vars
clears the environment variables.
To use run aws_2fa 987655
(where "987655" is a MFA code - it will then get a session in the default profile / the one specified in AWS_PROFILE
and set the environment variables that the most AWS SDK-based tools use. (including the AWS CLI)
It will try to follow the session length from duration_seconds
in the ~/.aws/config.
It is necessary to ensure the presence of mfa_serial entries on the profile being used (including default
)
How it works:
aws configure
mfa_serial
setting in the configget-session-token
if there is no role specified or a assume-role
if a role is specified to get a token, etc out of STSUsage examples:
# Basic, default profile
aws_2fa 434235
aws ec2 describe_instances
For other profiles (mostly not needed, since the CLI will prompt for a code, but can be useful for python stuff that does not support the credential cache)
AWS_PROFILE=otheraccount aws_2fa 426536
aws ec2 describe_instances # This will now be against that profile, since env vars are set
ansible-playbook -i inventories/ansible-managed-region_aws_ec2.yml test.yml # will not prompt for MFA and operate on that profile
aws_clear_vars
aws ec2 describe_instances # Back to as if aws_2fa was not run
Upvotes: 0
Reputation: 5338
Step-by-step manual solution:
aws sts get-session-token --serial-number arn-of-the-mfa-device --token-code code-from-token
arn-of-the-mfa-device
: visible from your user IAM
aws iam list-mfa-devices --user-name ryan
code-from-token
: 6 digit code from your configured MFA device
aws configure --profile cli
aws configure set --profile cli aws_session_token <SESSION_TOKEN_HERE>
aws_session_token
is not included in aws configure
aws s3 ls --profile cli
Upvotes: 21
Reputation: 31980
Here's a PowerShell module that lets you set up AWS profiles that authenticate using MFA. It will manage the MFA session token, which will last up to 36 hours without needing to re-enter MFA credentials:
https://github.com/CurtisLusmore/AwsCredentialsManager/tree/161783a4c89a3f694b8010778dd34029bc153921
Upvotes: 0
Reputation: 14068
Note: this solution requires 1Password, which requires a paid subscription.
1Password can securely store credentials, and automatically create short-term credentials even in cases where you are working in a basic setup with AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
configuration.
MFA can be enabled using biometrics (e.g. faceid, touchid, apple watch in the Apple world, others as well) -- 1Password will supply the required MFA token automatically.
Set up the 1Password CLI (op
) using these instructions: https://developer.1password.com/docs/cli
Set up the AWS plugin, including steps to enable MFA using these instructions: https://developer.1password.com/docs/cli/shell-plugins/aws
Upvotes: 0
Reputation: 14045
The CLI can manage a lot of this for you if you're using roles. Described here: http://docs.aws.amazon.com/cli/latest/userguide/cli-roles.html
In my credentials file I have:
[my_iam_user]
aws_access_key_id = AKIABLAHBLAHBLAHBLAH
aws_secret_access_key = <blah>
region = us-east-1
[my_admin_role]
role_arn = arn:aws:iam::123456789123:role/my_admin_role
source_profile = my_iam_user
mfa_serial = arn:aws:iam::123456789123:mfa/my_iam_user
region = us-east-1
Note the mfa_serial
entry. You can get this value from your user details in the AWS IAM console. This entry tells the CLI that MFA is required for that role.
When I call aws s3 ls --profile my_admin_role
it says Enter MFA code:
, after I paste in the code it returns the listing.
Note: I haven't found a way to get the CLI to ask for MFA when calling a user profile (--profile my_iam_user
) only calling a role profile triggers the MFA request.
The MFA token is then carried forward and the user profile can be used as well:
aws sts get-caller-identity --profile my_iam_user
# {
# "Account": "123456789123",
# "UserId": "AIDABLAHBLAHBLAHBLAH",
# "Arn": "arn:aws:iam::123456789123:user/my_iam_user"
# }
aws sts get-caller-identity --profile my_admin_role
# {
# "Account": "123456789123",
# "UserId": "AROABLAHBLAHBLAHBLAH:AWS-CLI-session-1234567890",
# "Arn": "arn:aws:sts::123456789123:assumed-role/my_admin_role/AWS-CLI-session-1234567890"
# }
Upvotes: 115
Reputation: 574
Snippet easy to copy and paste.
cat <<EOF >aws-credentials.sh
export AWS_ACCESS_KEY_ID=<key>
export AWS_SECRET_ACCESS_KEY=<secret>
export AWS_DEFAULT_REGION=us-east-1
export AWS_USER=<aws_user>
export AWS_ACCOUNT=<aws_account>
EOF
# Almost one liner:
source aws-credentials.sh
source <(paste -d= <(echo -ne "export AWS_ACCESS_KEY_ID\nexport AWS_SECRET_ACCESS_KEY\nexport AWS_SESSION_TOKEN\nexport EXPIRATION\n") <(aws sts get-session-token --duration-seconds 129600 --serial-number arn:aws:iam::$AWS_ACCOUNT:mfa/$AWS_USER --token-code $(read -p "Token:" TOKEN; echo $TOKEN) | jq '.Credentials | .[]'))
# Example
aws s3 ls s3://my-bucket/
Upvotes: 0
Reputation: 5145
I think my answer will be useful for people trying to follow the official docs, which sadly leave out a lot of details. I discovered a few nuances when trying to figure out how to do this according to the official docs so I wrote this up to help.
I originally had a non-MFA CLI user configured in my ~/.aws/credentials file
(this will be important later)
I then created a 2nd user "mfa-test" to which I attached a custom policy named Force_MFA. I sourced the policy from this aws doc
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListActions",
"Effect": "Allow",
"Action": [
"iam:ListUsers",
"iam:ListVirtualMFADevices"
],
"Resource": "*"
},
{
"Sid": "AllowIndividualUserToManageTheirOwnMFA",
"Effect": "Allow",
"Action": [
"iam:CreateVirtualMFADevice",
"iam:DeleteVirtualMFADevice",
"iam:ListMFADevices",
"iam:EnableMFADevice",
"iam:ResyncMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
]
},
{
"Sid": "AllowIndividualUserToDeactivateOnlyTheirOwnMFAOnlyWhenUsingMFA",
"Effect": "Allow",
"Action": [
"iam:DeactivateMFADevice"
],
"Resource": [
"arn:aws:iam::*:mfa/${aws:username}",
"arn:aws:iam::*:user/${aws:username}"
],
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "BlockMostAccessUnlessSignedInWithMFA",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:ListMFADevices",
"iam:ListUsers",
"iam:ListVirtualMFADevices",
"iam:ResyncMFADevice"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
Nuances I learned about this command:
aws sts get-session-token --serial-number arn:aws:iam::853680132675:mfa/mfa-test --token-code 630011
You should update to the latest version of the AWS CLI before running the command.
The docs mention it might fail if your aws cli isn't updated, but it's easy to miss that suggestion.
The TOTP(time-based one-time password) token code 630011
comes from your virtual MFA device
arn:aws:iam::853680132675:mfa/mfa-test
can be looked up by viewing the Security credentials tab of the IAM user.
The command will fail (without a useful error message) if ~/.aws/credentials corresponds to another account (like non-MFA CLI user).
[default]
aws_access_key_id = lalala
aws_secret_access_key = lalala
In other words, there's a hard requirement that the credentials used when running the aws sts get-session-token --serial-number arn:aws:iam::853680132675:mfa/mfa-test --token-code 630011
command, map to the user referenced in that command (username = mfa-test
). (The only exception is if you have additional profiles defined in ~/.aws/credentials & ~/.aws/config and reference them
using --profile additional_profile
)
So I'd recommend running aws sts get-caller-identity
and making sure you see the user (mfa-test) in the results (.../user/mfa-test) matches the user mentioned in the ARN of the mfa device (.../mfa/mfa-test)
"Arn": "arn:aws:iam::853680132675:user/mfa-test"
Also if you install jq (json query) cli tool then unix users can use the following trick to streamline the trade-off of non-MFA CLI creds to MFA CLI creds that expire after 12 hours by default (note the | tr -d '"'
in the command is read as translate delete "
, it strips out the double quotes)
export MFA_CLI_SESSION=$(aws sts get-session-token --serial-number arn:aws:iam::853680132675:mfa/mfa-test --token-code 630011)
export AWS_ACCESS_KEY_ID=$( echo $MFA_CLI_SESSION | jq .Credentials.AccessKeyId | tr -d '"' )
export AWS_SECRET_ACCESS_KEY=$( echo $MFA_CLI_SESSION | jq .Credentials.SecretAccessKey | tr -d '"' )
export AWS_SESSION_TOKEN=$( echo $MFA_CLI_SESSION | jq .Credentials.SessionToken | tr -d '"' )
You can run these commands as a smoke test to verify the variables aren't empty.
echo $MFA_CLI_SESSION
echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY
echo $AWS_SESSION_TOKEN
From this point on your AWS CLI commands will work for the next 12 hours within that terminal session (since they're implemented as env vars). Also they'll work without having to add --profile additional_profile
flag to your commands.
Upvotes: 1
Reputation: 11
Authenticating with MFA is done with the aws sts
command. The basic process is:
~/.aws/credentials
.aws sts
command with the "permanent" profile.~/.aws/credentials
with the result from #2aws
commands.#1:
[myaccountPerm]
aws_access_key_id = REDACTED
aws_secret_access_key = REDACTED
#2:
$ aws sts get-session-token --token-code 123456 --profile myaccountPerm --serial-number arn:aws:iam::REDACTED:mfa/REDACTED
{
"Credentials": {
"AccessKeyId": "REDACTED",
"SecretAccessKey": "REDACTED",
"SessionToken": "REDACTED",
"Expiration": "2021-03-13T09:37:10Z"
}
}
#3:
[myaccount]
aws_access_key_id = REDACTED
aws_secret_access_key = REDACTED
aws_session_token = REDACTED
You'll notice that this is kind of an excessive process for logging in. I recommend using a utility/script for this purpose. Several exist, including some mentioned in other answers.
I have also written such a utility, as well as an in-depth article on how to authenticate with MFA using the AWS CLI (includes a couple of other details, like how to require MFA).
My utility is just a short script, and doesn't use a pip installer, which makes it easy to inspect.
Upvotes: 0
Reputation: 1898
A one-liner to authorize and append an MFA user to your credentials file using jq:
SERIAL_NUMBER=arn:aws:iam::000000000000:mfa/john TOKEN_CODE=123123 PROFILE_NAME=my_aws_2fa; \
aws sts get-session-token --serial-number $SERIAL_NUMBER --token-code $TOKEN_CODE \
| jq -r '.Credentials | ("aws_access_key_id = " + .AccessKeyId), ("aws_secret_access_key = " + .SecretAccessKey), ("aws_session_token = " + .SessionToken)' \
| (echo "\n[$PROFILE_NAME]" && cat) >> ~/.aws/credentials
Upvotes: 0
Reputation: 200998
Call aws sts get-session-token --serial-number <serial> --token-code <code>
documented here. This will give you a temporary security token. Documentation on using the temporary security token can be found here.
Upvotes: 23
Reputation: 2975
Run the sts get-session-token AWS CLI command, replacing the variables with information from your account, resources, and MFA device:
$ aws sts get-session-token --serial-number arn-of-the-mfa-device --token-code code-from-token
https://aws.amazon.com/premiumsupport/knowledge-center/authenticate-mfa-cli/
Upvotes: 1
Reputation: 1197
Wrote a tool to add MFA support for standard IAM user profiles until @outcoldman PR gets merged: https://github.com/tongueroo/aws-mfa-secure
gem install aws-mfa-secure
~/.aws/credentials
with mfa_serial
~/.aws/credentials:
[mfa]
aws_access_key_id = BKCAXZ6ODJLQ1EXAMPLE
aws_secret_access_key = ABCDl4hXikfOHTvNqFAnb2Ea62bUuu/eUEXAMPLE
mfa_serial = arn:aws:iam::112233445566:mfa/MFAUser
~/.bash_profile
alias aws="aws-mfa-secure session"
Restart your terminal.
$ export AWS_PROFILE=mfa
$ aws s3 ls
Please provide your MFA code: 751888
2019-09-21 15:53:34 my-example-test-bucket
$ aws s3 ls
2019-09-21 15:53:34 my-example-test-bucket
$
Assume role profiles work already for the AWS CLI, here's an example:
~/.aws/credentials:
[mfa]
aws_access_key_id = BKCAXZ6ODJLQ1EXAMPLE
aws_secret_access_key = ABCDl4hXikfOHTvNqFAnb2Ea62bUuu/eUEXAMPLE
mfa_serial = arn:aws:iam::112233445566:mfa/MFAUser
[assumed-role]
role_arn = arn:aws:iam::112233445566:role/Admin
source_profile = mfa
role_session_name = MFAUser
mfa_serial = arn:aws:iam::112233445566:mfa/MFAUser
Upvotes: 3
Reputation: 25167
I'm on windows and I created a batch file to pass in my MFA code and have it automatically set up my credentials. First, you need to set up your production credentials in AWS:
aws configure --profile prod
Answer the questions appropriately with your key and secret. Then, I run my script like this:
C:\> mfa-getCreds.bat 229168
Your credentials are set up, and will expire on 2019-05-12T04:04:13Z
Now you should be able to run aws commands like this: aws s3 ls
Here are the contents of my mfa-getCreds.bat
:
@echo off
set TOKEN=%1
if not defined TOKEN goto showUsage
@call aws sts get-session-token --profile prod --serial-number "arn:aws:iam::109627855994:mfa/ryan.shillington" --token-code %* > c:\temp\mfa-getCreds.json
FOR /F "tokens=* USEBACKQ" %%g IN (`jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json`) do (SET AWS_ACCESS_KEY=%%g)
FOR /F "tokens=*" %%g IN ('jq -r ".Credentials.SecretAccessKey" c:\temp\mfa-getCreds.json') do (SET "AWS_SECRET_KEY=%%g")
FOR /F "tokens=*" %%g IN ('jq -r ".Credentials.SessionToken" c:\temp\mfa-getCreds.json') do (SET "AWS_SESSION_TOKEN=%%g")
FOR /F "tokens=*" %%g IN ('jq -r ".Credentials.Expiration" c:\temp\mfa-getCreds.json') do (SET "EXPIRATION=%%g")
set AWS_ACCESS_KEY_ID=%AWS_ACCESS_KEY%
set "AWS_SECRET_ACCESS_KEY=%AWS_SECRET_KEY%"
echo.
echo Your credentials are set up, but will expire on %EXPIRATION%
echo.
echo Now you should be able to run aws commands like this: aws s3 ls
goto :EOF
:showUsage
echo Usage: %0 [MFA Token]
goto :EOF
For this to run, you'll need the excellent jq package in your path.
Upvotes: 2
Reputation: 4346
AWS MFA use on the command line can be rather unpleasant and cumbersome, especially if you have multiple profiles and roles.
I have released awscli-mfa.sh
script that makes MFA/role session management on the command line a lot easier. A companion script enable-disable-vmfa-device.sh
similarly makes it easy to enable or disable a virtual MFA device on an IAM user account.
awscli-mfa.sh
persists a started session in ~/.aws/credentials
(with some info in ~/.aws/config
), or allows you to start an in-env session only so that its details don't get persisted. When executed in Windows Subsystem for Linux, the script also provides session activation strings for PowerShell and Windows command line. However, the script itself only runs in bash (written for macOS, Linux, and WSL bash with Ubuntu).
You can find the scripts and the example MFA policies in my GitHub repo at https://github.com/vwal/awscli-mfa
Upvotes: 0
Reputation: 6674
aws-mfa
acts as a wrapper around sts
and works really well: https://github.com/broamski/aws-mfa
Upvotes: 6
Reputation: 46
I have forked Chinmay's gist and updated it to pull the device serial from aws instead of hardcoding it. I have also updated the exits to return a status of 1 instead of just exiting.
Available here: https://gist.github.com/jpribyl/e44021ae5cbf7fd1b4549598e85b5341
I am using it in deploy scripts like this (I renamed the script to awsMfaCli.sh):
. awsMfaCli.sh
script_status=$?
if [[ $script_status -ne 1 ]]; then
echo "Building production"
if npm run build ; then
echo "Build Successful"
else
echo "Error building, exiting.."
return 1
fi
echo "Removing all files on bucket.."
aws s3 rm --recursive s3://mybucket
echo "Uploading site.."
aws s3 sync build/ s3://mybucket
echo "S3 Upload complete.."
echo "Deployment complete."
else
return 1
fi
Upvotes: 0
Reputation: 8214
We documented a few considerations for AWS API multifactor in general (where to add the conditions, what are the implications etc.) in the documentation for some custom tooling (https://github.com/kreuzwerker/awsu) we developed for using Yubikeys as source for the TOTP tokens. This makes working with roles and long-term credentials + session tokens pretty easy.
Upvotes: 0
Reputation: 11
My use-case is I have a root account where all IAM users are created and assigned to IAM groups which in turn have the capability to assume roles on a different account with varying degree of access depending on the group they are on. I have a few house rules in place;
This has been set up using AWS Shared Organizations.
Previously, I've been using a python script I wrote to let my users to login via cli with MFA and switch accounts. This is done by manipulating the ~/.aws/credentials.
I've since migrated to using this project https://gitlab.com/severity1/aws-auth, which is written in Go and allows me to do the same without much setup and it works on windows, macosx and linux.
This effectively gives all my users the ability to do local testing while developing Apps for AWS without having to hardcode AWS Credentials into their code.
Upvotes: 1
Reputation: 497
I wrote a small bash script to get over this annoying problem. You can find it here: https://gist.github.com/geekgunda/db4c9c8d850c08a48d1d60f119628032
Assumptions:
Upvotes: 1
Reputation: 11832
I have published a PR for aws-cli, which will allow to use mfa_serial in the credentials, that will force you to enter the token before making request to AWS (and it will be cached while token is valid)
Feel free to vote, if you want to get it in.
Upvotes: 9