README.md

awscli-mfa.sh and its companion scripts

The awscli-mfa.sh and its companion scripts enable-disable-vmfa-device.sh and source-this-to-clear-AWS-envvars.sh were created to make handling multi-factor sessions with AWS command line interface easy.

These scripts create a workflow to easily and quickly create/configure a virtual MFA device ("vMFAd" for short, an app which you run on your phone) for a profile, then start an MFA or a role session, and then monitor the remaining session validity period for any of the active sessions. You can have multiple concurrent active MFA or role sessions and easily switch between them and base and root profiles (where no MFA session is used/desired) simply by re-executing the awscli-mfa.sh script. If you choose to persist sessions so that the session details get written into your config and credentials files (it's the default operation when starting a new MFA session) you can then use the --profile switch with your aws CLI command to temporarily select another active session or base/role profile without re-running awscli-mfa.sh.

Usage, quick!

(Prerequisites) Make sure you have aws CLI command installed (version 1.16.0 or newer). AWS has details for Mac and Linux including Ubuntu on Windows Subsystem for Linux (WSL). Although not necessary, it is also recommended to have jq command (version 1.5 or newer) installed. It's avilable via most package managers e.g., brew install jq on macOS, or apt install jq on Ubuntu.

If you don't yet have your AWS command line profile(s) configured: Configure the first AWS profile using aws configure for the first/default profile, or aws configure --profile "SomeDescriptiveProfileName" for a additional named profiles. You can view the any existing profiles with cat ~/.aws/config and cat ~/.aws/credentials. For an overview of the AWS configuration files, check out their documentation page. Note that while you can also put the credentials information in the config file, awscli-mfa.sh always writes the persisted session credentials in the credentials file. Furthermore, if there are any overlapping credentials properties (i.e. aws_access_key_id, aws_secret_access_key, or aws_session_token) in the two files, the entries in the credentials file take precedence. Thus I recommend using the config file for the profile configuration properties and the credentials file for the profile credentials (this is what aws configure does automatically).

If you have previously set up the vMFAd for the same IAM user via the AWS Web Console, you can skip this step. However, if you don't yet have the virtual MFA device ("vMFAd") configured, execute enable-disable-vmfa-device.sh to create and enable a vMFAd with a Google Authenticator compatible app such as my favorite, Authy (Android, iOS) on your portable device. You can also use Duo Security app for this purpose. Follow the interactive directions from the script. Note that if you happen to be on Linux without a GUI, you'll have the option to initialize the vMFAd using a seed string.

Execute awscli-mfa.sh to start an MFA session using the vMFAd you just configured. Follow the interactive directions from the script. You have couple of command line options:-q / --quick - "quick mode", forgoes all the upfront profile status checks for quicker access to the profile list-m / --monochrome - turns off the color attributes from the output

If you need to switch between the configured base/root profiles and/or active MFA or role sessions, re-execute awscli-mfa.sh and follow its prompts. If you need to disable/detach (and possibly delete) a vMFAd from your IAM user account, re-execute enable-disable-vmfa-device.sh and follow its interactive guidance.This script also accepts the -m / --monochrome switch.

Once you have activated a session in your current shell environment and then want to discontinue it, you can override it with a different session, simply close the shell window/tab, or execute:source ./source-this-to-clear-AWS-envvars.shThis script also accepts the -m / --monochrome switch.

Keep reading for the features, rationale, and script-specific overview...

awscli-mfa.sh Features

Supports any number of configured base and root profiles.

Supports any number of configured roles.

Supports chained roles which can only be authenticated with another role's existing role session.

External ID is supported in the role configuration.

Script automatically queries the maximum role session length for each role profile when the user permissions allow the user to do so. When this query is not allowed (such as perhaps with third-party roles), the user can set the session length separately for each profile by using the proprietary sessmax property in the config file. This is important especially in the cases where the allowed session maximum length is below 3600 seconds (1h) as the role session requests with a longer session length than what the role's policy allows, fail. When neither the local sessmax or queryable session maximum are available, the session uses the role session default length which is set by default to 3600 seconds (1h) with ROLE_SESSION_LENGTH_IN_SECONDS variable on top of the script.

The default length of MFA sessions is set to 32400 seconds (9h) with MFA_SESSION_LENGTH_IN_SECONDS variable on top of the script. User can similarly override the MFA session length in each profile's configuration using the sessmax property. The MFA session length is only informative: if it is set to a longer value than what the policy allows, the session will still start, but the remaining session length indicators don't show the correct value (i.e. the session stops working before the timer runs out). For this reason, the script queries an optional parameter (/unencrypted/mfa/session_length) in AWS Systems Manager (SSM)Parameter Store. If found, it will override the default and configured sessmax for that profile. This way the account administrator can advertise the maximum allowed session length (it should be set to the same value as is set in the EnforceMFA policy). The commands for managing the SSM parameter value are included at the end of this document.

The script doesn't require the default profile to be present in case you prefer to always explicitly define the profile you want to use with the aws command.

When region and output properties have not been set for a profile, the script attempts to automatically inherit them, first from the MFA/role session's source baseprofile, and then from the default profile, if available. A baseprofile missing these values only inherits them from the default profile, if available.

Validates the profiles when executed in the full mode (use --full/-f or give no option to activate as this is the default mode).

Provides "quick mode" (use --quick/-q to activate) that forgoes the validity checks but brings up the menu much faster; this makes the utility a lot more convenient to use especially when you have lots of profiles configured and need to frequently jump between baseprofiles or active sessions. However, it's a good idea to execute the script in the "full mode" every once in a while, and especially whenever there have been any changes to your profiles/IAM accounts as the full mode persists some of its findings for reference in the quick mode.

Written to be portable; the script is environment-aware and has been tested in macOS (with bash 3.2 - 5.0), Ubuntu/Debian, RedHat/CentOS, and Windows Subsystem for Linux ("WSL") with Ubuntu. The script is bash-native, but has also been tested with zsh.

Provides the option to either persist a started MFA/role session into the credentials file, or to only export the session into the environment. When executed in the bash, the script also provides profile/session activation strings for Windows PowerShell and Windows Command Prompt.

Automatically copies the selected activation string onto the clipboard; this is a built-in in macOS and in WSL bash; in the Linux Desktop distros (e.g., Ubuntu) xclip is required for the automatic copy-to-clipboard.

The script validates the AWS configuration files for common configuration errors and provides guidance on how to fix them, including providing the source profile selection for the roles which don't have a source profile configured (in the full mode only).

The script validates the baseprofiles and the MFA/role sessions (in the full mode only). When the script detects an invalid baseprofile or an invalid MFA/role session, it tags them as "invalid" both in the config and credentials files with the last detection time (provided in UTC). The invalid_as_of = {date stamp} pseudo-property makes it easier to detect and remove the invalid profiles when editing the configuration files.

The remaining validity periods are displayed for all MFA and role sessions that were started with this script (both in the full and the quick mode).

Checks the current state of the environment on startup; if a profile/session is detected in the environment, its status and details are displayed.

Presents a simplified interface when only a single profile plus its possible MFA session are present.

The only hard dependency is a recent version of the aws command. The script checks for the presence of aws and its version, and instructs the user to install/upgrade it if necessary. Additionally, in Linux, coreutils is required (and checked for), but it is generally part of the standard Linux installations.

The only soft dependency is jq. The script works without it, but with jq present it works faster, especially when any role profiles are present. When jq is not detected, the script recommends it to be installed.

Rationale

When the presence of a multi-factor authentication session is enforced with an IAM policy, the enforcement cannot be limited to the web console operations (nor should it, but that's a different topic). This is because the AWS web console is basically a front-end to the AWS APIs, i.e., the same ones which are also accessed using the aws CLI command. When you log in to the AWS web console and enter an MFA code, the browser takes care of caching the credentials and the session token, and so beyond that point, in the web browser, the MFA/role session is transparent to the user until the session eventually expires, and the AWS web console prompts the user to log in again. On the command line it's different. To create, enable, or disable a virtual MFA device (vMFAd), or to start an MFA or a role session, complex sequences of commands are required, followed by the need to painstakingly save the session token/credentials in the ~/.aws/credentials file, and then to either refer to that session profile by using the --profile {session profile name} switch in each aws CLI command, or to add/modify/delete various AWS_* environment variables by cut-and-pasting at least the aws access key id, the aws secret access key, plus for the sessions the session token. Furthermore, the only way to know that a session has expired is that the aws CLI commands start failing, thus making it difficult to plan long-running command execution, and potentially being confusing as to why such failures should occur.

The awscli-mfa.sh and its companion scripts change all this by making use of the MFA sessions with aws CLI command a breeze! Let's first look at what each script does on the high level.

Overview

These scripts provide significant interactive guidance as well as user-friendly failure information when something doesn't work as expected.

The scripts have been written for macOS (with stock bash 3.2.x, and homebrew-installed bash 4.4.x or 5.x) as well as with Linux (Ubuntu/Debian, RHEL/CentOS, and WSL Ubuntu). The only dependencies are aws itself (required) and jq (recommended but not required). The scripts will notify the user if aws is not present.

awscli-mfa.sh - Makes it easy to start MFA/role sessions with aws, and to switch between active sessions and base profiles. Multiple profiles are supported, but if only a single profile is in use, a simplified user interface is presented.

This is an interactive script since it prompts for the current MFA one time pass code from the Google Authenticator/Authy app. The accepted command line arguments are: --quick/-q for the quick mode, --full / -f for the full mode (same as no arguments), and --debug / -d which enables debug output (not very useful unless you're debugging the script's internals; note that the debug mode may print your AWS credentials on the screen).

When an MFA or a role session is started with this script, it automatically records the expiration time of the session, and names the session profile with the -mfasession postfix.

enable-disable-vmfa-device.sh - Makes it easy to enable/attach and disable/detach (as well as to delete) a virtual MFA device ("vMFAd"). Assumes that each IAM user can have one vMFAd configured at a time, and that the vMFAd is named the same as their IAM username (i.e. the serial number which is known as the ARN or "Amazon Resource Name" of the vMFAd is of the format arn:aws:iam::{AWS_account_id}:mfa/{IAM_username} when the IAM user ARN is of the format arn:aws:iam::{AWS_account_id}:user/{IAM_username}). Disabling a vMFAd requires usually an active MFA session with that profile. However, you can also use another profile that is authorized to detach a vMFAd. If you no longer have access to the vMFAd in your Google Authenticator or Authy app, you either need to have access to an AWS account which is authorized to detach vMFAd for other users and/or without an active MFA session. In the absence of such, contact the admin/ops with a request to delete the vMFAd off of your account so that you can create a new one.

As with awscli-mfa.sh, this script supports multiple configured profiles, but if only a single profile is in use, a simplified user interface is presented to either create/enable a vMFAd if none is present, or disable/deleted a vMFAd if one is active.

Also, like awscli-mfa.sh, this script supports macOS, Linux, and WSL bash. When executed on a Linux system without a GUI, you'll have the option to initialize the vMFA using a seed-string instead of scanning a QRcode image (this requires an app that allows manual seed-string entry; for example, Authy offers this feature).

source-this-to-clear-AWS-envvars.sh - A simple sourceable script that removes any AWS secrets/settings that may have been set in the local environment by the awscli-mfa.sh script. Source it, like so: source ./source-this-to-clear-AWS-envvars.sh, or set an alias, like so: alias clearaws='source ~/awscli-mfa/source-this-to-clear-AWS-envvars.sh'. The AWS envvars that are used to define alternative configuration and credentials files (AWS_CONFIG_FILE and AWS_SHARED_CREDENTIALS_FILE) are removed from the environment only if the file(s) defined by them do not exist. This is because if you are using custom config and/or credentials file locations, you likely want to keep using them more continuously rather than from session-to-session.

example-mfa-policies (a subdirectory) - If you're implementing MFA enforcement, this directory contains a carefully crafted example IAM policy, EnforceMFA.txt, for enforcing an active MFA session for aws command execution. The EnforceMFA example policy was inspired by (but significantly improved from) the example policies provided by AWS and Trek10 (both of those policies had problems which have been resolved in this example policy). Note that when an MFA enforcement is enabled on the command line using this policy, it is also enabled for the web console login. Also note that the awscli-mfa.sh script uses the innocuous permission for get-access-key-last-used as an indicator of whether MFA enforcement is in effect (besides it being harmless information security-wise it also makes sense since it's only relevant if you're using the aws commmand-line command where you obviously have an API key assigned and thus "access key last used" is relevant).
The two other example policies found in the directory, AllowMFA.txt and OpenMFA.txt, are examples of policies to be used for the transition period from non-enforced to endforced (AllowMFA), and for automated, non-interactive processes (OpenMFA). The AllowMFA policy does not enforce the MFA use, but provides the user the permissions required to manage their IAM password and the vMFAd. The only restrictions it imposes are: the user is allowed to disable the vMFAd off of their IAM user only when they have an active MFA session (this is the cornerstone requirement for the MFA validity), and they cannot access resources outside their current account even if they otherwise have permission to do so without having an active MFA session. The OpenMFA also provides the permissions for the password and the vMFAd management (and requires an MFA session for disabling the vMFAd), but imposes no other MFA-based restrictions as it is intended to be used with automated operations.

This parameter (the session length in seconds) should be set to the same value as what is being enforced in the EnforceMFA IAM policy. The below examples assume you're using a policy that has the privileges to edit the parameter. Also note that the parameter path, /unencrypted/mfa/session_length is hardcoded into the script.

To set the parameter (here setting the advertised maximum session length to 7200 seconds, or 2 hours):