Skip to content

Instantly share code, notes, and snippets.

@tracphil
Forked from defanator/.envrc
Created December 1, 2023 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tracphil/8e4c69a38a4ffb1a354612c5efee2277 to your computer and use it in GitHub Desktop.
Save tracphil/8e4c69a38a4ffb1a354612c5efee2277 to your computer and use it in GitHub Desktop.
Example of direnv .envrc configuration for working with awscli as MFA-enabled IAM user
#
# Copyright (C) Andrei Belov (defanator@gmail.com)
#
# This is an example of direnv [1] .envrc file approaching the way
# of using awscli [2] with MFA-enabled accounts in a (more or less)
# secure manner.
#
# The following assumptions are expected:
#
# a) there should be two files, key.asc and skey.asc, containing
# AWS access key and secure access key, respectively, encrypted
# with GPG using a key specified in the DEFAULT_GPG_KEY
# environment variable;
#
# b) IAM user name equals local user name reported by whoami(1);
#
# c) IAM user has basic permissions to obtain general account details
# as well as personal settings like MFA devices.
#
# The policy outlined in the following document should work:
# https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_users-self-manage-mfa-and-creds.html
#
# Honored environment variables:
#
# - DEFAULT_GPG_KEY (mandatory, no default): GPG key which is being
# used to decrypt initial credentials from key.asc and skey.asc,
# as well as to encrypt IAM user session credentials in order to
# keep them in a temporary file;
#
# - AWS_SESSION_TOKEN_DURATION (default is 900): the duration, in seconds,
# that the credentials should remain valid. Acceptable durations
# for IAM user sessions range from 900 seconds (15 minutes) to 129600
# seconds (36 hours).
#
# Also it's worth to increase DIRENV_WARN_TIMEOUT to something greater
# than the default (5s) in order to avoid unnecessary warnings.
#
# [1] https://direnv.net
# [2] https://github.com/aws/aws-cli
#
umask 077
if [ -z "${DEFAULT_GPG_KEY}" ]; then
echo "Please set DEFAULT_GPG_KEY" >&2
exit 1
fi
if [ -z "${AWS_SESSION_TOKEN_DURATION}" ]; then
export AWS_SESSION_TOKEN_DURATION=900
fi
export AWS_DEFAULT_REGION=us-east-1
export AWS_ACCESS_KEY_ID=`cat key.asc | gpg2 -d -r ${DEFAULT_GPG_KEY} --no-tty 2>/dev/null`
export AWS_SECRET_ACCESS_KEY=`cat skey.asc | gpg2 -d -r ${DEFAULT_GPG_KEY} --no-tty 2>/dev/null`
HASMFA=1
WHOAMI=`whoami`
MFASERIAL=`aws --output text iam list-mfa-devices --user-name ${WHOAMI} --query 'MFADevices[0].SerialNumber'`
if [ x"${MFASERIAL}" = x"None" ]; then
HASMFA=0
fi
if [ ${HASMFA} -eq 1 ]; then
ACCOUNT=`aws --output text sts get-caller-identity --query 'Account'`
TMPSTATE=/tmp/${ACCOUNT}.asc
GETNEW=1
if [ -e ${TMPSTATE} ]; then
TOKENAGE=$((`date +%s` - `stat -f '%m' ${TMPSTATE}`))
if [ ${TOKENAGE} -lt ${AWS_SESSION_TOKEN_DURATION} ]; then
GETNEW=0
fi
fi
if [ ${GETNEW} -eq 1 ]; then
ACCOUNTALIAS=`aws --output text iam list-account-aliases --query 'AccountAliases[0]'`
if [ x"${ACCOUNTALIAS}" = x"None" ]; then
echo -n "MFA code for ${WHOAMI}@${ACCOUNT}: "
else
echo -n "MFA code for ${WHOAMI}@${ACCOUNTALIAS}: "
fi
read TOKENCODE
STS=`aws --output text sts get-session-token --serial-number "${MFASERIAL}" --token-code ${TOKENCODE} --duration ${AWS_SESSION_TOKEN_DURATION}`
echo ${STS} | gpg2 -ae -r ${DEFAULT_GPG_KEY} >${TMPSTATE}
else
STS=`cat ${TMPSTATE} | gpg2 -d -r ${DEFAULT_GPG_KEY} --no-tty 2>/dev/null`
fi
export AWS_ACCESS_KEY_ID=`echo ${STS} | awk '{print $2}'`
export AWS_SECRET_ACCESS_KEY=`echo ${STS} | awk '{print $4}'`
export AWS_SESSION_TOKEN=`echo ${STS} | awk '{print $5}'`
fi
The proposed .envrc is supposed to be placed in a top-level directory of a structure like the following (${HOME}/aws/111122223333/.envrc):
$ tree -al ${HOME}/aws/111122223333/
├── .envrc
├── eu-west-1
│   └── .envrc
├── key.asc
├── skey.asc
├── us-east-1
│   └── .envrc
├── us-west-1
│   └── .envrc
└── us-west-2
└── .envrc
In subdirectories, .envrc could be as simple as:
$ cat ${HOME}/aws/111122223333/us-west-1/.envrc
source_env ..
export AWS_DEFAULT_REGION=us-west-1
$ cat ${HOME}/aws/111122223333/eu-west-1/.envrc
source_env ..
export AWS_DEFAULT_REGION=eu-west-1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment