Securing Cross-Account AWS API Calls & CLI Access with MFA (Two-Factor) Authentication

By Morten Jensen

| 2 minutes read

AWS Cross-Account Roles are an excellent way of managing access to a target account (the account in which work is carried out) from other AWS accounts. Some scenarios to consider in this context include:

  • Managed Services & Support
  • Centralised accounts, e.g. from an AWS Organizations perspective
  • 3rd parties & services (e.g. Cloudcheckr)

The advantages of Cross-Account roles include not having to create an IAM user account in the target account for every single user that needs access and instead delegate trust to the source account (where the IAM users exist). It also enables centralised authentication inside an organisation by designating a centralised AWS access account in which all users like developers, testers and operations have an account; and in turn are given the necessary access to organisational AWS accounts.

In addition to this, the role set-up can mandate MFA authentication from the target account, which provides a much more secure environment where the effects of accidental leakage of credentials can be mitigated considerably.

I previously blogged on how to escalate privileges via MFA-dependent policies for AWS API & CLI access from a shell script perspective.

However, this approach is also possible when using Cross-Account Roles. The script to do so is just a little bit different (see below).

One would need to replace the following in the script (I typically keep one script per cross-account role):

  • 234567890123 with the target account id
  • cross-account-role-name with the name of the role in the target account
  • role-session-name (my-session-role) optionally with a meaningful session name
  • serial number with the ARN of the MFA device from the IAM user in the source account
  • profile name (my-profile) with the name of the source account AWS key/secret profile from ~/.aws/credentials

To use the script don’t forget to source it in the shell to get the environment variables set in current shell context:

. get-aws-cross-account-role-credentials

The script:

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
echo -n "Enter token followed by [ENTER]: "
read token
output=`aws sts assume-role --role-arn arn:aws:iam::234567890123:role/cross-account-role-name \
 --role-session-name my-session-role --serial-number "arn:aws:iam::123456789012:mfa/MyIAMUsername" \
--token-code $token --profile my-profile --output text "$@"`
rc=$?
if [[ $rc -ne 0 ]] ; then
  return $rc
fi
line=`cat <<<"$output" | head -2 | tail -1`
oarr=($line)
export AWS_ACCESS_KEY_ID="${oarr[1]}"
export AWS_SECRET_ACCESS_KEY="${oarr[3]}"
export AWS_SESSION_TOKEN="${oarr[4]}"