Skip to content

Commit

Permalink
[DC] Adds IAM Connection Type to AWS Inventory (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
alldoami authored and sfc-gh-afedorov committed Oct 7, 2019
1 parent 84dd992 commit 6da0735
Showing 1 changed file with 109 additions and 4 deletions.
113 changes: 109 additions & 4 deletions src/connectors/aws_inventory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""AWS Asset Inventory
Collect AWS EC2, SG, ELB assets using an Access Key or privileged Role
Collect AWS EC2, SG, ELB, IAM assets using an Access Key or privileged Role
"""
from datetime import datetime
import json
Expand All @@ -20,6 +20,7 @@
{'value': 'EC2', 'label': "EC2 Inventory"},
{'value': 'SG', 'label': "SG Inventory"},
{'value': 'ELB', 'label': "ELB Inventory"},
{'value': 'IAM', 'label': "IAM Inventory"}
],
'name': 'connection_type',
'title': "Asset Type",
Expand Down Expand Up @@ -145,6 +146,18 @@
('region_name', 'STRING(16)'),
('scheme', 'STRING(30)'),
('vpc_id', 'STRING(30)')
],
# IAM Users
'IAM': [
('raw', 'VARCHAR'),
('ingested_at', 'TIMESTAMP_LTZ'),
('path', 'VARCHAR'),
('user_name', 'VARCHAR'),
('user_id', 'VARCHAR'),
('arn', 'VARCHAR'),
('create_date', 'TIMESTAMP_LTZ'),
('password_last_used', 'TIMESTAMP_LTZ'),
('account_id', 'STRING(32)')
]
}

Expand Down Expand Up @@ -186,15 +199,17 @@ def create_asset_table(connection_name, asset_type, columns, options):
return f"AWS {asset_type} asset ingestion table created!"


def ingest(table_name, options):
def ingest(table_name, options: dict):
landing_table = f'data.{table_name}'
connection_type = options['connection_type']

aws_access_key = options.get('aws_access_key')
aws_secret_key = options.get('aws_secret_key')
connection_type = options.get('connection_type')

source_role_arn = options.get('source_role_arn')
destination_role_name = options.get('destination_role_name')
external_id = options.get('external_id')
accounts_connection_name = options.get('accounts_connection_name')
accounts_connection_name = options.get('accounts_connection_name', '')

if not accounts_connection_name.startswith('data.'):
accounts_connection_name = 'data.' + accounts_connection_name
Expand All @@ -203,6 +218,7 @@ def ingest(table_name, options):
'EC2': ec2_dispatch,
'SG': sg_dispatch,
'ELB': elb_dispatch,
'IAM': iam_dispatch,
}[connection_type]

if source_role_arn and destination_role_name and external_id and accounts_connection_name:
Expand Down Expand Up @@ -232,6 +248,39 @@ def ingest(table_name, options):
log.error()


def iam_dispatch(landing_table, aws_access_key='', aws_secret_key='', accounts=None, source_role_arn='',
destination_role_name='', external_id=''):
results = 0
if accounts:
for account in accounts:
id = account['ACCOUNT_ID']
name = account['ACCOUNT_ALIAS']
target_role = f'arn:aws:iam::{id}:role/{destination_role_name}'
log.info(f"Using role {target_role}")
try:
session = sts_assume_role(source_role_arn, target_role, external_id)

results += ingest_iam(landing_table, session=session, account=account)

db.insert(
AWS_ACCOUNTS_METADATA,
values=[(datetime.utcnow(), RUN_ID, id, name, results)],
columns=['snapshot_at', 'run_id', 'account_id', 'account_alias', 'iam_count']
)

except Exception as e:
db.insert(
AWS_ACCOUNTS_METADATA,
values=[(datetime.utcnow(), RUN_ID, id, name, 0, e)],
columns=['snapshot_at', 'run_id', 'account_id', 'account_alias', 'iam_count', 'error']
)
log.error(f"Unable to assume role {target_role} with error", e)
else:
results += ingest_iam(landing_table, aws_access_key=aws_access_key, aws_secret_key=aws_secret_key)

return results


def ec2_dispatch(landing_table, aws_access_key='', aws_secret_key='', accounts=None, source_role_arn='',
destination_role_name='', external_id=''):
results = 0
Expand Down Expand Up @@ -327,6 +376,37 @@ def elb_dispatch(landing_table, aws_access_key='', aws_secret_key='', accounts=N
return results


def ingest_iam(landing_table, aws_access_key=None, aws_secret_key=None, session=None, account=None):
users = get_iam_users(
aws_access_key=aws_access_key,
aws_secret_key=aws_secret_key,
session=session,
account=account
)

monitor_time = datetime.utcnow().isoformat()

db.insert(
landing_table,
values=[(
row,
monitor_time,
row['Path'],
row['UserName'],
row['UserId'],
row.get('Arn'),
row['CreateDate'],
row.get('PasswordLastUsed'),
row.get('Account'))
for row in users
],
select=db.derive_insert_select(LANDING_TABLES_COLUMNS['IAM']),
columns=db.derive_insert_columns(LANDING_TABLES_COLUMNS['IAM'])
)

return len(users)


def ingest_ec2(landing_table, aws_access_key=None, aws_secret_key=None, session=None, account=None):
instances = get_ec2_instances(
aws_access_key=aws_access_key,
Expand Down Expand Up @@ -406,6 +486,31 @@ def ingest_elb(landing_table, aws_access_key=None, aws_secret_key=None, session=
return len(elbs)


def get_iam_users(aws_access_key=None, aws_secret_key=None, session=None, account=None):
log.info(f"Searching for iam users.")

# get list of all users
if session:
client = session.client('iam', region_name=REGION)
else:
client = boto3.client('iam', aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key,
region_name=REGION)
paginator = client.get_paginator('list_users')
page_iterator = paginator.paginate()
results = [
user
for page in page_iterator
for user in page['Users']
]

for user in results:
if account:
user['Account'] = account

# return list of users
return results


def get_ec2_instances(aws_access_key=None, aws_secret_key=None, session=None, account=None):
client = boto3.client(
'ec2',
Expand Down

0 comments on commit 6da0735

Please sign in to comment.