Skip to content

Instantly share code, notes, and snippets.

@gene1wood
Last active October 15, 2023 22:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gene1wood/1d0b090fcba672babe32da08da2f2a1e to your computer and use it in GitHub Desktop.
Save gene1wood/1d0b090fcba672babe32da08da2f2a1e to your computer and use it in GitHub Desktop.
Tool to create ephemeral awscli/boto config/credentials files for creating a long lasting (36 hour) cached MFA and child assumed role

Setup

SOURCE_PROFILE_NAME

If the AWS API key and secret which you use and and are stored in ~/.aws/credentials in a profile called default then you don't need to set the SOURCE_PROFILE_NAME in the code. If the profile name in ~/.aws/credentials is something other than default then set SOURCE_PROFILE_NAME to that name. For example if your ~/.aws/credentials looked like this

[infosec-prod]
aws_access_key_id=ABCDEFGHIJKLMNOPQRST
aws_secret_access_key=abcdefghijklmnopqrstuvwxyz012345689/+ABC

then you would need to set line 5 in get-sts-session.sh to

SOURCE_PROFILE_NAME=infosec-prod

mfa_serial

If you use an MFA token with your IAM user, make sure that in your ~/.aws/config file where you have your profile configured there is an mfa_serial set in that profile. For example, if you login with a profile called infosec-prod make sure your ~/.aws/config looks like this

[profile infosec-prod]
region = us-west-2
mfa_serial = arn:aws:iam::123456789012:mfa/jdoe

Usage

  • To cache your MFA serial so you don't need to keep entering it : get-sts-session.sh 012345
  • To assume an IAM role : get-sts-session.sh 012345 arn:aws:iam::123456789012:role/MyIAMRole
  • To assume an IAM role and enter the MFA code interactively : get-sts-session.sh arn:aws:iam::123456789012:role/MyIAMRole
  • To set the optional name of your session : get-sts-session.sh arn:aws:iam::123456789012:role/MyIAMRole production
  • To assume the IAM role set in your DEFAULT_ASSUMED_ROLE_ARN variable in the script : get-sts-session.sh 012345

The order of the three possible arguments doesn't matter

  • MFA code
  • IAM Role ARN
  • Name to give the session
#!/bin/bash
# This only needs to be set if in your non-ephemeral AWS config has a source profile name other than "default".
# Source profile is the profile with your actual long lived API keys
SOURCE_PROFILE_NAME=
# This is the ARN of the IAM role that you want to assume by default
DEFAULT_ASSUMED_ROLE_ARN=
# This is an optional descriptive name of the IAM role that you want to assume by default
DEFAULT_ASSUMED_ROLE_NAME=
# Session duration
DURATION=129600
if [ -n "$SOURCE_PROFILE_NAME" ]; then
profile_argument="--profile $SOURCE_PROFILE_NAME"
fi
unset AWS_SHARED_CREDENTIALS_FILE
unset AWS_CONFIG_FILE
unset AWS_DEFAULT_PROFILE
# Fetch the ARN of the MFA device from the source profile
MFA_SERIAL=$(aws configure get mfa_serial $profile_argument)
for argument in "$@"; do
if [[ "$argument" =~ ^[0-9]+$ ]]; then
token="$argument"
elif [ "${argument:0:12}" = "arn:aws:iam:" ]; then
assumed_role_arn="$argument"
else
assumed_role_name="$argument"
fi
done
cred_file=~/.aws/ephemeral-credentials
config_file=~/.aws/ephemeral-config
if [ -z "$MFA_SERIAL" ]; then
echo -e "Unable to determine the ARN of the MFA device from "
test -n "$SOURCE_PROFILE_NAME" && echo "profile ${SOURCE_PROFILE_NAME}" || echo "the default profile."
echo -e "Esure that a 'mfa_serial' value is configured in the [${SOURCE_PROFILE_NAME}] section of your ~/.aws/config file"
exit 1
fi
if [ -z "$assumed_role_arn" ]; then assumed_role_arn="$DEFAULT_ASSUMED_ROLE_ARN"; fi
if [ -z "$assumed_role_arn" ]; then
echo "No assumed role ARN was passed on the command line and no DEFAULT_ASSUMED_ROLE_ARN is configured in the tool."
echo "If you want to assume a role, either pass an ARN on the command line or set a DEFAULT_ASSUMED_ROLE_ARN in the tool"
echo "Proceeding assuming that you don't want to assume any role"
assumed_role_name="default"
fi
if [ -z "$assumed_role_name" ]; then assumed_role_name="$DEFAULT_ASSUMED_ROLE_NAME"; fi
if [ -z "$assumed_role_name" ]; then
IFS=':' read -ra arn <<< "$assumed_role_arn"
assumed_role_name="${arn[4]}-${arn[5]#role/}"
fi
if [ -z "$token" ]; then
read -p 'MFA code (6 digit number) : ' token
fi
if ! grep "^\[profile ${assumed_role_name}\]$" "$config_file" >/dev/null 2>&1; then
echo "[profile ${assumed_role_name}]" >> "$config_file"
fi
if ! sts=( $(
aws sts get-session-token \
${profile_argument} \
--serial-number "$MFA_SERIAL" \
--token-code "$token" \
--duration-seconds "$DURATION" \
--query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
--output text
) ); then
exit 1
fi
AWS_SHARED_CREDENTIALS_FILE="$cred_file" AWS_CONFIG_FILE="$config_file" aws configure set aws_access_key_id ${sts[0]} --profile default
AWS_SHARED_CREDENTIALS_FILE="$cred_file" AWS_CONFIG_FILE="$config_file" aws configure set aws_secret_access_key ${sts[1]} --profile default
AWS_SHARED_CREDENTIALS_FILE="$cred_file" AWS_CONFIG_FILE="$config_file" aws configure set aws_session_token ${sts[2]} --profile default
if [ -n "$assumed_role_arn" ]; then
AWS_SHARED_CREDENTIALS_FILE="$cred_file" AWS_CONFIG_FILE="$config_file" aws configure set profile.${assumed_role_name}.source_profile default
AWS_SHARED_CREDENTIALS_FILE="$cred_file" AWS_CONFIG_FILE="$config_file" aws configure set profile.${assumed_role_name}.role_arn ${assumed_role_arn}
fi
export_line="export AWS_SHARED_CREDENTIALS_FILE=\"$cred_file\" AWS_CONFIG_FILE=\"$config_file\""
if [ -n "$assumed_role_arn" ]; then
export_line="$export_line AWS_DEFAULT_PROFILE=\"$assumed_role_name\""
export_line="$export_line;PS1=\"\$PS1\${AWS_DEFAULT_PROFILE:+(\$AWS_DEFAULT_PROFILE)} \""
fi
echo -e "\e[92m${export_line}\e[39m"
token_code=123456
export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s" \
$(aws sts assume-role \
--role-arn `aws configure get role_arn` \
--role-session-name MySession \
--query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken]" \
--output text \
--serial-number `aws configure get mfa_serial` \
--token-code $token_code))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment