Skip to content

Instantly share code, notes, and snippets.

@kumar-de
Last active June 4, 2020 08:16
Show Gist options
  • Save kumar-de/8e7c7fa8f67f84cf51f946d925e569d4 to your computer and use it in GitHub Desktop.
Save kumar-de/8e7c7fa8f67f84cf51f946d925e569d4 to your computer and use it in GitHub Desktop.
Upload lambda with MFA to AWS #aws #lambda #mfa #s3 #secure

In ~/.aws/credentials file, add a default profile

[default]
aws_access_key_id = XXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXX

In ~/.aws/config file, add the following

[default]
region = eu-west-1
output = json

Install the following python3 packages

pip3 install Click==7.0 boto3

Create a new python3 script called rotator.py

"""
rotator.py

Rotate AWS credentials, when MFA and role-based (assume role) access are in use.

Python requirements:
- boto3
- Click>=7.0

Run:
python3 rotator.py [aws-credentials-file] [MFA-device-arn] [MFA-token-from-device]

References:
https://docs.python.org/3/library/configparser.html
https://aws.amazon.com/premiumsupport/knowledge-center/authenticate-mfa-cli/
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts.html#STS.Client.get_session_token
"""

import configparser
import os.path
import sys

import boto3
import click

''' Allowed values between 900 - 43200 sec (12 hrs). '''
TOKEN_DURATION = 43200
REGION = 'eu-west-1'


def get_tokens(mfa_device_arn=None, mfa_code=None):
    """ Get new session tokens with AWS Security Token Service.
        The default profile is used to get new tokens.
    """
    session = boto3.Session(profile_name='default')
    client = session.client('sts')

    response = client.get_session_token(
        DurationSeconds=TOKEN_DURATION,
        SerialNumber=mfa_device_arn,
        TokenCode=mfa_code
    )

    tokens = {
        'output': 'json',
        'region': REGION,
        'aws_access_key_id': response['Credentials']['AccessKeyId'],
        'aws_secret_access_key': response['Credentials']['SecretAccessKey'],
        'aws_session_token': response['Credentials']['SessionToken']
    }

    print(f"Token expiration: {response['Credentials']['Expiration']}")

    return tokens


@click.command()
@click.argument('credentials_file')
@click.argument('mfa_device_arn')
@click.argument('mfa_code')
def rotate(credentials_file, mfa_device_arn, mfa_code):
    """ Rotate sessions tokens for AWS CLI. """

    ''' Check that the required parameters have values. '''
    if not os.path.isfile(credentials_file):
        print('Credentials file is missing!')
        sys.exit()
    if not mfa_device_arn.startswith('arn:aws:iam:'):
        print('MFA Device ARN should have a correct value.')
        sys.exit()
    if len(mfa_code) != 6:
        print('MFA Code should contain 6 characters.')
        sys.exit()

    ''' Get the new session tokens from AWS. '''
    tokens = get_tokens(mfa_device_arn, mfa_code)

    ''' Set the new tokens to credentials config file. '''
    config = configparser.ConfigParser()
    config.read(credentials_file)

    config['mfa'] = tokens

    with open(credentials_file, 'w') as configfile:
        config.write(configfile)

    print('New session tokens have been set successfully.')

    sys.exit()


if __name__ == '__main__':
    rotate()

Run the rotator.py script

python3 rotator.py [aws-credentials-file] [MFA-device-arn] [MFA-token-from-device]

For example:

# The ARN must contain mfa/<YourUserName>
python3 rotator.py ~/.aws/credentials arn:aws:iam::12xxxxxxxxx:mfa/achintyak 445334

Export the MFA profile

export AWS_PROFILE=mfa

Run AWS CLI commands. For example:

aws s3 ls
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment