cartography 0.84.0__py3-none-any.whl → 0.85.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/data/indexes.cypher +0 -8
- cartography/data/jobs/analysis/aws_s3acl_analysis.json +7 -2
- cartography/intel/aws/ec2/instances.py +6 -6
- cartography/intel/aws/ec2/network_interfaces.py +186 -213
- cartography/intel/aws/ec2/security_groups.py +2 -2
- cartography/intel/aws/ec2/subnets.py +2 -2
- cartography/intel/aws/eks.py +46 -54
- cartography/intel/aws/inspector.py +44 -142
- cartography/intel/aws/s3.py +6 -1
- cartography/models/aws/ec2/loadbalancerv2.py +0 -0
- cartography/models/aws/ec2/networkinterface_instance.py +109 -0
- cartography/models/aws/ec2/networkinterfaces.py +36 -49
- cartography/models/aws/ec2/privateip_networkinterface.py +72 -0
- cartography/models/aws/ec2/{securitygroups.py → securitygroup_instance.py} +9 -6
- cartography/models/aws/ec2/securitygroup_networkinterface.py +52 -0
- cartography/models/aws/ec2/{subnets.py → subnet_instance.py} +7 -4
- cartography/models/aws/ec2/subnet_networkinterface.py +87 -0
- cartography/models/aws/eks/__init__.py +0 -0
- cartography/models/aws/eks/clusters.py +50 -0
- cartography/models/aws/inspector/__init__.py +0 -0
- cartography/models/aws/inspector/findings.py +124 -0
- cartography/models/aws/inspector/packages.py +73 -0
- cartography/util.py +8 -0
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/METADATA +1 -1
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/RECORD +30 -23
- cartography/data/jobs/cleanup/aws_import_eks_cleanup.json +0 -15
- cartography/data/jobs/cleanup/aws_import_inspector_cleanup.json +0 -35
- cartography/data/jobs/cleanup/aws_ingest_network_interfaces_cleanup.json +0 -30
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/LICENSE +0 -0
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/NOTICE +0 -0
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/WHEEL +0 -0
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/entry_points.txt +0 -0
- {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/top_level.txt +0 -0
cartography/data/indexes.cypher
CHANGED
|
@@ -23,10 +23,6 @@ CREATE INDEX IF NOT EXISTS FOR (n:AWSDNSZone) ON (n.zoneid);
|
|
|
23
23
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSDNSZone) ON (n.lastupdated);
|
|
24
24
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSGroup) ON (n.arn);
|
|
25
25
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSGroup) ON (n.lastupdated);
|
|
26
|
-
CREATE INDEX IF NOT EXISTS FOR (n:AWSInspectorFinding) ON (n.id);
|
|
27
|
-
CREATE INDEX IF NOT EXISTS FOR (n:AWSInspectorFinding) ON (n.lastupdated);
|
|
28
|
-
CREATE INDEX IF NOT EXISTS FOR (n:AWSInspectorPackage) ON (n.id);
|
|
29
|
-
CREATE INDEX IF NOT EXISTS FOR (n:AWSInspectorPackage) ON (n.lastupdated);
|
|
30
26
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSInternetGateway) ON (n.id);
|
|
31
27
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSInternetGateway) ON (n.lastupdated);
|
|
32
28
|
CREATE INDEX IF NOT EXISTS FOR (n:AWSIpv4CidrBlock) ON (n.id);
|
|
@@ -93,8 +89,6 @@ CREATE INDEX IF NOT EXISTS FOR (n:DOProject) ON (n.lastupdated);
|
|
|
93
89
|
CREATE INDEX IF NOT EXISTS FOR (n:EBSSnapshot) ON (n.id);
|
|
94
90
|
CREATE INDEX IF NOT EXISTS FOR (n:EBSSnapshot) ON (n.lastupdated);
|
|
95
91
|
CREATE INDEX IF NOT EXISTS FOR (n:EC2KeyPair) ON (n.keyfingerprint);
|
|
96
|
-
CREATE INDEX IF NOT EXISTS FOR (n:EC2PrivateIp) ON (n.id);
|
|
97
|
-
CREATE INDEX IF NOT EXISTS FOR (n:EC2PrivateIp) ON (n.lastupdated);
|
|
98
92
|
CREATE INDEX IF NOT EXISTS FOR (n:EC2ReservedInstance) ON (n.id);
|
|
99
93
|
CREATE INDEX IF NOT EXISTS FOR (n:EC2ReservedInstance) ON (n.lastupdated);
|
|
100
94
|
CREATE INDEX IF NOT EXISTS FOR (n:ECRImage) ON (n.id);
|
|
@@ -125,8 +119,6 @@ CREATE INDEX IF NOT EXISTS FOR (n:ECSContainerDefinition) ON (n.id);
|
|
|
125
119
|
CREATE INDEX IF NOT EXISTS FOR (n:ECSContainerDefinition) ON (n.lastupdated);
|
|
126
120
|
CREATE INDEX IF NOT EXISTS FOR (n:ECSContainer) ON (n.id);
|
|
127
121
|
CREATE INDEX IF NOT EXISTS FOR (n:ECSContainer) ON (n.lastupdated);
|
|
128
|
-
CREATE INDEX IF NOT EXISTS FOR (n:EKSCluster) ON (n.id);
|
|
129
|
-
CREATE INDEX IF NOT EXISTS FOR (n:EKSCluster) ON (n.lastupdated);
|
|
130
122
|
CREATE INDEX IF NOT EXISTS FOR (n:ElasticacheCluster) ON (n.id);
|
|
131
123
|
CREATE INDEX IF NOT EXISTS FOR (n:ElasticacheCluster) ON (n.arn);
|
|
132
124
|
CREATE INDEX IF NOT EXISTS FOR (n:ElasticacheCluster) ON (n.lastupdated);
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"statements": [
|
|
3
3
|
{
|
|
4
|
+
"__comment__": "READ -> ListBucket, ListBucketVersions, ListBucketMultipartUploads",
|
|
4
5
|
"query": "MATCH (acl:S3Acl)-[:APPLIES_TO]->(bucket:S3Bucket)<-[:RESOURCE]-(aws:AWSAccount{id: $AWS_ID})\nWHERE acl.uri IN ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers'] AND acl.permission = 'READ'\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:ListBucket', 's3:ListBucketVersions', 's3:ListBucketMultipartUploads']",
|
|
5
6
|
"iterative": false
|
|
6
7
|
},
|
|
7
8
|
{
|
|
8
|
-
"
|
|
9
|
+
"__comment__": "WRITE -> PutObject",
|
|
10
|
+
"query": "MATCH (acl:S3Acl)-[:APPLIES_TO]->(bucket:S3Bucket)<-[:RESOURCE]-(aws:AWSAccount{id: $AWS_ID})\nWHERE acl.uri IN ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers'] AND acl.permission = 'WRITE'\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:PutObject']",
|
|
9
11
|
"iterative": false
|
|
10
12
|
},
|
|
11
13
|
{
|
|
12
|
-
"
|
|
14
|
+
"__comment__": "READ_ACP -> GetBucketAcl",
|
|
15
|
+
"query": "MATCH (acl:S3Acl)-[:APPLIES_TO]->(bucket:S3Bucket)<-[:RESOURCE]-(aws:AWSAccount{id: $AWS_ID})\nWHERE acl.uri IN ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers'] AND acl.permission = 'READ_ACP'\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:GetBucketAcl']",
|
|
13
16
|
"iterative": false
|
|
14
17
|
},
|
|
15
18
|
{
|
|
19
|
+
"__comment__": "WRITE_ACP -> PutBucketAcl",
|
|
16
20
|
"query": "MATCH (acl:S3Acl)-[:APPLIES_TO]->(bucket:S3Bucket)<-[:RESOURCE]-(aws:AWSAccount{id: $AWS_ID})\nWHERE acl.uri IN ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers'] AND acl.permission = 'WRITE_ACP'\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:PutBucketAcl']",
|
|
17
21
|
"iterative": false
|
|
18
22
|
},
|
|
19
23
|
{
|
|
24
|
+
"__comment__": "FULL_CONTROL -> Pretty much everything",
|
|
20
25
|
"query": "MATCH (acl:S3Acl)-[:APPLIES_TO]->(bucket:S3Bucket)<-[:RESOURCE]-(aws:AWSAccount{id: $AWS_ID})\nWHERE acl.uri IN ['http://acs.amazonaws.com/groups/global/AllUsers', 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers'] AND acl.permission = 'FULL_CONTROL'\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:ListBucket', 's3:ListBucketVersions', 's3:ListBucketMultipartUploads', 's3:PutObject', 's3:DeleteObject', 's3:DeleteObjectVersion', 's3:PutBucketAcl']",
|
|
21
26
|
"iterative": false
|
|
22
27
|
}],
|
|
@@ -13,10 +13,10 @@ from cartography.graph.job import GraphJob
|
|
|
13
13
|
from cartography.intel.aws.ec2.util import get_botocore_config
|
|
14
14
|
from cartography.models.aws.ec2.instances import EC2InstanceSchema
|
|
15
15
|
from cartography.models.aws.ec2.keypairs import EC2KeyPairSchema
|
|
16
|
-
from cartography.models.aws.ec2.
|
|
16
|
+
from cartography.models.aws.ec2.networkinterface_instance import EC2NetworkInterfaceInstanceSchema
|
|
17
17
|
from cartography.models.aws.ec2.reservations import EC2ReservationSchema
|
|
18
|
-
from cartography.models.aws.ec2.
|
|
19
|
-
from cartography.models.aws.ec2.
|
|
18
|
+
from cartography.models.aws.ec2.securitygroup_instance import EC2SecurityGroupInstanceSchema
|
|
19
|
+
from cartography.models.aws.ec2.subnet_instance import EC2SubnetInstanceSchema
|
|
20
20
|
from cartography.models.aws.ec2.volumes import EBSVolumeInstanceSchema
|
|
21
21
|
from cartography.util import aws_handle_regions
|
|
22
22
|
from cartography.util import timeit
|
|
@@ -183,7 +183,7 @@ def load_ec2_subnets(
|
|
|
183
183
|
) -> None:
|
|
184
184
|
load(
|
|
185
185
|
neo4j_session,
|
|
186
|
-
|
|
186
|
+
EC2SubnetInstanceSchema(),
|
|
187
187
|
subnet_list,
|
|
188
188
|
Region=region,
|
|
189
189
|
AWS_ID=current_aws_account_id,
|
|
@@ -219,7 +219,7 @@ def load_ec2_security_groups(
|
|
|
219
219
|
) -> None:
|
|
220
220
|
load(
|
|
221
221
|
neo4j_session,
|
|
222
|
-
|
|
222
|
+
EC2SecurityGroupInstanceSchema(),
|
|
223
223
|
sg_list,
|
|
224
224
|
Region=region,
|
|
225
225
|
AWS_ID=current_aws_account_id,
|
|
@@ -237,7 +237,7 @@ def load_ec2_network_interfaces(
|
|
|
237
237
|
) -> None:
|
|
238
238
|
load(
|
|
239
239
|
neo4j_session,
|
|
240
|
-
|
|
240
|
+
EC2NetworkInterfaceInstanceSchema(),
|
|
241
241
|
network_interface_list,
|
|
242
242
|
Region=region,
|
|
243
243
|
AWS_ID=current_aws_account_id,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
|
+
from collections import namedtuple
|
|
4
|
+
from typing import Any
|
|
3
5
|
from typing import Dict
|
|
4
6
|
from typing import List
|
|
5
7
|
|
|
@@ -7,18 +9,30 @@ import boto3
|
|
|
7
9
|
import neo4j
|
|
8
10
|
|
|
9
11
|
from .util import get_botocore_config
|
|
12
|
+
from cartography.client.core.tx import load
|
|
10
13
|
from cartography.graph.job import GraphJob
|
|
11
14
|
from cartography.models.aws.ec2.networkinterfaces import EC2NetworkInterfaceSchema
|
|
15
|
+
from cartography.models.aws.ec2.privateip_networkinterface import EC2PrivateIpNetworkInterfaceSchema
|
|
16
|
+
from cartography.models.aws.ec2.securitygroup_networkinterface import EC2SecurityGroupNetworkInterfaceSchema
|
|
17
|
+
from cartography.models.aws.ec2.subnet_networkinterface import EC2SubnetNetworkInterfaceSchema
|
|
12
18
|
from cartography.util import aws_handle_regions
|
|
13
|
-
from cartography.util import run_cleanup_job
|
|
14
19
|
from cartography.util import timeit
|
|
15
20
|
|
|
16
21
|
logger = logging.getLogger(__name__)
|
|
17
22
|
|
|
23
|
+
Ec2NetworkData = namedtuple(
|
|
24
|
+
"Ec2NetworkData", [
|
|
25
|
+
"network_interface_list",
|
|
26
|
+
"private_ip_list",
|
|
27
|
+
"sg_list",
|
|
28
|
+
"subnet_list",
|
|
29
|
+
],
|
|
30
|
+
)
|
|
31
|
+
|
|
18
32
|
|
|
19
33
|
@timeit
|
|
20
34
|
@aws_handle_regions
|
|
21
|
-
def get_network_interface_data(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
|
|
35
|
+
def get_network_interface_data(boto3_session: boto3.session.Session, region: str) -> List[Dict[str, Any]]:
|
|
22
36
|
client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
|
|
23
37
|
paginator = client.get_paginator('describe_network_interfaces')
|
|
24
38
|
subnets: List[Dict] = []
|
|
@@ -27,256 +41,215 @@ def get_network_interface_data(boto3_session: boto3.session.Session, region: str
|
|
|
27
41
|
return subnets
|
|
28
42
|
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
Creates (:NetworkInterface),
|
|
37
|
-
(:NetworkInterface)-[:RESOURCE]->(:AWSAccount),
|
|
38
|
-
(:NetworkInterface)-[:MEMBER_OF_EC2_SECURITY_GROUP]->(:EC2SecurityGroup),
|
|
39
|
-
(:NetworkInterface)-[:PART_OF_SUBNET]->(:EC2Subnet),
|
|
40
|
-
(:PrivateIpAddress),
|
|
41
|
-
(:NetworkInterface)-[:PRIVATE_IP_ADDRESS]->(:PrivateIpAddress)
|
|
42
|
-
"""
|
|
43
|
-
logger.debug("Loading %d network interfaces in %s.", len(data), region)
|
|
44
|
-
ingest_network_interfaces = """
|
|
45
|
-
UNWIND $network_interfaces AS network_interface
|
|
46
|
-
MERGE (netinf:NetworkInterface{id: network_interface.NetworkInterfaceId})
|
|
47
|
-
ON CREATE SET netinf.firstseen = timestamp()
|
|
48
|
-
SET netinf.lastupdated = $update_tag,
|
|
49
|
-
netinf.mac_address = network_interface.MacAddress,
|
|
50
|
-
netinf.description = network_interface.Description,
|
|
51
|
-
netinf.private_ip_address = network_interface.PrivateIpAddress,
|
|
52
|
-
netinf.id = network_interface.NetworkInterfaceId,
|
|
53
|
-
netinf.private_dns_name = network_interface.PrivateDnsName,
|
|
54
|
-
netinf.status = network_interface.Status,
|
|
55
|
-
netinf.subnetid = network_interface.SubnetId,
|
|
56
|
-
netinf.interface_type = network_interface.InterfaceType,
|
|
57
|
-
netinf.requester_managed = network_interface.RequesterManaged,
|
|
58
|
-
netinf.source_dest_check = network_interface.SourceDestCheck,
|
|
59
|
-
netinf.requester_id = network_interface.RequesterId,
|
|
60
|
-
netinf.public_ip = network_interface.Association.PublicIp
|
|
61
|
-
WITH network_interface, netinf
|
|
44
|
+
def transform_network_interface_data(data_list: List[Dict[str, Any]], region: str) -> Ec2NetworkData:
|
|
45
|
+
network_interface_list = []
|
|
46
|
+
private_ip_list = []
|
|
47
|
+
sg_list = []
|
|
48
|
+
subnet_list = []
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
50
|
+
for network_interface in data_list:
|
|
51
|
+
# Parse network interface description for ELB association
|
|
52
|
+
# https://aws.amazon.com/premiumsupport/knowledge-center/elb-find-load-balancer-IP/
|
|
53
|
+
elb_v1_id = None
|
|
54
|
+
elb_v2_id = None
|
|
55
|
+
elb_match = re.match(r'^ELB (?:net|app)/([^\/]+)\/(.*)', network_interface.get('Description', ''))
|
|
56
|
+
if elb_match:
|
|
57
|
+
elb_v1_id = f'{elb_match[1]}-{elb_match[2]}.elb.{region}.amazonaws.com'
|
|
58
|
+
else:
|
|
59
|
+
elb_match = re.match(r'^ELB (.*)', network_interface.get('Description', ''))
|
|
60
|
+
if elb_match:
|
|
61
|
+
elb_v2_id = elb_match[1]
|
|
62
|
+
# TODO issue #1024 change this to arn when ready
|
|
63
|
+
network_interface_id = network_interface['NetworkInterfaceId']
|
|
64
|
+
network_interface_list.append(
|
|
65
|
+
{
|
|
66
|
+
'Id': network_interface_id,
|
|
67
|
+
'NetworkInterfaceId': network_interface['NetworkInterfaceId'],
|
|
68
|
+
'Description': network_interface['Description'],
|
|
69
|
+
'InstanceId': network_interface.get('Attachment', {}).get('InstanceId'),
|
|
70
|
+
'InterfaceType': network_interface['InterfaceType'],
|
|
71
|
+
'MacAddress': network_interface['MacAddress'],
|
|
72
|
+
'PrivateDnsName': network_interface['PrivateDnsName'],
|
|
73
|
+
'PrivateIpAddress': network_interface['PrivateIpAddress'],
|
|
74
|
+
'PublicIp': network_interface.get('Association', {}).get('PublicIp'),
|
|
75
|
+
'RequesterId': network_interface.get('RequesterId'),
|
|
76
|
+
'RequesterManaged': network_interface['RequesterManaged'],
|
|
77
|
+
'SourceDestCheck': network_interface['SourceDestCheck'],
|
|
78
|
+
'Status': network_interface['Status'],
|
|
79
|
+
'SubnetId': network_interface['SubnetId'],
|
|
80
|
+
'ElbV1Id': elb_v1_id,
|
|
81
|
+
'ElbV2Id': elb_v2_id,
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
if network_interface.get('PrivateIpAddresses'):
|
|
85
|
+
for private_ip_address in network_interface['PrivateIpAddresses']:
|
|
86
|
+
private_ip_list.append(
|
|
87
|
+
{
|
|
88
|
+
'Id': f"{network_interface['NetworkInterfaceId']}:{private_ip_address['PrivateIpAddress']}",
|
|
89
|
+
'NetworkInterfaceId': network_interface['NetworkInterfaceId'],
|
|
90
|
+
'IpOwnerId': private_ip_address.get('Association', {}).get('IpOwnerId'),
|
|
91
|
+
'Primary': private_ip_address['Primary'],
|
|
92
|
+
'PrivateIpAddress': private_ip_address['PrivateIpAddress'],
|
|
93
|
+
'PublicIp': private_ip_address.get('Association', {}).get('PublicIp'),
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if network_interface.get("Groups"):
|
|
98
|
+
for group in network_interface["Groups"]:
|
|
99
|
+
sg_list.append(
|
|
100
|
+
{
|
|
101
|
+
'GroupId': group['GroupId'],
|
|
102
|
+
'NetworkInterfaceId': network_interface_id,
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
subnet_id = network_interface.get('SubnetId')
|
|
107
|
+
if subnet_id:
|
|
108
|
+
subnet_list.append(
|
|
109
|
+
{
|
|
110
|
+
'NetworkInterfaceId': network_interface_id,
|
|
111
|
+
'SubnetId': subnet_id,
|
|
112
|
+
'ElbV1Id': elb_v1_id,
|
|
113
|
+
'ElbV2Id': elb_v2_id,
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return Ec2NetworkData(
|
|
118
|
+
network_interface_list=network_interface_list,
|
|
119
|
+
private_ip_list=private_ip_list,
|
|
120
|
+
sg_list=sg_list,
|
|
121
|
+
subnet_list=subnet_list,
|
|
105
122
|
)
|
|
106
123
|
|
|
107
124
|
|
|
108
125
|
@timeit
|
|
109
|
-
def
|
|
110
|
-
|
|
126
|
+
def load_network_interfaces(
|
|
127
|
+
neo4j_session: neo4j.Session,
|
|
128
|
+
data: List[Dict[str, Any]],
|
|
129
|
+
region: str,
|
|
130
|
+
aws_account_id: str,
|
|
131
|
+
update_tag: int,
|
|
111
132
|
) -> None:
|
|
112
|
-
""
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
121
|
-
SET r.lastupdated = $update_tag
|
|
122
|
-
"""
|
|
123
|
-
logger.debug("Attaching %d EC2 instances to network interfaces in %s.", len(instance_associations), region)
|
|
124
|
-
neo4j_session.run(
|
|
125
|
-
ingest_network_interface_instance_relations, instance_associations=instance_associations,
|
|
126
|
-
update_tag=update_tag, region=region, aws_account_id=aws_account_id,
|
|
133
|
+
logger.info(f"Loading {len(data)} network interfaces in {region}.")
|
|
134
|
+
load(
|
|
135
|
+
neo4j_session,
|
|
136
|
+
EC2NetworkInterfaceSchema(),
|
|
137
|
+
data,
|
|
138
|
+
Region=region,
|
|
139
|
+
AWS_ID=aws_account_id,
|
|
140
|
+
lastupdated=update_tag,
|
|
127
141
|
)
|
|
128
142
|
|
|
129
143
|
|
|
130
144
|
@timeit
|
|
131
|
-
def
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
def load_private_ip_network_interface(
|
|
146
|
+
neo4j_session: neo4j.Session,
|
|
147
|
+
data: List[Dict[str, Any]],
|
|
148
|
+
region: str,
|
|
149
|
+
aws_account_id: str,
|
|
150
|
+
update_tag: int,
|
|
134
151
|
) -> None:
|
|
135
152
|
"""
|
|
136
|
-
|
|
153
|
+
Private IPs as known by describe-network-interfaces.
|
|
137
154
|
"""
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
logger.debug("Attaching %d ELBs to network interfaces in %s.", len(elb_associations), region)
|
|
147
|
-
neo4j_session.run(
|
|
148
|
-
ingest_network_interface_elb_relations, elb_associations=elb_associations,
|
|
149
|
-
update_tag=update_tag, region=region, aws_account_id=aws_account_id,
|
|
155
|
+
logger.info(f"Loading {len(data)} private IPs in {region}.")
|
|
156
|
+
load(
|
|
157
|
+
neo4j_session,
|
|
158
|
+
EC2PrivateIpNetworkInterfaceSchema(),
|
|
159
|
+
data,
|
|
160
|
+
Region=region,
|
|
161
|
+
AWS_ID=aws_account_id,
|
|
162
|
+
lastupdated=update_tag,
|
|
150
163
|
)
|
|
151
164
|
|
|
152
165
|
|
|
153
166
|
@timeit
|
|
154
|
-
def
|
|
155
|
-
|
|
156
|
-
|
|
167
|
+
def load_security_group_network_interface(
|
|
168
|
+
neo4j_session: neo4j.Session,
|
|
169
|
+
data: List[Dict[str, Any]],
|
|
170
|
+
region: str,
|
|
171
|
+
aws_account_id: str,
|
|
172
|
+
update_tag: int,
|
|
157
173
|
) -> None:
|
|
158
174
|
"""
|
|
159
|
-
|
|
160
|
-
"""
|
|
161
|
-
ingest_network_interface_elb2_relations = """
|
|
162
|
-
UNWIND $elb_associations AS elb_association
|
|
163
|
-
MATCH (netinf:NetworkInterface{id: elb_association.netinf_id}),
|
|
164
|
-
(elb:LoadBalancerV2{id: elb_association.elb_id})
|
|
165
|
-
MERGE (elb)-[r:NETWORK_INTERFACE]->(netinf)
|
|
166
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
167
|
-
SET r.lastupdated = $update_tag
|
|
175
|
+
Security groups as known by describe-network-interfaces.
|
|
168
176
|
"""
|
|
169
|
-
logger.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
177
|
+
logger.info(f"Loading {len(data)} security groups in {region}.")
|
|
178
|
+
load(
|
|
179
|
+
neo4j_session,
|
|
180
|
+
EC2SecurityGroupNetworkInterfaceSchema(),
|
|
181
|
+
data,
|
|
182
|
+
Region=region,
|
|
183
|
+
AWS_ID=aws_account_id,
|
|
184
|
+
lastupdated=update_tag,
|
|
173
185
|
)
|
|
174
186
|
|
|
175
187
|
|
|
176
188
|
@timeit
|
|
177
|
-
def
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
MERGE (i)-[r:PART_OF_SUBNET]->(s)
|
|
185
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
186
|
-
SET r.lastupdated = $update_tag
|
|
187
|
-
"""
|
|
188
|
-
logger.debug("-> Instance to subnet")
|
|
189
|
-
neo4j_session.run(
|
|
190
|
-
ingest_network_interface_instance_relations, update_tag=update_tag,
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
@timeit
|
|
195
|
-
def load_network_interface_load_balancer_relations(neo4j_session: neo4j.Session, update_tag: int) -> None:
|
|
196
|
-
"""
|
|
197
|
-
Creates (:LoadBalancer)-[:PART_OF_SUBNET]->(:EC2Subnet) if
|
|
198
|
-
(:LoadBalancer)--(:NetworkInterface)--(:EC2Subnet).
|
|
199
|
-
"""
|
|
200
|
-
ingest_network_interface_loadbalancer_relations = """
|
|
201
|
-
MATCH (i:LoadBalancer)-[:NETWORK_INTERFACE]-(interface:NetworkInterface)-[:PART_OF_SUBNET]-(s:EC2Subnet)
|
|
202
|
-
MERGE (i)-[r:PART_OF_SUBNET]->(s)
|
|
203
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
204
|
-
SET r.lastupdated = $update_tag
|
|
205
|
-
"""
|
|
206
|
-
logger.debug("-> ELB to subnet")
|
|
207
|
-
neo4j_session.run(
|
|
208
|
-
ingest_network_interface_loadbalancer_relations, update_tag=update_tag,
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
@timeit
|
|
213
|
-
def load_network_interface_load_balancer_v2_relations(neo4j_session: neo4j.Session, update_tag: int) -> None:
|
|
214
|
-
"""
|
|
215
|
-
Creates (:LoadBalancerV2)-[:PART_OF_SUBNET]->(:EC2Subnet) if
|
|
216
|
-
(:LoadBalancerV2)--(:NetworkInterface)--(:EC2Subnet).
|
|
189
|
+
def load_subnet_network_interface(
|
|
190
|
+
neo4j_session: neo4j.Session,
|
|
191
|
+
data: List[Dict[str, Any]],
|
|
192
|
+
region: str,
|
|
193
|
+
aws_account_id: str,
|
|
194
|
+
update_tag: int,
|
|
195
|
+
) -> None:
|
|
217
196
|
"""
|
|
218
|
-
|
|
219
|
-
MATCH (i:LoadBalancerV2)-[:NETWORK_INTERFACE]-(interface:NetworkInterface)-[:PART_OF_SUBNET]-(s:EC2Subnet)
|
|
220
|
-
MERGE (i)-[r:PART_OF_SUBNET]->(s)
|
|
221
|
-
ON CREATE SET r.firstseen = timestamp()
|
|
222
|
-
SET r.lastupdated = $update_tag
|
|
197
|
+
Subnets as known by describe-network-interfaces.
|
|
223
198
|
"""
|
|
224
|
-
logger.
|
|
225
|
-
|
|
226
|
-
|
|
199
|
+
logger.info(f"Loading {len(data)} subnets in {region}.")
|
|
200
|
+
load(
|
|
201
|
+
neo4j_session,
|
|
202
|
+
EC2SubnetNetworkInterfaceSchema(),
|
|
203
|
+
data,
|
|
204
|
+
Region=region,
|
|
205
|
+
AWS_ID=aws_account_id,
|
|
206
|
+
lastupdated=update_tag,
|
|
227
207
|
)
|
|
228
208
|
|
|
229
209
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
else:
|
|
245
|
-
matchObj = re.match(r'^ELB (.*)', network_interface.get('Description', ''))
|
|
246
|
-
if matchObj:
|
|
247
|
-
elb_associations.append({
|
|
248
|
-
'netinf_id': network_interface['NetworkInterfaceId'],
|
|
249
|
-
'elb_name': matchObj[1],
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
if 'Attachment' in network_interface and 'InstanceId' in network_interface['Attachment']:
|
|
253
|
-
instance_associations.append({
|
|
254
|
-
'netinf_id': network_interface['NetworkInterfaceId'],
|
|
255
|
-
'instance_id': network_interface['Attachment']['InstanceId'],
|
|
256
|
-
})
|
|
257
|
-
load_network_interfaces(neo4j_session, data, region, aws_account_id, update_tag) # type: ignore
|
|
258
|
-
load_network_interface_instance_relations(
|
|
259
|
-
neo4j_session, instance_associations, region, aws_account_id, update_tag,
|
|
260
|
-
)
|
|
261
|
-
load_network_interface_elb_relations(neo4j_session, elb_associations, region, aws_account_id, update_tag)
|
|
262
|
-
load_network_interface_elbv2_relations(neo4j_session, elb_associations_v2, region, aws_account_id, update_tag)
|
|
263
|
-
load_network_interface_instance_to_subnet_relations(neo4j_session, update_tag)
|
|
264
|
-
load_network_interface_load_balancer_relations(neo4j_session, update_tag)
|
|
210
|
+
def load_network_data(
|
|
211
|
+
neo4j_session: neo4j.Session,
|
|
212
|
+
region: str,
|
|
213
|
+
current_aws_account_id: str,
|
|
214
|
+
update_tag: int,
|
|
215
|
+
network_interface_list: List[Dict[str, Any]],
|
|
216
|
+
private_ip_list: List[Dict[str, Any]],
|
|
217
|
+
subnet_list: List[Dict[str, Any]],
|
|
218
|
+
sg_list: List[Dict[str, Any]],
|
|
219
|
+
) -> None:
|
|
220
|
+
load_network_interfaces(neo4j_session, network_interface_list, region, current_aws_account_id, update_tag)
|
|
221
|
+
load_private_ip_network_interface(neo4j_session, private_ip_list, region, current_aws_account_id, update_tag)
|
|
222
|
+
load_subnet_network_interface(neo4j_session, subnet_list, region, current_aws_account_id, update_tag)
|
|
223
|
+
load_security_group_network_interface(neo4j_session, sg_list, region, current_aws_account_id, update_tag)
|
|
265
224
|
|
|
266
225
|
|
|
267
226
|
@timeit
|
|
268
227
|
def cleanup_network_interfaces(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
|
|
269
|
-
run_cleanup_job('aws_ingest_network_interfaces_cleanup.json', neo4j_session, common_job_parameters)
|
|
270
228
|
GraphJob.from_node_schema(EC2NetworkInterfaceSchema(), common_job_parameters).run(neo4j_session)
|
|
229
|
+
GraphJob.from_node_schema(EC2PrivateIpNetworkInterfaceSchema(), common_job_parameters).run(neo4j_session)
|
|
271
230
|
|
|
272
231
|
|
|
273
232
|
@timeit
|
|
274
233
|
def sync_network_interfaces(
|
|
275
|
-
|
|
276
|
-
|
|
234
|
+
neo4j_session: neo4j.Session,
|
|
235
|
+
boto3_session: boto3.session.Session,
|
|
236
|
+
regions: List[str],
|
|
237
|
+
current_aws_account_id: str,
|
|
238
|
+
update_tag: int,
|
|
239
|
+
common_job_parameters: Dict,
|
|
277
240
|
) -> None:
|
|
278
241
|
for region in regions:
|
|
279
|
-
logger.info("Syncing EC2 network interfaces for region '
|
|
242
|
+
logger.info(f"Syncing EC2 network interfaces for region '{region}' in account '{current_aws_account_id}'.")
|
|
280
243
|
data = get_network_interface_data(boto3_session, region)
|
|
281
|
-
|
|
244
|
+
ec2_network_data = transform_network_interface_data(data, region)
|
|
245
|
+
load_network_data(
|
|
246
|
+
neo4j_session,
|
|
247
|
+
region,
|
|
248
|
+
current_aws_account_id,
|
|
249
|
+
update_tag,
|
|
250
|
+
ec2_network_data.network_interface_list,
|
|
251
|
+
ec2_network_data.private_ip_list,
|
|
252
|
+
ec2_network_data.subnet_list,
|
|
253
|
+
ec2_network_data.sg_list,
|
|
254
|
+
)
|
|
282
255
|
cleanup_network_interfaces(neo4j_session, common_job_parameters)
|
|
@@ -8,7 +8,7 @@ import neo4j
|
|
|
8
8
|
|
|
9
9
|
from .util import get_botocore_config
|
|
10
10
|
from cartography.graph.job import GraphJob
|
|
11
|
-
from cartography.models.aws.ec2.
|
|
11
|
+
from cartography.models.aws.ec2.securitygroup_instance import EC2SecurityGroupInstanceSchema
|
|
12
12
|
from cartography.util import aws_handle_regions
|
|
13
13
|
from cartography.util import run_cleanup_job
|
|
14
14
|
from cartography.util import timeit
|
|
@@ -148,7 +148,7 @@ def cleanup_ec2_security_groupinfo(neo4j_session: neo4j.Session, common_job_para
|
|
|
148
148
|
neo4j_session,
|
|
149
149
|
common_job_parameters,
|
|
150
150
|
)
|
|
151
|
-
GraphJob.from_node_schema(
|
|
151
|
+
GraphJob.from_node_schema(EC2SecurityGroupInstanceSchema(), common_job_parameters).run(neo4j_session)
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
@timeit
|
|
@@ -7,7 +7,7 @@ import neo4j
|
|
|
7
7
|
|
|
8
8
|
from .util import get_botocore_config
|
|
9
9
|
from cartography.graph.job import GraphJob
|
|
10
|
-
from cartography.models.aws.ec2.
|
|
10
|
+
from cartography.models.aws.ec2.subnet_instance import EC2SubnetInstanceSchema
|
|
11
11
|
from cartography.util import aws_handle_regions
|
|
12
12
|
from cartography.util import run_cleanup_job
|
|
13
13
|
from cartography.util import timeit
|
|
@@ -78,7 +78,7 @@ def load_subnets(
|
|
|
78
78
|
@timeit
|
|
79
79
|
def cleanup_subnets(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
|
|
80
80
|
run_cleanup_job('aws_ingest_subnets_cleanup.json', neo4j_session, common_job_parameters)
|
|
81
|
-
GraphJob.from_node_schema(
|
|
81
|
+
GraphJob.from_node_schema(EC2SubnetInstanceSchema(), common_job_parameters).run(neo4j_session)
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
@timeit
|