AWth (pronounced Awe-th) is yet another CLI tool for authenticating to multiple AWS accounts using MFA.
🚧 We're still making heavy modifications here, so things may be broken (we haven't tested assuming roles yet) 🚧
It's a fork/significant rewrite of elastic/aws-mfa which is a fork of broamski/aws-mfa which itself uses the boto4 library to authenticate to AWS. @cloudymax and @jessebot are giving it a massive face lift to use modern python libraries such as rich and click, but also to use modern packaging such as poetry. In addition to that, we've grabbed some required fixes to make this work with the latest version of boto, and we're committed to making this work well in modern environments. The original aws-mfa was great, but it's been almost a decade and this was needed.
-
add support for keychain not always being on (covers default OS keychain tool and keypass when it is on)
-
use click instead of argparse
- add prettier logging and help text
-
add support for specifying a region
-
remove deprecated boto support (we now will only support boto3)
-
add support for long term credentials from bitwarden
- add support for MFA Token from bitwarden
-
add support for long term credentials from 1password
- add support for MFA Token from 1password
-
test assuming roles
-
test sourcing this as a library rather than using the CLI
-
revise docs (still need to do a full pass on it since fork
-
support
$AWS_KEYCHAIN=true
env var to always use keychain -
setup both your
~/.aws/credentials
file and your~/.aws/config
file- setup setting json as default output
aws-mfa makes it easy to manage your AWS SDK Security Credentials when Multi-Factor Authentication (MFA) is enforced on your AWS account. It automates the process of obtaining temporary credentials from the AWS Security Token Service and updating your AWS Credentials file (located at ~/.aws/credentials
). Traditional methods of managing MFA-based credentials requires users to write their own bespoke scripts/wrappers to fetch temporary credentials from STS and often times manually update their AWS credentials file.
The concept behind awth
is that there are 2 types of credentials:
-
long-term
- Your typcial AWS access keys, consisting of anAWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
-
short-term
- A temporary set of credentials that are generated by AWS STS using yourlong-term
credentials in combination with your MFA device serial number (either a hardware device serial number or virtual device ARN) and one time token code. Your short term credentials are the credentials that are actively utilized by the AWS SDK in use.
If you haven't yet enabled multi-factor authentication for AWS API access, check out the AWS article on doing so.
I highly recommend you use pipx for installation:
pipx install awth
You could also use pip directly though:
pip install awth
By default long term credentials are stored long term credentials are stored in and retrieved from ~/.aws/credentials
.
It is possible to use system keychain to store and retrieve long term credentials by in system keychain (using keyring library), so only short term credentials are stored in ~/.aws/credentials
. To use this option pass in --keychain
. (Coming soon: set $AWS_KEYCHAIN=true to always use the keychain)
In a typical AWS credentials file credentials are stored in sections, denoted by a pair of brackets: []
. The [default]
section stores your default credentials. You can store multiple sets of credentials using different profile names. If no profile is specified, the [default]
section is always used.
Long term credential sections are identified by the convention [<profile_name>-long-term]
and short term credentials are identified by the typical convention: [<profile_name>]
. The following illustrates how you would configure you credentials file using awth
with your default credentials:
[default-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
After running awth
, your credentials file would read:
[default-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
[default]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
Similarly, if you utilize a credentials profile named development, your credentials file would look like:
[development-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
After running awth
, your credentials file would read:
[development-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
[development]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
The default naming convention for the credential section can be overriden by using the --long-term-suffix
and
--short-term-suffix
command line arguments. For example, in a multi account scenario you can have one AWS account
that manages the IAM users for your organization and have other AWS accounts for development, staging and production
environments.
After running awth
once for each environment with a different value for --short-term-suffix
, your credentials
file would read:
[myorganization-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
[myorganization-development]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
[myorganization-staging]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
[myorganization-production]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
This allows you to access multiple environments without the need to run awth
each time you want to switch
environments.
If you don't like the a long term suffix, you can omit it by passing the value none
for the --long-term-suffix
command line argument. After running awth
once for each environment with a different value for
--short-term-suffix
, your credentials file would read:
[myorganization]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
[myorganization-development]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
[myorganization-staging]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
[myorganization-production]
aws_access_key_id = <POPULATED_BY_awth>
aws_secret_access_key = <POPULATED_BY_awth>
aws_security_token = <POPULATED_BY_awth>
screenreader friendly usage:
--device arn:aws:iam::123456788990:mfa/mirandel-smith The MFA Device ARN. This value can also be provided via the environment variable 'MFA_DEVICE' or the ~/.aws/credentials variable 'aws_mfa_device'.
--duration DURATION The duration, in seconds, that the temporary credentials should remain valid. Minimum value: 900 (15 minutes). Maximum: 129600 (36 hours). Defaults to 43200 (12 hours), or 3600 (one hour) when using '--assume-role'. This value can also be provided via the environment variable 'MFA_STS_DURATION'.
--profile PROFILE If using profiles, specify the name here. The default profile name is 'default'. The value can also be provided via the environment variable 'AWS_PROFILE'.
--long-term-suffix LONG_TERM_SUFFIX To identify the long term credential section by [<profile_name>-LONG_TERM_SUFFIX]. Use 'none' to identify the long term credential section by [<profile_name>]. Omit to identify the long term credential section by [<profile_name>-long-term].
--short-term-suffix SHORT_TERM_SUFFIX To identify the short term credential section by [<profile_name>-SHORT_TERM_SUFFIX]. Omit or use 'none' to identify the short term credential section by [<profile_name>].
--assume-role arn:aws:iam::123456788990:role/RoleName The ARN of the AWS IAM Role you would like to assume, if specified. This value can also be provided via the environment variable 'MFA_ASSUME_ROLE'
--role-session-name ROLE_SESSION_NAME Friendly session name required when using --assume- role. By default, this is your local username.
--token TOKEN, --mfa-token TOKEN Provide MFA token as an argument
--no-keychain Do not use system keychain to store or retrieve long term credentials
Argument precedence: Command line arguments take precedence over environment variables.
Run awth
before running any of your scripts that use any AWS SDK.
Using command line arguments:
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith
INFO - Using profile: default
INFO - Your credentials have expired, renewing.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):123456
INFO - Success! Your credentials will expire in 1800 seconds at: 2015-12-21 23:07:09+00:00
Using environment variables:
export MFA_DEVICE=arn:aws:iam::123456788990:mfa/mirandel-smith
$> awth --duration 1800
INFO - Using profile: default
INFO - Your credentials have expired, renewing.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):123456
INFO - Success! Your credentials will expire in 1800 seconds at: 2015-12-21 23:07:09+00:00
export MFA_DEVICE=arn:aws:iam::123456788990:mfa/mirandel-smith
export MFA_STS_DURATION=1800
$> awth
INFO - Using profile: default
INFO - Your credentials have expired, renewing.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):123456
INFO - Success! Your credentials will expire in 1800 seconds at: 2015-12-21 23:07:09+00:00
Output of running awth
while credentials are still valid:
$> awth
INFO - Using profile: default
INFO - Your credentials are still valid for 1541.791134 seconds they will expire at 2015-12-21 23:07:09
Using a profile: (profiles allow you to reference different sets of credentials, perhaps for different users or different regions)
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith --profile development
INFO - Using profile: development
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):666666
INFO - Success! Your credentials will expire in 1800 seconds at: 2015-12-21 23:09:04+00:00
Using a profile that is set via the environment variable AWS_PROFILE
:
$> export AWS_PROFILE=development
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith
INFO - Using profile: development
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):666666
INFO - Success! Your credentials will expire in 1800 seconds at: 2015-12-21 23:09:04+00:00
Assuming a role:
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith --assume-role arn:aws:iam::123456788990:role/some-role --role-session-name some-role-session
INFO - Validating credentials for profile: default with assumed role arn:aws:iam::123456788990:role/some-role
INFO - Obtaining credentials for a new role or profile.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):123456
INFO - Success! Your credentials will expire in 1800 seconds at: 2016-10-24 18:58:17+00:00
Assuming a role: Assume a role specified in your long-term
configuration
[default-long-term]
aws_access_key_id = YOUR_LONGTERM_KEY_ID
aws_secret_access_key = YOUR_LONGTERM_ACCESS_KEY
assume_role = arn:aws:iam::123456788990:role/some-role
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith --role-session-name some-role-session
Assuming a role using a profile:
$> awth --duration 1800 --device arn:aws:iam::123456788990:mfa/mirandel-smith --profile development --assume-role arn:aws:iam::123456788990:role/some-role --role-session-name some-role-session
INFO - Validating credentials for profile: development with assumed role arn:aws:iam::123456788990:role/some-role
INFO - Obtaining credentials for a new role or profile.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/mirandel-smith] (renewing for 1800 seconds):123456
INFO - Success! Your credentials will expire in 1800 seconds at: 2016-10-24 18:58:17+00:00
Assuming a role in multiple accounts and be able to work with both accounts simultaneously (i.e. production an staging):
$> awth —profile myorganization --assume-role arn:aws:iam::222222222222:role/Administrator --short-term-suffix production --long-term-suffix none --role-session-name production
INFO - Validating credentials for profile: myorganization-production with assumed role arn:aws:iam::222222222222:role/Administrator
INFO - Your credentials have expired, renewing.
Enter AWS MFA code for device [arn:aws:iam::111111111111:mfa/me] (renewing for 3600 seconds):123456
INFO - Success! Your credentials will expire in 3600 seconds at: 2017-07-10 07:16:43+00:00
$> awth —profile myorganization --assume-role arn:aws:iam::333333333333:role/Administrator --short-term-suffix staging --long-term-suffix none --role-session-name staging
INFO - Validating credentials for profile: myorganization-staging with assumed role arn:aws:iam::333333333333:role/Administrator
INFO - Your credentials have expired, renewing.
Enter AWS MFA code for device [arn:aws:iam::111111111111:mfa/me] (renewing for 3600 seconds):123456
INFO - Success! Your credentials will expire in 3600 seconds at: 2017-07-10 07:16:44+00:00
$> aws s3 list-objects —bucket my-production-bucket —profile myorganization-production
$> aws s3 list-objects —bucket my-staging-bucket —profile myorganization-staging