Skip to content

Instantly share code, notes, and snippets.

@tracphil
Forked from defanator/.envrc
Created December 1, 2023 13:20
Show Gist options
  • Save tracphil/8e4c69a38a4ffb1a354612c5efee2277 to your computer and use it in GitHub Desktop.
Save tracphil/8e4c69a38a4ffb1a354612c5efee2277 to your computer and use it in GitHub Desktop.

Revisions

  1. @defanator defanator created this gist Mar 7, 2018.
    96 changes: 96 additions & 0 deletions .envrc
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,96 @@
    #
    # Copyright (C) Andrei Belov ([email protected])
    #
    # 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
    24 changes: 24 additions & 0 deletions README
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,24 @@
    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