Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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']
Ejemplo n.º 3
0
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