Generate MFA authenticated credentials for AWS CLI (and a script to automate this task)

Generate MFA authenticated credentials for AWS CLI (and a script to automate this task)

You'll learn how to generate MFA authenticated temporary credentials to pass the MFA check while using AWS CLI to access the AWS resources.

In my previous post Securing AWS Infrastructure using MFA, we discussed how we can enforce MFA authentication on AWS Console and AWS CLI, so that users cannot access any AWS resource until they use MFA authenticated credentials.

A quick recap for AWS CLI, the following IAM policy can be attached to the IAM users, which will enforce users to use MFA to access any AWS service:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BlockMostAccessUnlessSignedInWithMFA",
            "Effect": "Deny",
            "NotAction": [
                "iam:CreateVirtualMFADevice",
                "iam:DeleteVirtualMFADevice",
                "iam:ListVirtualMFADevices",
                "iam:EnableMFADevice",
                "iam:ResyncMFADevice",
                "iam:ListAccountAliases",
                "iam:ListUsers",
                "iam:ListSSHPublicKeys",
                "iam:ListAccessKeys",
                "iam:ListServiceSpecificCredentials",
                "iam:ListMFADevices",
                "iam:GetAccountSummary",
                "sts:GetSessionToken"
            ],
            "Resource": "*",
            "Condition": {
                "BoolIfExists": {
                    "aws:MultiFactorAuthPresent": "false"
                }
            }
        }
    ]
}

In this article, we are going to discuss the steps to generate those MFA authenticated temporary credentials. These will allow the user to pass the MFA check that we applied using the above mentioned IAM policy and will grant access to our AWS resources using AWS CLI.

To accomplish this we need to:

Configure the AWS CLI with long-term credentials

The long term credentials belongs to an IAM user and are called "Access Keys". These are used to sign programmatic requests to the AWS CLI. Access keys consist of two parts:

  • Access Key ID (for example, AKIAIOSFODNN7EXAMPLE)
  • Secret Access Key (for example, wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY).

Just a heads up, the above mentioned access key is not valid 😉

The access key is prompted to be saved when we create a new IAM user with programmatic access. In case you don't have an access key for your user, we can create a new access key from the user's summary page in IAM console as shown below:

blog-0002-1.png

Once you have the access key, now we can configure that in AWS CLI using the following command:

$ aws configure
AWS Access Key ID: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name: us-east-1
Default output format: json

⚡️Interesting observation⚡️

After the above AWS CLI configuration, try running a CLI command such as to list all the S3 buckets in your AWS account and observe the output:

$ aws s3 ls

An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

Getting an "AccessDenied" error is an expected behaviour as we are still using long-term credentials to access S3, which are not MFA authenticated. Hence, not passing the MFA check defined using the IAM policy.

Generate the MFA authenticated temporary credentials

Now we will use the above configured long term credentials to generate temporary credentials which are MFA authenticated, by running the "get-session-token" CLI command:

$ aws sts get-session-token --serial-number "YourMFADeviceSerialNumber" --token-code 123456

{
    "Credentials": {
        "AccessKeyId": "ASIAIOSFODNN7EXAMPLE",
        "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY",
        "SessionToken": "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE",
        "Expiration": "2020-05-19T18:06:10+00:00"
    }
}

The serial number here is an identification number of the MFA device that is associated with the IAM user. The value for this can either be the serial number for a hardware device (such as GAHT12345678 ) or an Amazon Resource Name (ARN) for a virtual MFA device (such as arn:aws:iam::123456789012:mfa/MFA-User), which we can find on the IAM console:

blog-0002-2.png

Configure an AWS CLI profile to use the credentials

Next up we need to create a user profile for AWS CLI to store the temporary credentials generated in the previous section, so that they can be used to access the MFA protected AWS resources.

$ aws configure --profile mfa
AWS Access Key ID: ASIAIOSFODNN7EXAMPLE
AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name: us-east-1
Default output format: json

# Do add "--profile mfa" at the end of the command
$ aws configure set aws_session_token AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE --profile mfa

Bonus: Create a script to automate MFA credentials generation and setup

The following script first calls the "get-session-token" command to generate the temporary credentials and then automatically configure an AWS CLI profile named "mfa" to store these credentials.

#!/bin/bash
# Usage
#
# ./setup-mfa-cred.sh $PROFILE $MFA_DEVICE_ARN $TOKEN
# ./setup-mfa-cred.sh mfa arn:aws:iam::123456789012:mfa/MFA-User 123456
#
# aws s3 ls --profile mfa

PROFILE=$1
MFA_DEVICE_ARN=$2
TOKEN=$3

echo "Getting MFA credentials"
sts=$(aws sts get-session-token \
  --serial-number $MFA_DEVICE_ARN \
  --token-code $TOKEN \
  --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
  --output text)
sts=($sts)
echo "AWS_ACCESS_KEY_ID is ${sts[0]}"
aws configure set aws_access_key_id ${sts[0]} --profile $PROFILE
aws configure set aws_secret_access_key ${sts[1]} --profile $PROFILE
aws configure set aws_session_token ${sts[2]} --profile $PROFILE
echo "MFA Credentials stored in the AWS CLI profile: $PROFILE"

The above script requires us to pass 3 arguments i.e.

  • AWS CLI profile name (i.e. mfa)
  • MFA Device Serial Number (i.e. GAHT12345678 or arn:aws:iam::123456789012:mfa/MFA-User)
  • MFA Token (i.e. 123456)
./setup-mfa-cred.sh mfa arn:aws:iam::123456789012:mfa/MFA-User 123456

Once the AWS CLI profile is created, then we can access our MFA protected AWS resources using the CLI command, such as:

aws s3 ls --profile mfa

Note: As the credentials generated above are temporary, so they will expire after 12 hours, which is the default value for session duration. So, we can re-run the above script with a new MFA token to configure new credentials automatically within the same AWS CLI profile.


👋 Enjoyed the article? Reach out to me anytime in the comments below or on Twitter for any further discussion or feedback.

Did you find this article valuable?

Support Gurjot Singh by becoming a sponsor. Any amount is appreciated!