Example #1
0
 def __init__(self, account_id):
     self.session = boto3.Session()
     self.iam = BotoFactory().get_capability(boto3.resource,
                                             self.session,
                                             'iam',
                                             account_id=account_id)
     self.interesting_roles = None
     self.users_w_used_passwords = None
Example #2
0
def main(event, context):
    """ Updates the metadata DynamoDB table with Organizations as source of truth,
    Must have an existing table to run (from .env)
    If there is no table, run make_table.py
    """
    if event.get('profile_name'):
        session = boto3.Session(profile_name=event.get('profile_name'))
    else:
        session = boto3.Session()

    # check if DDB table exists, if not create it
    ddb_r = BotoFactory().get_capability(boto3.resource, session, 'dynamodb')
    table = ddb_r.Table(os.environ['TABLE_NAME'])

    try:
        table.creation_date_time
    except ddb_r.meta.client.exceptions.ResourceNotFoundException:
        logging.error('Table does not exist, creating')
        logging.info(DynamoDBOps().make_metadata_table(
            ddb_r.meta.client, os.environ['TABLE_NAME']))
        table.wait_until_exists()
        logging.info(f"Table created: {table.creation_date_time}")

    # create dictionary of all ACTIVE organization accounts
    accounts = AccountOps().get_accounts(session)

    ddb = BotoFactory().get_capability(boto3.client, session, 'dynamodb')
    # update dynamoDB with account information
    DynamoDBOps().populate_baseline_metadata(ddb, os.environ['TABLE_NAME'],
                                             accounts)

    # make roleswitch URLs
    for id in accounts:
        DynamoDBOps().add_roleswitch_url(ddb, os.environ['TABLE_NAME'], id,
                                         __make_roleswitch_url(accounts[id]))

    # make HTML file
    column_order = ['AccountId', 'Name', 'RoleSwitchURL']
    local_path = f"/tmp/{os.environ['DEFAULT_FILENAME']}"
    logging.info(
        DDBToHTML(session).make_html_file(column_order=column_order,
                                          filename=local_path))

    # put in S3, get pre-signed URL
    object_name = 'metadata.html'
    S3Ops(session).put_html_file(local_path, os.environ['HTML_BUCKET'],
                                 object_name)
    url = S3Ops(session).create_presigned_url(os.environ['S3_READONLY_ROLE'],
                                              os.environ['HTML_BUCKET'],
                                              object_name)

    response = {'success': True, 'url': url}

    return {'statusCode': 200, 'body': json.dumps(response)}
Example #3
0
    def get_accounts(self, session):

        org = BotoFactory().get_capability(boto3.client, session,
                                           'organizations')
        accounts = dict()
        paginator = org.get_paginator('list_accounts')
        itr = paginator.paginate()
        for i in itr:
            for account in i['Accounts']:
                accounts[account['Id']] = account

        return accounts
Example #4
0
 def check_acount_for_billing_access(self, session, account_id):
     costexplorer = BotoFactory().get_capability(boto3.client,
                                                 session,
                                                 'ce',
                                                 account_id=account_id)
     response = costexplorer.get_cost_and_usage(TimePeriod={
         'Start': '2019-08-01',
         'End': '2019-09-01'
     },
                                                Granularity='MONTHLY',
                                                Metrics=['BlendedCost'])
     return response
Example #5
0
 def get_cost_timespan(self, start, end):
     ce = BotoFactory().get_capability(
         boto3.client, self.session, 'ce', self.account_id
     )
     return ce.get_cost_and_usage(
         TimePeriod={
             'Start': start,
             'End': end
         },
         Granularity='MONTHLY',
         Metrics=['UnblendedCost']
     )['ResultsByTime']
Example #6
0
    def __init__(self, session):
        if os.environ.get('EXCLUDE_OUS'):
            self.blocklist = os.environ.get('EXCLUDE_OUS').split(',')
            log.info(f"Exclude OU:s: {self.blocklist}")
        else:
            log.warn(
                f"No EXCLUDE_OUS present in ENV, all OUs can be traversed"
            )
            self.blocklist = set()

        self.org = BotoFactory().get_capability(
            boto3.client, session, 'organizations'
        )
Example #7
0
 def __get_client(self, rolename=''):
     if rolename == '':
         rolename = os.environ['DEFAULT_ROLE']
     return BotoFactory().get_capability(boto3.client,
                                         self.session,
                                         's3',
                                         rolename=rolename)
