def enable_mfa(iam_client, user, qrcode_file=None): """ Create and activate an MFA virtual device :param iam_client: :param user: :param qrcode_file: :return: """ mfa_serial = '' tmp_qrcode_file = None try: printInfo('Enabling MFA for user \'%s\'...' % user) mfa_device = iam_client.create_virtual_mfa_device( VirtualMFADeviceName=user)['VirtualMFADevice'] mfa_serial = mfa_device['SerialNumber'] mfa_png = mfa_device['QRCodePNG'] mfa_seed = mfa_device['Base32StringSeed'] tmp_qrcode_file = display_qr_code(mfa_png, mfa_seed) if qrcode_file != None: with open(qrcode_file, 'wt') as f: f.write(mfa_png) while True: mfa_code1 = prompt_4_mfa_code() mfa_code2 = prompt_4_mfa_code(activate=True) if mfa_code1 == 'q' or mfa_code2 == 'q': try: delete_virtual_mfa_device(iam_client, mfa_serial) except Exception as e: printException(e) pass raise Exception try: iam_client.enable_mfa_device(UserName=user, SerialNumber=mfa_serial, AuthenticationCode1=mfa_code1, AuthenticationCode2=mfa_code2) printInfo( 'Succesfully enabled MFA for for \'%s\'. The device\'s ARN is \'%s\'.' % (user, mfa_serial)) break except Exception as e: printException(e) pass except Exception as e: printException(e) # We shouldn't return normally because if we've gotten here # the user has potentially not set up the MFA device # correctly, so we don't want to e.g. write the .no-mfa # credentials file or anything. raise finally: if tmp_qrcode_file is not None: # This is a tempfile.NamedTemporaryFile, so simply closing # it will also unlink it. tmp_qrcode_file.close() return mfa_serial
def init_sts_session(profile_name, credentials, duration=28800, session_name=None, save_creds=True): # Set STS arguments sts_args = {'DurationSeconds': duration} # Prompt for MFA code if MFA serial present if 'SerialNumber' in credentials and credentials['SerialNumber']: if not credentials['TokenCode']: credentials['TokenCode'] = prompt_4_mfa_code() if credentials['TokenCode'] == 'q': credentials['SerialNumber'] = None sts_args['TokenCode'] = credentials['TokenCode'] sts_args['SerialNumber'] = credentials['SerialNumber'] # Init session sts_client = boto3.session.Session( credentials['AccessKeyId'], credentials['SecretAccessKey']).client('sts') sts_response = sts_client.get_session_token(**sts_args) if save_creds: # Move long-lived credentials if needed if not profile_name.endswith( '-nomfa') and credentials['AccessKeyId'].startswith('AKIA'): write_creds_to_aws_credentials_file(profile_name + '-nomfa', credentials) # Save STS values in the .aws/credentials file write_creds_to_aws_credentials_file(profile_name, sts_response['Credentials']) return sts_response['Credentials']
def read_creds(profile_name, csv_file=None, mfa_serial_arg=None, mfa_code=None, force_init=False, role_session_name='opinel'): """ Read credentials from anywhere (CSV, Environment, Instance metadata, config/credentials) :param profile_name: :param csv_file: :param mfa_serial_arg: :param mfa_code: :param force_init: :param role_session_name: :return: """ first_sts_session = False expiration = None credentials = init_creds() if csv_file: # Read credentials from a CSV file that was provided credentials['AccessKeyId'], credentials[ 'SecretAccessKey'], credentials[ 'SerialNumber'] = read_creds_from_csv(csv_file) elif profile_name == 'default': # Try reading credentials from environment variables (Issue #11) if the profile name is 'default' credentials = read_creds_from_environment_variables() if ('AccessKeyId' not in credentials or not credentials['AccessKeyId'] ) and not csv_file and profile_name == 'default': credentials = read_creds_from_ec2_instance_metadata() if not credentials['AccessKeyId'] and not csv_file: # Lookup if a role is defined in ~/.aws/config role_arn, source_profile, role_mfa_serial = read_profile_from_aws_config_file( profile_name) if role_arn and source_profile: # Lookup cached credentials try: cached_credentials_filename = get_cached_credentials_filename( profile_name, role_arn) with open(cached_credentials_filename, 'rt') as f: assume_role_data = json.load(f) credentials = assume_role_data['Credentials'] expiration = dateutil.parser.parse( credentials['Expiration']) expiration = expiration.replace(tzinfo=None) current = datetime.datetime.utcnow() if expiration < current: print('Role\'s credentials have expired on %s' % credentials['Expiration']) except Exception as e: pass if not expiration or expiration < current or credentials[ 'AccessKeyId'] == None: credentials = read_creds(source_profile) if role_mfa_serial: credentials['SerialNumber'] = role_mfa_serial # Auto prompt for a code... if not mfa_code: credentials['TokenCode'] = prompt_4_mfa_code() credentials = assume_role(profile_name, credentials, role_arn, role_session_name) # Read from ~/.aws/credentials else: credentials = read_creds_from_aws_credentials_file(profile_name) if credentials['SessionToken']: if 'Expiration' in credentials and credentials['Expiration']: expiration = dateutil.parser.parse( credentials['Expiration']) expiration = expiration.replace(tzinfo=None) current = datetime.datetime.utcnow() if expiration < current: printInfo('Saved STS credentials expired on %s' % credentials['Expiration']) force_init = True else: force_init = True sts_credentials = credentials else: first_sts_session = True if force_init or (mfa_serial_arg and mfa_code): credentials = read_creds_from_aws_credentials_file( profile_name if first_sts_session else '%s-nomfa' % profile_name) if not credentials['AccessKeyId']: printInfo( 'Warning: Unable to determine STS token expiration; later API calls may fail.' ) credentials = sts_credentials else: if mfa_serial_arg: credentials['SerialNumber'] = mfa_serial_arg if mfa_code: credentials['TokenCode'] = mfa_code if 'AccessKeyId' in credentials and credentials[ 'AccessKeyId']: credentials = init_sts_session(profile_name, credentials) # If we don't have valid creds by now, print an error message if 'AccessKeyId' not in credentials or credentials[ 'AccessKeyId'] == None or 'SecretAccessKey' not in credentials or credentials[ 'SecretAccessKey'] == None: printError( 'Error: could not find AWS credentials. Use the --help option for more information.' ) if not 'AccessKeyId' in credentials: credentials = {'AccessKeyId': None} return credentials