Esempio n. 1
0
def boto3_session(service, region=DEFAULT_REGION, profile=None):
    """
    Summary:
        Establishes boto3 sessions, client
    Args:
        :service (str): boto3 service abbreviation ('ec2', 's3', etc)
        :profile (str): profile_name of an iam user from local awscli config
    Returns:
        TYPE: boto3 client object
    """
    try:

        if profile and profile != 'default':
            session = boto3.Session(profile_name=profile)
            return session.client(service, region_name=region)

    except ClientError as e:
        logger.exception(
            "%s: IAM user or role not found (Code: %s Message: %s)" %
            (inspect.stack()[0][3], e.response['Error']['Code'],
             e.response['Error']['Message']))
        raise
    except ProfileNotFound:
        msg = ('%s: The profile (%s) was not found in your local config' %
               (inspect.stack()[0][3], profile))
        stdout_message(msg, 'FAIL')
        logger.warning(msg)
    return boto3.client(service, region_name=region)
Esempio n. 2
0
def stopped_instances(region, profile=None, ids=False, debug=False):
    """
    Summary.
        Determines state of all ec2 machines in a region

    Returns:
        :stopped ec2 instances, TYPE: ec2 objects
            OR
        :stopped ec2 instance ids, TYPE: str

    """
    try:
        if profile and profile != 'default':
            session = boto3.Session(profile_name=profile)
            ec2 = session.resource('ec2', region_name=region)
        else:
            ec2 = boto3.resource('ec2', region_name=region)

        instances = ec2.instances.all()

        if ids:
            return [x.id for x in instances if x.state['Name'] == 'stopped']

    except ClientError as e:
        logger.exception(
            "%s: IAM user or role not found (Code: %s Message: %s)" %
            (inspect.stack()[0][3], e.response['Error']['Code'],
             e.response['Error']['Message']))
        raise
    except ProfileNotFound:
        msg = ('%s: The profile (%s) was not found in your local config' %
               (inspect.stack()[0][3], profile))
        stdout_message(msg, 'FAIL')
        logger.warning(msg)
    return [x for x in instances if x.state['Name'] == 'stopped']
Esempio n. 3
0
def log_message(label, msg):
    """ logs all messages sent to stdout """

    if label in critical_status:
        logger.critical(msg)

    elif label in warning_status:
        logger.warning(msg)

    else:
        logger.info(msg)
    return True
Esempio n. 4
0
def init_cli():
    # parser = argparse.ArgumentParser(add_help=False, usage=help_menu())
    parser = argparse.ArgumentParser(add_help=False)

    try:
        args = options(parser)
    except Exception as e:
        help_menu()
        stdout_message(str(e), 'ERROR')
        sys.exit(exit_codes['EX_OK']['Code'])

    if len(sys.argv) == 1:
        help_menu()
        sys.exit(exit_codes['EX_OK']['Code'])

    elif args.help:
        help_menu()
        sys.exit(exit_codes['EX_OK']['Code'])

    elif args.version:
        package_version()

    elif args.configure:
        r = option_configure(args.debug,
                             local_config['PROJECT']['CONFIG_PATH'])
        return r
    else:
        if precheck():  # if prereqs set, run
            if authenticated(profile=args.profile):
                # execute keyset operation
                success = main(operation=args.operation,
                               profile=args.profile,
                               user_name=args.username,
                               auto=args.auto,
                               debug=args.debug)
                if success:
                    logger.info('IAM access keyset operation complete')
                    sys.exit(exit_codes['EX_OK']['Code'])
            else:
                stdout_message(
                    'Authenication Failed to AWS Account for user %s' %
                    args.profile,
                    prefix='AUTH',
                    severity='WARNING')
                sys.exit(exit_codes['E_AUTHFAIL']['Code'])

    failure = """ : Check of runtime parameters failed for unknown reason.
    Please ensure local awscli is configured. Then run keyconfig to
    configure keyup runtime parameters.   Exiting. Code: """
    logger.warning(failure +
                   'Exit. Code: %s' % sys.exit(exit_codes['E_MISC']['Code']))
    print(failure)