Example #8
0
def main(fqdn, source, target, profile='', verify=''):
    if (fqdn or source or target) is None:
        print("Missing parameters, use --help")
        sys.exit(1)
    if profile == '':
        profile = 'default'

    # FQDN must end with ., add if missing
    if not fqdn.endswith('.'):
        fqdn = fqdn + '.'

    # make Route53 resources
    r53ops = Route53Ops(fqdn)
    session = boto3.Session(profile_name=profile)

    r53_source = BotoFactory().get_capability(
        boto3.client, session, 'route53', account_id=source
    )
    r53_target = BotoFactory().get_capability(
        boto3.client, session, 'route53', account_id=target
    )
    try:
        source_records = r53ops.get_all_records_from_hosted_zone(r53_source)
    except AttributeError as e:
        sys.stdout.write(f"{fqdn} doesn't appear to exist in {source}")
        sys.exit(1)

    # if not verify, run put
    if verify != 'true':
        r53ops.put_records(r53_target, source_records)

    # if verify, then only run verify and skip put
    try:
        target_records = r53ops.get_all_records_from_hosted_zone(r53_target)
    except AttributeError as e:
        sys.stdout.write(f"{fqdn} doesn't appear to exist in {target}")
        sys.exit(1)


    __json_print(check_records_similarity(
        fqdn, source_records, target_records
    ))
Example #9
0
 def check_account_for_roles(self, session, account_id, roles):
     for r in roles:
         try:
             BotoFactory().get_capability(boto3.client,
                                          session,
                                          'sts',
                                          account_id,
                                          rolename=r)
             roles[r] = True
         except ClientError as e:
             if e.response['Error']['Code'] == 'AccessDenied':
                 logging.info(f"{r} did not exist in {account_id}")
                 pass
     return roles
Example #10
0
class IAMOps():
    def __init__(self, account_id):
        self.session = boto3.Session()
        self.iam = BotoFactory().get_capability(boto3.resource,
                                                self.session,
                                                'iam',
                                                account_id=account_id)
        self.interesting_roles = None
        self.users_w_used_passwords = None

    def get_interesting_roles(self):
        # returns all Roles as iam.Role resource
        #  .all() method Roles don't include role_last_used attribute!!
        roles = self.iam.roles.all()
        interesting_roles = list()
        for r in roles:
            if '/aws-service-role/' in r.arn or r.name in whitelisted_roles:
                pass
            else:
                for p in r.assume_role_policy_document.get('Statement'):
                    if p.get('Principal').get('Service'):
                        pass
                    else:
                        log.debug(f"Appending to interesting roles: {r.arn}")
                        interesting_roles.append(r)
        self.interesting_roles = interesting_roles
        return interesting_roles

    def get_timestamped_roles(self):
        if not self.interesting_roles:
            self.interesting_roles = self.get_interesting_roles()
        timestamped_roles = list()
        for r in self.interesting_roles:
            role = self.iam.Role(r.name)
            if role.role_last_used:
                timestamped_roles.append(role)
        return timestamped_roles

    def get_iam_users_w_used_password(self):
        # returns all users as iam.User resource
        self.users_w_used_passwords = [
            user for user in self.iam.users.all() if user.password_last_used
        ]
        return self.users_w_used_passwords
 def __init__(self, session):
     self.ddb = BotoFactory().get_capability(boto3.client, session,
                                             'dynamodb')
