def get_connections(account_id, region, connections=None): logging.info('Getting connections for {} {}..'.format(account_id, region)) sts = boto3.client('sts') response = sts.assume_role(RoleArn='arn:aws:iam::' + account_id + ':role/fullstop', RoleSessionName='fullstop', DurationSeconds=900) session = boto3.Session( aws_access_key_id=response['Credentials']['AccessKeyId'], aws_secret_access_key=response['Credentials']['SecretAccessKey'], aws_session_token=response['Credentials']['SessionToken'], region_name=region) ec2_client = session.client('ec2') rds = session.client('rds') instance_ids = [] interfaces = {} logging.info('%s: Collecting network interfaces..', account_id) res = ec2_client.describe_network_interfaces() lb_names = [] for iface in res['NetworkInterfaces']: if 'Association' in iface: # public IP involved interfaces[iface['NetworkInterfaceId']] = iface descr = iface.get('Description') if descr.startswith('ELB'): words = descr.split() lb_names.append(words[-1]) if 'Attachment' in iface and 'InstanceId' in iface['Attachment']: instance_ids.append(iface['Attachment']['InstanceId']) lb_dns_names = get_lb_dns_names(session, lb_names) res = rds.describe_db_instances() for db in res['DBInstances']: if db['PubliclyAccessible']: host, port = (db['Endpoint']['Address'], db['Endpoint']['Port']) try: ai = socket.getaddrinfo(host, port, family=socket.AF_INET, socktype=socket.SOCK_STREAM) except: ai = [] for _, _, _, _, ip_port in ai: ip, _ = ip_port NAMES[ip] = '/'.join((account_id, region, host)) local_names = {} instance_count = 0 logging.info('%s: Collecting public EC2 instances..', account_id) res = ec2_client.describe_instances(InstanceIds=instance_ids) for reservation in res['Reservations']: for inst in reservation['Instances']: instance_count += 1 if 'PrivateIpAddress' in inst and 'Tags' in inst: name = ''.join( [x['Value'] for x in inst['Tags'] if x['Key'] == 'Name']) local_names[inst['PrivateIpAddress']] = '/'.join( (name, inst.get('PublicIpAddress', ''))) logging.info( '%s: Got {} interfaces, {} load balancers and {} instances'.format( len(interfaces), len(lb_dns_names), instance_count), account_id) connections = collections.Counter() if connections is None else connections now = datetime.datetime.utcnow() start_time = LAST_TIMES.get(account_id, now - datetime.timedelta(minutes=10)) reader = FlowLogsReader('vpc-flowgroup', region_name=region, start_time=start_time, end_time=now) reader.logs_client = session.client('logs') record_count = 0 new_connections = 0 for record in reader: # just consider accepted packets if record.action == 'ACCEPT': record_count += 1 src = ipaddress.ip_address(record.srcaddr) # only look at packets received at public interfaces if record.interface_id in interfaces and not src.is_private: name = get_name(record.srcaddr) dest = interfaces.get(record.interface_id, {}).get('Description') if not dest or dest.startswith('Primary'): # EC2 instance if record.srcaddr in AWS_IPS and AWS_S3_DOMAIN_PATTERN.match( name.split('/')[0]): # ignore S3 public IPs # (most probably packets from S3 to public EC2) continue dest = local_names.get(record.dstaddr, record.dstaddr) elif dest.startswith('ELB'): # ELB words = dest.split() dest = lb_dns_names.get(words[-1], dest) elif dest.startswith('RDS'): # RDS instance public_ip = interfaces.get(record.interface_id, {}).get('Association', {}).get('PublicIp', '') dest = NAMES.get(public_ip, 'RDS/' + public_ip) elif dest: dest += '/' + interfaces.get(record.interface_id, {}).get( 'Association', {}).get('PublicIp', '') if 'NAT' not in dest and 'Odd' not in dest: conn = (name, dest, record.dstport) if conn not in connections: new_connections += 1 connections[conn] += 1 logging.info( '%s: Got {} records and {} new connections'.format( record_count, new_connections), account_id) LAST_TIMES[account_id] = now return connections
def get_connections(account_id, region, connections=None): logging.info('Getting connections for {} {}..'.format(account_id, region)) sts = boto3.client('sts') response = sts.assume_role(RoleArn='arn:aws:iam::' + account_id + ':role/fullstop', RoleSessionName='fullstop', DurationSeconds=900) session = boto3.Session(aws_access_key_id=response['Credentials']['AccessKeyId'], aws_secret_access_key=response['Credentials']['SecretAccessKey'], aws_session_token=response['Credentials']['SessionToken'], region_name=region) ec2_client = session.client('ec2') rds = session.client('rds') instance_ids = [] interfaces = {} logging.info('%s: Collecting network interfaces..', account_id) res = ec2_client.describe_network_interfaces() lb_names = [] for iface in res['NetworkInterfaces']: if 'Association' in iface: # public IP involved interfaces[iface['NetworkInterfaceId']] = iface descr = iface.get('Description') if descr.startswith('ELB'): words = descr.split() lb_names.append(words[-1]) if 'Attachment' in iface and 'InstanceId' in iface['Attachment']: instance_ids.append(iface['Attachment']['InstanceId']) lb_dns_names = get_lb_dns_names(session, lb_names) res = rds.describe_db_instances() for db in res['DBInstances']: if db['PubliclyAccessible']: host, port = (db['Endpoint']['Address'], db['Endpoint']['Port']) try: ai = socket.getaddrinfo(host, port, family=socket.AF_INET, socktype=socket.SOCK_STREAM) except: ai = [] for _, _, _, _, ip_port in ai: ip, _ = ip_port NAMES[ip] = '/'.join((account_id, region, host)) local_names = {} instance_count = 0 logging.info('%s: Collecting public EC2 instances..', account_id) res = ec2_client.describe_instances(InstanceIds=instance_ids) for reservation in res['Reservations']: for inst in reservation['Instances']: instance_count += 1 if 'PrivateIpAddress' in inst and 'Tags' in inst: name = ''.join([x['Value'] for x in inst['Tags'] if x['Key'] == 'Name']) local_names[inst['PrivateIpAddress']] = '/'.join((name, inst.get('PublicIpAddress', ''))) logging.info('%s: Got {} interfaces, {} load balancers and {} instances'.format( len(interfaces), len(lb_dns_names), instance_count), account_id) connections = collections.Counter() if connections is None else connections now = datetime.datetime.utcnow() start_time = LAST_TIMES.get(account_id, now - datetime.timedelta(minutes=10)) reader = FlowLogsReader('vpc-flowgroup', region_name=region, start_time=start_time, end_time=now) reader.logs_client = session.client('logs') record_count = 0 new_connections = 0 for record in reader: # just consider accepted packets if record.action == 'ACCEPT': record_count += 1 src = ipaddress.ip_address(record.srcaddr) # only look at packets received at public interfaces if record.interface_id in interfaces and not src.is_private: name = get_name(record.srcaddr) dest = interfaces.get(record.interface_id, {}).get('Description') if not dest or dest.startswith('Primary'): # EC2 instance if record.srcaddr in AWS_IPS and AWS_S3_DOMAIN_PATTERN.match(name.split('/')[0]): # ignore S3 public IPs # (most probably packets from S3 to public EC2) continue dest = local_names.get(record.dstaddr, record.dstaddr) elif dest.startswith('ELB'): # ELB words = dest.split() dest = lb_dns_names.get(words[-1], dest) elif dest.startswith('RDS'): # RDS instance public_ip = interfaces.get(record.interface_id, {}).get('Association', {}).get('PublicIp', '') dest = NAMES.get(public_ip, 'RDS/' + public_ip) elif dest: dest += '/' + interfaces.get(record.interface_id, {}).get('Association', {}).get('PublicIp', '') if 'NAT' not in dest and 'Odd' not in dest: conn = (name, dest, record.dstport) if conn not in connections: new_connections += 1 connections[conn] += 1 logging.info('%s: Got {} records and {} new connections'.format(record_count, new_connections), account_id) LAST_TIMES[account_id] = now return connections