Example #1
0
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
Example #2
0
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