AWS MFA in Bash

Best practice when working with AWS (along with most things that require authentication) is to use some form of multi-factor authentication (MFA). After enabling MFA for your account, interactions with AWS using the CLI needs to provide the corresponding additional information. The CLI itself doesn’t provide particular support for this need, and so often additional helpers such as awsmfa are used. While such a tool is very effective and as the one referenced is written in Python it is unlikely to represent significant overhead beyond the AWS CLL/boto, I’ve had cases in the past for which it was less than ideal.

The particular case where a solution such as awsmfa did not readily help was where I wanted to rely on the relevant ticket information to be present in the environment which could then be accessed by the standard AWS credentials lookup chain. As forking an additional process does not lend itself to modifying the current environment, adopting an approach which can more directly modify that environment would be preferred. The shell/Bash can coordinate calls to the AWS CLI to support this functionality across a range of flows.

Supported Flows

Different organizations manage their AWS IAM differently, so far I’ve used variations of this script to support. I’ve typically only had to use one of these at a time so in the past I’ve modified the script in ways that may or may not preserve backwards compatibility, so some flows may need some tightening.

Basic Single User MFA

The most straightforward scenario is supporting MFA for a given IAM user, analogous to logging directly into the desired account using the AWS console. This can be supported by a basic population of the associated environment variables.

Multiple Specified Profiles

Multiple accounts can be accessed by associating the ticket information in a profile for each account and then referencing the profile while accessing AWS. In this scenario the environment doesn’t need to be modified and therefore this is likely to not be any value in this approach compared to awscli. A wrinkle when using this approach is that the named profiles risk coupling the calls that are being made with the environment in which they are executed thereby inviting additional complexity of one form or other.

Assumed Roles

A more elaborate AWS configuration may involve a network of accounts where most of the resources themselves are housed in accounts which are not that which has been logged into and is managed through cross account access which requires assuming a role in such resource accounts.

aws.sh

As referenced earlier modifying an environment is best done without forking a process and therefore modifying the environment of the current shell is best done within the current shell process. This can be accomplished through invoking functions which provide the desired functionality as opposed to calling a separate process, and this file is therefore intended to be sourced rather than run.

Variables

As many of these variables reflect the current environment they will be left mutable so as not to lead to incidentally limiting use of the shell.

AWS_CONFIG_FILE

The ARN for the MFA token should be defined in a local configuration file so the location of that file will be indicated.

declare AWS_CONFIG_FILE="${AWS_CONFIG_FILE:-${HOME}/.aws/config}"

AWS_PROFILE

Some of the use cases for this script can benefit from referencing an AWS_PROFILE, so the variable is defined here with a default of default.

declare AWS_PROFILE="${AWS_PROFILE:-default}"