Esempio n. 5
0
def boto3_session(service, region=DEFAULT_REGION, profile=None):
    """
    Summary:
        Establishes boto3 sessions, client
    Args:
        :service (str): boto3 service abbreviation ('ec2', 's3', etc)
        :profile (str): profile_name of an iam user from local awscli config
        :region (str):  AWS region code, optional

    Returns:
        client (boto3 object)

    """
    fx = inspect.stack()[0][3]

    try:

        if (not profile or profile == 'default') and service != 'iam':
            return boto3.client(service, region_name=region)

        elif (not profile or profile == 'default') and service == 'iam':
            return boto3.client(service)

        elif profile and profile != 'default':
            session = boto3.Session(profile_name=profile)
            return session.client(service, region_name=region)

    except ClientError as e:
        if e.response['Error']['Code'] == 'InvalidClientTokenId':
            logger.warning(
                '{}: Invalid credentials used by profile user {}'.format(
                    fx, profile or 'default'))

        elif e.response['Error']['Code'] == 'ExpiredToken':
            logger.info(
                '%s: Expired temporary credentials detected for profile user (%s) [Code: %d]'
                % (fx, profile, exit_codes['EX_CONFIG']['Code']))

    except ProfileNotFound:
        msg = (
            '{}: Profile name {} was not found in your local config.'.format(
                fx, profile))
        stdout_message(msg, 'WARN')
        logger.warning(msg)
        return None
    return boto3.client(service, region_name=region)
Esempio n. 6
0
def get_account_info(account_profile=None):
    """
    Summary.

        Queries AWS iam and sts services to discover account id information
        in the form of account name and account alias (if assigned)

    Returns:
        TYPE: tuple

    Example usage:

    >>> account_number, account_name = lambda_utils.get_account_info()
    >>> print(account_number, account_name)
    103562488773 tooling-prod

    """
    if account_profile:
        session = boto3.Session(profile_name=account_profile)
        sts_client = session.client('sts')
        iam_client = session.client('iam')
    else:
        sts_client = boto3.client('sts')
        iam_client = boto3.client('iam')

    try:
        number = sts_client.get_caller_identity()['Account']
        name = iam_client.list_account_aliases()['AccountAliases'][0]

    except IndexError as e:
        name = '<no_alias_assigned>'
        logger.info(
            'Error: %s. No account alias defined. account_name set to %s' %
            (e, name))
        return (number, name)
    except ClientError as e:
        logger.warning(
            "%s: problem retrieving caller identity (Code: %s Message: %s)" %
            (inspect.stack()[0][3], e.response['Error']['Code'],
             e.response['Error']['Message']))
        raise e
    return (number, name)
Esempio n. 7
0
def delete_tags(resourceIds, region, tags):
    """ Removes tags from an EC2 resource """
    client = boto3_session('ec2', region)
    try:
        for resourceid in resourceIds:
            response = client.delete_tags(
                Resources=[resourceid],
                Tags=tags
            )
            if response['ResponseMetadata']['HTTPStatusCode'] == 200:
                logger.info('Existing Tags deleted from vol id %s' % resourceid)
                return True
            else:
                logger.warning('Problem deleting existing tags from vol id %s' % resourceid)
                return False
    except ClientError as e:
        logger.critical(
            "%s: Problem apply tags to ec2 instances (Code: %s Message: %s)" %
            (inspect.stack()[0][3], e.response['Error']['Code'], e.response['Error']['Message']))
        return False
