Beispiel #1
0
def authenticated(profile):
    """
    Summary:
        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.info(
                '%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:
        return False
    return False
Beispiel #2
0
def print_tags(resource_list, tag_list, mode=''):
    """
        - Prints tag keys, values applied to resources
        - output: cloudwatch logs
        - mode:  INFO, DBUG, or UNKN (unknown or not provided)
    """
    if mode == 0:
        mode_text = 'DBUG'
    else:
        mode_text = 'INFO'

    try:
        for resource in resource_list:
            logger.info('Tags successfully applied to resource: ' + str(resource))
            ct = 0
            for t in tag_list:
                logger.info('tag' + str(ct) + ': ' + str(t['Key']) + ' : ' + str(t['Value']))
                ct += 1
        if mode == 0:
            logger.debug('DBUGMODE = True, No tags applied')

    except Exception as e:
        logger.critical(
            "%s: problem printing tag keys or values to cw logs: %s" %
            (inspect.stack()[0][3], str(e)))
        return 1
    return 0
Beispiel #3
0
    def query_dynamodb(self, partition_key, key_value):
        """
        Queries DynamoDB table using partition key,
        returns the item matching key value
        """
        try:
            resource_dynamodb = self.boto_dynamodb_resource(self.region)
            table = resource_dynamodb.Table(self.tablename)
            logger.info('Table %s: Table Item Count is: %s' %
                        (table.table_name, table.item_count))

            # query on parition key
            response = table.query(
                KeyConditionExpression=Key(partition_key).eq(str(key_value)))
            if response['Items']:
                item = response['Items'][0]['Account Name']
            else:
                item = 'unIdentified'

        except ClientError as e:
            logger.exception(
                "Couldn\'t query DynamoDB table (Code: %s Message: %s)" %
                (e.response['Error']['Code'], e.response['Error']['Message']))
            return 1
        return item
Beispiel #4
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
Beispiel #5
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)
Beispiel #6
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)
Beispiel #7
0
    def scan_accounts(self, account_type):
        """
        Read method for DynamoDB table
        """

        accounts, account_ids = [], []
        valid_mpc_pkgs = [
            'B', 'RA-PKG-B', 'RA-PKG-C', 'P', 'ATA', 'BUP', 'DXA'
        ]

        types = [x.strip(' ') for x in account_type.split(',')]  # parse types

        try:
            resource_dynamodb = self.boto_dynamodb_resource(self.region)
            table = resource_dynamodb.Table(self.tablename)
            # scan table
            if set(types).issubset(set(valid_mpc_pkgs)):
                for type in types:
                    response = table.scan(
                        FilterExpression=Attr('MPCPackage').eq(type))
                    for account_dict in response['Items']:
                        accounts.append(account_dict)
            elif types[0] == 'All':
                # all valid_mpc_pkgs accounts (commercial accounts)
                response = table.scan(
                    FilterExpression=Attr('MPCPackage').ne("P"))
                for account_dict in response['Items']:
                    accounts.append(account_dict)

        except ClientError as e:
            logger.exception(
                "Couldn\'t scan DynamoDB table (Code: %s Message: %s)" %
                (e.response['Error']['Code'], e.response['Error']['Message']))
            return 1

        if accounts:
            for account in accounts:
                account_info = {}
                account_info['AccountName'] = account['Account Name']
                account_info['AccountId'] = account['Account ID']
                account_ids.append(account_info)
        else:
            logger.info('No items returned from DyanamoDB')
        return account_ids
Beispiel #8
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)
Beispiel #9
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
Beispiel #10
0
def json_tags(resource_list, tag_list, mode=''):
    """
        - Prints tag keys, values applied to resources
        - output: cloudwatch logs
        - mode:  INFO, DBUG, or UNKN (unknown or not provided)
    """
    if mode == 0:
        mode_text = 'DBUG'
    else:
        mode_text = 'INFO'

    try:
        for resource in resource_list:
            if mode == 0:
                logger.debug('DBUGMODE enabled - Print tags found on resource %s:' % str(resource))
            else:
                logger.info('Tags found resource %s:' % str(resource))
            print(json.dumps(tag_list, indent=4, sort_keys=True))
    except Exception as e:
        logger.critical(
            "%s: problem printing tag keys or values to cw logs: %s" %
            (inspect.stack()[0][3], str(e)))
        return False
    return True
Beispiel #11
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
Beispiel #12
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
Beispiel #13
0
                               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)


if __name__ == '__main__':
    start_time = datetime.datetime.now()
    main()
    end_time = datetime.datetime.now()
    duration, unit = calc_runtime(start_time, end_time)
    logger.info('Job Start: %s' % start_time.isoformat())
    logger.info('Job End: %s' % end_time.isoformat())
    logger.info('Job Completed. Duration: %d %s' % (duration, unit))
    sys.exit(0)