class DDBToHTML():
    def __init__(self, session):
        self.ddb = BotoFactory().get_capability(boto3.client, session,
                                                'dynamodb')

    def table_to_list(self):
        paginator = self.ddb.get_paginator('scan')
        itr = paginator.paginate(TableName=os.environ['TABLE_NAME'],
                                 Select='ALL_ATTRIBUTES')
        all_items = list()
        for i in itr:
            all_items = i['Items'] + all_items

        return all_items

    def get_all_attributes(self, list_ddb_items):
        """expects a list of dictionaries where each dictionary is a single item
        from DynamoDB"""
        attributes = set()
        for i in list_ddb_items:
            attributes = attributes.union(i.keys())
        return attributes

    def make_order_of_columns(self, attributes, desired_order_list):
        """takes input of attributes set and a partial or complete list of
        attributes in the desired order for the columns, e.g. should AccountId
        be first column
        then
            desired_order_list=['AccountId']
        If the desired order has fewer items than the attributes they will be
        added randomly depending on the order of the set returns list of order
        which can be used for HTML table generation
        """
        order_list = list()
        for attr in desired_order_list:
            try:
                attributes.remove(attr)
                order_list.append(attr)
            except Exception as e:
                raise (e)

        if len(attributes) > 0:
            for i in range(len(attributes)):
                order_list.append(attributes.pop())

        return order_list

    def make_table_head(self, ordered_list):
        thead = '<thead>\n\t\t\t<tr>\n'
        th_row = '\t\t\t\t<th>\n\t\t\t\t\t<p>%s\n\t\t\t\t</th>\n'
        for i in range(len(ordered_list)):
            thead += th_row % ordered_list[i]
        thead += '\t\t\t</tr>\n\t\t</thead>\n'
        return thead

    def make_table_row(self, ordered_list, account_info):
        tr = '\t\t<tr>\n'
        tr_td = "\t\t\t<td>\n\t\t\t\t<p>%s\n\t\t\t</td>\n"
        for i in range(len(ordered_list)):
            data = account_info.get(ordered_list[i])['S']
            if data.startswith('https://'):
                data = "<a href=\"%s\" target=_blank>%s</a>" % (data, data)
            tr += tr_td % data
        tr += '\t\t</tr>\n'
        return tr

    def make_html_file(self, column_order='', filename=''):
        if column_order == '':
            self.logging.warning('No column order specified')
            column_order = []
        if filename == '':
            filename = os.environ['DEFAULT_FILENAME']

        items = self.table_to_list()
        attributes = self.get_all_attributes(items)

        ordered_list = self.make_order_of_columns(attributes, column_order)

        thead = self.make_table_head(ordered_list)
        html_rows = str()
        for item in items:
            html_rows += self.make_table_row(ordered_list, item)

        params = {
            'TITLE': 'Account Roleswitching and Metadata',
            'THEAD_VALS': thead,
            'TR_VALS': html_rows
        }

        with open('html_templating/table_template.html', 'r') as f:
            template = f.read()

        path = filename
        with open(path, 'w') as out:
            out.write(template % params)
        return ({'Status': 'OK', 'Path': path})
Example #13
0
class OrgOps():

    def __init__(self, session):
        if os.environ.get('EXCLUDE_OUS'):
            self.blocklist = os.environ.get('EXCLUDE_OUS').split(',')
            log.info(f"Exclude OU:s: {self.blocklist}")
        else:
            log.warn(
                f"No EXCLUDE_OUS present in ENV, all OUs can be traversed"
            )
            self.blocklist = set()

        self.org = BotoFactory().get_capability(
            boto3.client, session, 'organizations'
        )

    def get_active_accounts(self):
        accounts = dict()
        paginator = self.org.get_paginator('list_accounts')
        itr = paginator.paginate()
        for i in itr:
            for account in i['Accounts']:
                if account['Status'] == 'ACTIVE':
                    accounts[account['Id']] = account
        return accounts

    def get_all_children_ou(self, parent_ou):
        ous = set()
        log.info(f"Getting children OU for {parent_ou}")
        pgnt = self.org.get_paginator('list_organizational_units_for_parent')
        itr = pgnt.paginate(
            ParentId=parent_ou
        )

        for i in itr:
            for ou in i['OrganizationalUnits']:
                if ou['Id'] not in self.blocklist:
                    ous.add(ou['Id'])

        if ous:
            for ou in ous.copy():
                ous.update(self.get_all_children_ou(ou))

        return ous

    def get_active_accounts_from_ous(self, ous):
        pgnt = self.org.get_paginator('list_accounts_for_parent')
        accounts = dict()
        for ou in ous:
            log.info(f"Getting accounts from {ou}")
            itr = pgnt.paginate(ParentId=ou)
            for i in itr:
                for account in i['Accounts']:
                    if account['Status'] == 'ACTIVE':
                        accounts[account['Id']] = account
        return accounts

    def get_accounts_from_root(self):
        root_ou = self.org.list_roots()['Roots'][0]['Id']
        return self.get_active_accounts_from_ous(
            self.get_all_children_ou(root_ou)
        )