Esempio n. 8
0
def export_json_object(dict_obj, filename=None, logging=True):
    """
    Summary:
        exports object to block filesystem object

    Args:
        :dict_obj (dict): dictionary object
        :filename (str):  name of file to be exported (optional)

    Returns:
        True | False Boolean export status

    """
    try:
        if filename:
            try:
                with open(filename, 'w') as handle:
                    handle.write(json.dumps(dict_obj, indent=4, sort_keys=True))
                    logger.info(
                        '%s: Wrote %s to local filesystem location' %
                        (inspect.stack()[0][3], filename))
                handle.close()
            except TypeError as e:
                logger.warning(
                    '%s: object in dict not serializable: %s' %
                    (inspect.stack()[0][3], str(e)))
        else:
            json_str = json.dumps(dict_obj, indent=4, sort_keys=True)
            print(highlight(json_str, lexers.JsonLexer(), formatters.TerminalFormatter()).strip())
            if logging:
                logger.info('%s: successful export to stdout' % inspect.stack()[0][3])
            return True
    except OSError as e:
        logger.critical(
            '%s: export_file_object: error writing to %s to filesystem. Error: %s' %
            (inspect.stack()[0][3], filename, str(e)))
        return False
    if logging:
        logger.info('export_file_object: successful export to %s' % filename)
    return True
Esempio n. 9
0
def authenticated(profile):
    """
        Tests generic authentication status to AWS Account

    Args:
        :profile (str): iam user name from local awscli configuration

    Returns:
        TYPE: bool, True (Authenticated)| False (Unauthenticated)

    """
    try:
        sts_client = boto3_session(service='sts', profile=profile)
        httpstatus = sts_client.get_caller_identity(
        )['ResponseMetadata']['HTTPStatusCode']
        if httpstatus == 200:
            return True

    except ClientError as e:
        if e.response['Error']['Code'] == 'InvalidClientTokenId':
            logger.warning(
                '%s: Invalid credentials to authenticate for profile user (%s). Exit. [Code: %d]'
                % (inspect.stack()[0][3], profile,
                   exit_codes['EX_NOPERM']['Code']))

        elif e.response['Error']['Code'] == 'ExpiredToken':
            logger.info(
                '%s: Expired temporary credentials detected for profile user (%s) [Code: %d]'
                % (inspect.stack()[0][3], profile,
                   exit_codes['EX_CONFIG']['Code']))

        else:
            logger.exception(
                '%s: Unknown Boto3 problem. Error: %s' %
                (inspect.stack()[0][3], e.response['Error']['Message']))
    except Exception as e:
        fx = inspect.stack()[0][3]
        logger.exception('{}: Unknown error: {}'.format(fx, e))
        return False
    return False
Esempio n. 10
0
File: env.py Progetto: fstab50/pyaws
def read_env_variable(arg, default=None, patterns=None):
    """
    Summary.

        Parse environment variables, validate characters, convert
        type(s). default should be used to avoid conversion of an
        variable and retain string type

    Usage:
        >>> from lambda_utils import read_env_variable
        >>> os.environ['DBUGMODE'] = 'True'
        >>> myvar = read_env_variable('DBUGMODE')
        >>> type(myvar)
        True

        >>> from lambda_utils import read_env_variable
        >>> os.environ['MYVAR'] = '1345'
        >>> myvar = read_env_variable('MYVAR', 'default')
        >>> type(myvar)
        str

    Args:
        :arg (str):  Environment variable name (external name)
        :default (str): Default if no variable found in the environment under
            name in arg parameter
        :patterns (None):  Unused; not user callable. Used preservation of the
            patterns tuple between calls during runtime

    Returns:
        environment variable value, TYPE str

    """
    if patterns is None:
        patterns = (
            (re.compile('^[-+]?[0-9]+$'), int),
            (re.compile('\d+\.\d+'), float),
            (re.compile(r'^(true|false)$',
                        flags=re.IGNORECASE), lambda x: x.lower() == 'true'),
            (re.compile('[a-z/]+', flags=re.IGNORECASE), str),
            (re.compile('[a-z/]+\.[a-z/]+', flags=re.IGNORECASE), str),
        )

    if arg in os.environ:
        var = os.environ[arg]
        if var is None:
            ex = KeyError('environment variable %s not set' % arg)
            logger.exception(ex)
            raise ex
        else:
            if default:
                return str(var)  # force default type (str)
            else:
                for pattern, func in patterns:
                    if pattern.match(var):
                        return func(var)
            # type not identified
            logger.warning(
                '%s: failed to identify environment variable [%s] type. May contain \
                special characters' % (inspect.stack()[0][3], arg))
            return str(var)
    else:
        ex = KeyError('environment variable %s not set' % arg)
        logger.exception(ex)
        raise ex
