Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to assume a role without entering MFA #22

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ Usage
--role-session-name ROLE_SESSION_NAME
Friendly session name required when using --assume-
role. By default, this is your local username.
--no-mfa-prompt NO_MFA_PROMPT
If you've already created short-term
credentials and don't want to be prompted for
your MFA token when assuming a role, use this flag.
Used with --assume-role

**Argument precedence**: Command line arguments take precedence over environment variables.

Expand Down Expand Up @@ -297,3 +302,20 @@ Assuming a role in multiple accounts and be able to work with both accounts simu
$> aws s3 list-objects —bucket my-production-bucket —profile myorganization-production

$> aws s3 list-objects —bucket my-staging-bucket —profile myorganization-staging

If a profile with short-term credentials has the permissions to assume a role _without_ entering an MFA token, you can add the `--no-mfa-prompt` flag to not prompt you for the MFA token.

.. code-block:: sh

$> aws-mfa --profile myorganization --device arn:aws:iam::123456788990:mfa/dudeman
INFO - Validating credentials for profile: myorganization
INFO - Short term credentials section myorganization is missing, obtaining new credentials.
Enter AWS MFA code for device [arn:aws:iam::123456788990:mfa/dudeman] (renewing for 43200 seconds):953051
INFO - Fetching Credentials - Profile: myorganization, Duration: 43200
INFO - Success! Your credentials will expire in 43200 seconds at: 2018-02-06 03:54:40+00:00

$> aws-mfa --profile myorganization --long-term-suffix none --short-term-suffix audit-role --assume-role arn:aws:iam::222222222222:role/AuditRole --role-session-name some-session --no-mfa-prompt True
INFO - Validating credentials for profile: myorganization-audit-role with assumed role: arn:aws:iam::222222222222:role/AuditRole
INFO - Short term credentials section myorganization-audit-role is missing, obtaining new credentials.
INFO - Assuming Role - Profile: myorganization-audit-role, Role: arn:aws:iam::222222222222:role/AuditRole, Duration: 3600
INFO - Success! Your credentials will expire in 3600 seconds at: 2018-02-05 16:55:54+00:00
66 changes: 46 additions & 20 deletions aws-mfa
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ def main():
"--assume-role",
default=getpass.getuser(),
required=False)
parser.add_argument('--no-mfa-prompt',
help="If you've already created short-term "
"credentials and don't want to be prompted for "
"your MFA token when assuming a role, use this flag. "
"Used with --assume-role",
required=False)
parser.add_argument('--force',
help="Refresh credentials even if currently valid.",
action="store_true",
Expand Down Expand Up @@ -130,8 +136,15 @@ def validate(args, config):
reup_message = "Obtaining credentials for a new role or profile."

try:
key_id = config.get(long_term_name, 'aws_access_key_id')
access_key = config.get(long_term_name, 'aws_secret_access_key')
aws_creds = {
"aws_access_key_id": config.get(
long_term_name, 'aws_access_key_id'),
"aws_secret_access_key": config.get(
long_term_name, 'aws_secret_access_key')
}
if args.no_mfa_prompt:
aws_creds['aws_session_token'] = config.get(
long_term_name, 'aws_session_token')
except NoSectionError:
log_error_and_exit(
"Long term credentials session '[%s]' is missing. "
Expand Down Expand Up @@ -247,7 +260,7 @@ def validate(args, config):
% (diff.total_seconds(), exp))

if should_refresh:
get_credentials(short_term_name, key_id, access_key, args, config)
get_credentials(short_term_name, aws_creds, args, config)


def log_error_and_exit(message):
Expand All @@ -256,21 +269,22 @@ def log_error_and_exit(message):
sys.exit(1)


def get_credentials(short_term_name, lt_key_id, lt_access_key, args, config):
def get_credentials(short_term_name, aws_creds, args, config):
try:
token_input = raw_input
except NameError:
token_input = input

mfa_token = token_input('Enter AWS MFA code for device [%s] '
'(renewing for %s seconds):' %
(args.device, args.duration))
if not args.no_mfa_prompt:
mfa_token = token_input('Enter AWS MFA code for device [%s] '
'(renewing for %s seconds):' %
(args.device, args.duration))

client = boto3.client(
'sts',
aws_access_key_id=lt_key_id,
aws_secret_access_key=lt_access_key
)
client = boto3.client(
'sts',
aws_access_key_id=aws_creds['aws_access_key_id'],
aws_secret_access_key=aws_creds['aws_secret_access_key']
)

if args.assume_role:

Expand All @@ -279,14 +293,26 @@ def get_credentials(short_term_name, lt_key_id, lt_access_key, args, config):
if args.role_session_name is None:
log_error_and_exit("You must specify a role session name "
"via --role-session-name")

response = client.assume_role(
RoleArn=args.assume_role,
RoleSessionName=args.role_session_name,
DurationSeconds=args.duration,
SerialNumber=args.device,
TokenCode=mfa_token
)
if args.no_mfa_prompt:
client = boto3.client(
'sts',
aws_access_key_id=aws_creds['aws_access_key_id'],
aws_secret_access_key=aws_creds['aws_secret_access_key'],
aws_session_token=aws_creds['aws_session_token']
)
response = client.assume_role(
RoleArn=args.assume_role,
RoleSessionName=args.role_session_name,
DurationSeconds=args.duration
)
else:
response = client.assume_role(
RoleArn=args.assume_role,
RoleSessionName=args.role_session_name,
DurationSeconds=args.duration,
SerialNumber=args.device,
TokenCode=mfa_token
)

config.set(
short_term_name,
Expand Down