amazon-web-servicesaws-cliaws-stsaws-credentials

How to use AWS cli to get access keys in an MFA context?


I'm developing a simple app that will run on an existing EC2 instance. The AWS account is secured with MFA. We use a main account and assume a role into our target account for personal access.

The app only deals with the MFA when I'm developing locally. I would like to avoid creating a user in the target account just for development, and wrap my local development in --profile like functionality.

My thought was to use aws sts to generate the access key and secrete key, but performing an assume role using the same setup I have in my credentials file gives me an Access Denied error.

My credentials file follows this pattern:

[main-profile]
aws_access_key_id={access-key}
aws_secret_access_key={secret-key}

[target-profile]
mfa_serial=arn:blah
role_arn=arn:blah2
source_profile=main-profile

I tried to use aws sts --role-name arn:blah2 --role-session-name test --profile main-profile. It seems like I would need to reference the MFA device as well but I don't see that as an option.

Is there any way I can do what I'm looking to do?


Ok so I was able to successfully retrieve and cache the credentials, but the access key returned seems to not be valid for setting into the environment variable. Thoughts?

#!/bin/bash
#set -x

###
# Note: This uses jq (sudo apt-get install jq -y)

targetProfile="target-profile"

sessionFile="/tmp/session-$targetProfile.txt"
sessionFile=$(echo $sessionFile)
echo "Looking for $sessionFile"
if [[ -f "$sessionFile" ]]; then
    echo "Found $sessionFile"
    sessionInfo="$(cat $sessionFile)"    

else
    echo "Building $sessionFile"

    roleArn="$(aws configure get role_arn --profile $targetProfile)"
    mfaArn="$(aws configure get mfa_serial --profile $targetProfile)"
    mainProfile="$(aws configure get source_profile --profile $targetProfile)"

    echo MFA Token:
    read mfaToken

    echo "aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile"
    sessionInfo="$(aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile)"

fi
echo "Current session info: $sessionInfo"

expirationDateValue="$(echo $sessionInfo | jq '.Credentials.Expiration' | tr -d '"')"
echo "Expiration value: $expirationDateValue"
expirationDate=$(date -d $expirationDateValue +%s)
echo "Expiration date: $expirationDate"
currentDate=$(date +%s)
echo "Current date: $currentDate"

if [[ $currentDate -ge $expirationDate ]]; then
    rm $sessionFile
    /bin/bash $0
    exit
fi  

echo "$sessionInfo" > $sessionFile

export AWS_ACCESS_KEY_ID=$(echo $sessionInfo | jq '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $sessionInfo | jq '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $sessionInfo | jq '.Credentials.SessionToken')

#dotnet run
aws s3 ls

When I run this, I get the following error message:

An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The AWS Access Key Id you provided does not exist in our records.

It turns out I couldn't re-use the quotes in the values returned from the session JSON. I had to remove the quotes and add new quotes, which actually kind of makes sense. See my answer below for my solution.


Solution

  • Got it! I finally found the correct Bash spell : o)

    #!/bin/bash
    #set -x
    
    ###
    # Note: This uses jq (sudo apt-get install jq -y)
    
    targetProfile="target-profile"
    
    sessionFile="/tmp/session-$targetProfile.txt"
    sessionFile=$(echo $sessionFile)
    echo "Looking for $sessionFile"
    if [[ -f "$sessionFile" ]]; then
        echo "Found $sessionFile"
        sessionInfo="$(cat $sessionFile)"    
    
    else
        echo "Building $sessionFile"
    
        roleArn="$(aws configure get role_arn --profile $targetProfile)"
        mfaArn="$(aws configure get mfa_serial --profile $targetProfile)"
        mainProfile="$(aws configure get source_profile --profile $targetProfile)"
    
        echo MFA Token:
        read mfaToken
    
        sessionInfo="$(aws sts get-session-token --serial-number $mfaArn --token-code $mfaToken --profile $mainProfile)"
    
    fi
    
    expirationDateValue="$(echo $sessionInfo | jq '.Credentials.Expiration' | tr -d '"')"
    expirationDate=$(date -d $expirationDateValue +%s)
    currentDate=$(date +%s)
    
    if [[ $currentDate -ge $expirationDate ]]; then
        echo "Session expired"
        rm $sessionFile
        /bin/bash $0
        exit
    fi  
    
    echo "$sessionInfo" > $sessionFile
    
    export AWS_ACCESS_KEY_ID="$(echo $sessionInfo | jq '.Credentials.AccessKeyId' | tr -d '"')"
    export AWS_SECRET_ACCESS_KEY="$(echo $sessionInfo | jq '.Credentials.SecretAccessKey' | tr -d '"')"
    export AWS_SESSION_TOKEN="$(echo $sessionInfo | jq '.Credentials.SessionToken' | tr -d '"')"
    
    #dotnet run
    aws s3 ls