Esempio n. 11
0
def main():
    """ copies ec2 instance tags to attached resources """
    for profile in profiles:
        # derive account alias from profile
        account = '-'.join(profile.split('-')[1:])
        for region in regions:
            #instances = []
            session = boto3.Session(profile_name=profile, region_name=region)
            client = session.client('ec2')
            ec2 = session.resource('ec2')
            instances = get_instances(profile, region)
            volumes = get_volumes(profile, region)
            # print summary
            if SUMMARY_REPORT:
                print('\nFor AWS Account %s, region %s, Found %d Instances\n' %
                      (account, region, len(instances)))
                continue
            # copy tags
            if instances:
                try:
                    base = ec2.instances.filter(InstanceIds=instances)
                    ct = 0
                    for instance in base:
                        ids, after_tags = [], []
                        ct += 1
                        if instance.tags:
                            # filter out tags to prohibited from copy
                            filtered_tags = filter_tags(
                                instance.tags, *NO_COPY_LIST)
                        else:
                            # no tags on instance to copy
                            continue

                        if not valid_tags(filtered_tags):
                            print('\nWARNING:')
                            logger.warning(
                                'Skipping instance ID %s, Invalid Tags\n' %
                                instance.id)
                            continue
                        # collect attached resource ids to be tagged
                        for vol in instance.volumes.all():
                            ids.append(vol.id)
                        for eni in instance.network_interfaces:
                            ids.append(eni.id)
                        logger.info('InstanceID %s, instance %d of %d:' %
                                    (instance.id, ct, len(instances)))
                        logger.info('Resource Ids to tag is:')
                        logger.info(str(ids) + '\n')
                        if DEBUGMODE:
                            # BEFORE tag copy
                            logger.info('BEFORE list of %d tags is:' %
                                        (len(instance.tags)))
                            pretty_print_tags(instance.tags)

                            # AFTER tag copy | put Name tag back into apply tags, ie, after_tags
                            retain_tags = select_tags(instance.tags,
                                                      PRESERVE_TAGS)
                            for tag in (*retain_tags, *filtered_tags):
                                after_tags.append(tag)
                            logger.info(
                                'For InstanceID %s, the AFTER FILTERING list of %d tags is:'
                                % (instance.id, len(after_tags)))
                            logger.info('Tags to apply are:')
                            pretty_print_tags(after_tags)
                        else:
                            logger.info('InstanceID %s, instance %d of %d:' %
                                        (instance.id, ct, len(instances)))
                            if filtered_tags:  # we must have something to apply
                                # apply tags
                                for resourceId in ids:
                                    # retain a copy of tags to preserve if is a volume
                                    if resourceId.startswith('vol-'):
                                        r = client.describe_tags(Filters=[
                                            {
                                                'Name': 'resource-id',
                                                'Values': [resourceId],
                                            },
                                        ])
                                        retain_tags = select_tags(
                                            r['Tags'], PRESERVE_TAGS)
                                        # add retained tags before appling to volume
                                        if retain_tags:
                                            for tag in retain_tags:
                                                filtered_tags.append(tag)
                                    # clear tags
                                    print('\n')
                                    logger.info(
                                        'Clearing tags on resource: %s' %
                                        str(resourceId))
                                    client.delete_tags(Resources=[resourceId],
                                                       Tags=[])

                                    # create new tags
                                    logger.info(
                                        'Applying tags to resource %s\n' %
                                        resourceId)
                                    ec2.create_tags(Resources=[resourceId],
                                                    Tags=filtered_tags)
                                    # delay to throttle API requests
                                    sleep(1)

                except ClientError as e:
                    logger.exception(
                        "%s: Problem (Code: %s Message: %s)" %
                        (inspect.stack()[0][3], e.response['Error']['Code'],
                         e.response['Error']['Message']))
                    raise