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.

Files changed (33) hide show
  1. cartography/data/indexes.cypher +0 -8
  2. cartography/data/jobs/analysis/aws_s3acl_analysis.json +7 -2
  3. cartography/intel/aws/ec2/instances.py +6 -6
  4. cartography/intel/aws/ec2/network_interfaces.py +186 -213
  5. cartography/intel/aws/ec2/security_groups.py +2 -2
  6. cartography/intel/aws/ec2/subnets.py +2 -2
  7. cartography/intel/aws/eks.py +46 -54
  8. cartography/intel/aws/inspector.py +44 -142
  9. cartography/intel/aws/s3.py +6 -1
  10. cartography/models/aws/ec2/loadbalancerv2.py +0 -0
  11. cartography/models/aws/ec2/networkinterface_instance.py +109 -0
  12. cartography/models/aws/ec2/networkinterfaces.py +36 -49
  13. cartography/models/aws/ec2/privateip_networkinterface.py +72 -0
  14. cartography/models/aws/ec2/{securitygroups.py → securitygroup_instance.py} +9 -6
  15. cartography/models/aws/ec2/securitygroup_networkinterface.py +52 -0
  16. cartography/models/aws/ec2/{subnets.py → subnet_instance.py} +7 -4
  17. cartography/models/aws/ec2/subnet_networkinterface.py +87 -0
  18. cartography/models/aws/eks/__init__.py +0 -0
  19. cartography/models/aws/eks/clusters.py +50 -0
  20. cartography/models/aws/inspector/__init__.py +0 -0
  21. cartography/models/aws/inspector/findings.py +124 -0
  22. cartography/models/aws/inspector/packages.py +73 -0
  23. cartography/util.py +8 -0
  24. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/METADATA +1 -1
  25. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/RECORD +30 -23
  26. cartography/data/jobs/cleanup/aws_import_eks_cleanup.json +0 -15
  27. cartography/data/jobs/cleanup/aws_import_inspector_cleanup.json +0 -35
  28. cartography/data/jobs/cleanup/aws_ingest_network_interfaces_cleanup.json +0 -30
  29. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/LICENSE +0 -0
  30. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/NOTICE +0 -0
  31. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/WHEEL +0 -0
  32. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/entry_points.txt +0 -0
  33. {cartography-0.84.0.dist-info → cartography-0.85.1.dist-info}/top_level.txt +0 -0
@@ -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
- "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'\nAND (acl.ownerid = acl.granteeid)\nSET bucket.anonymous_access = true, bucket.anonymous_actions = coalesce(bucket.anonymous_actions, []) + ['s3:DeleteObjectVersion']",
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
- "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:DeleteObjectVersion']",
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.networkinterfaces import EC2NetworkInterfaceSchema
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.securitygroups import EC2SecurityGroupSchema
19
- from cartography.models.aws.ec2.subnets import EC2SubnetSchema
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
- EC2SubnetSchema(),
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
- EC2SecurityGroupSchema(),
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
- EC2NetworkInterfaceSchema(),
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
- @timeit
31
- def load_network_interfaces(
32
- neo4j_session: neo4j.Session, data: Dict, region: str, aws_account_id: str,
33
- update_tag: int,
34
- ) -> None:
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
- UNWIND network_interface.PrivateIpAddresses AS private_ip_address
64
- MERGE (private_ip:EC2PrivateIp{id: network_interface.NetworkInterfaceId + ':'
65
- + private_ip_address.PrivateIpAddress})
66
- ON CREATE SET private_ip.firstseen = timestamp()
67
- SET private_ip.lastupdated = $update_tag,
68
- private_ip.network_interface_id = network_interface.NetworkInterfaceId,
69
- private_ip.primary = private_ip_address.Primary,
70
- private_ip.private_ip_address = private_ip_address.PrivateIpAddress,
71
- private_ip.public_ip = private_ip_address.Association.PublicIp,
72
- private_ip.ip_owner_id = private_ip_address.Association.IpOwnerId
73
-
74
- MERGE (netinf)-[r:PRIVATE_IP_ADDRESS]->(private_ip)
75
- ON CREATE SET r.firstseen = timestamp()
76
- SET r.lastupdated = $update_tag
77
- WITH network_interface, netinf
78
-
79
- UNWIND network_interface.Groups AS security_group
80
- MERGE (sg:EC2SecurityGroup{id: security_group.GroupId})
81
- ON CREATE SET sg.firstseen = timestamp()
82
- SET sg.lastupdated = $update_tag
83
- MERGE (netinf)-[r:MEMBER_OF_EC2_SECURITY_GROUP]->(sg)
84
- ON CREATE SET r.firstseen = timestamp()
85
- SET r.lastupdated = $update_tag
86
- WITH network_interface, netinf
87
- MERGE (acc:AWSAccount{id: $aws_account_id})
88
- ON CREATE SET acc.firstseen = timestamp(), acc.inscope=true
89
- SET acc.lastupdated = $update_tag
90
- MERGE (acc)-[r:RESOURCE]->(netinf)
91
- ON CREATE SET r.firstseen = timestamp()
92
- SET r.lastupdated = $update_tag
93
- WITH network_interface, netinf
94
-
95
- MERGE (snet:EC2Subnet{subnetid: network_interface.SubnetId})
96
- ON CREATE SET snet.firstseen = timestamp()
97
- SET snet.lastupdated = $update_tag
98
- MERGE (netinf)-[r:PART_OF_SUBNET]->(snet)
99
- ON CREATE SET r.firstseen = timestamp()
100
- SET r.lastupdated = $update_tag
101
- """
102
- neo4j_session.run(
103
- ingest_network_interfaces, network_interfaces=data, update_tag=update_tag,
104
- region=region, aws_account_id=aws_account_id,
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 load_network_interface_instance_relations(
110
- neo4j_session: neo4j.Session, instance_associations: List[Dict], region: str, aws_account_id: str, update_tag: int,
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
- Creates (:EC2Instance)-[:NETWORK_INTERFACE]->(:NetworkInterface)
114
- """
115
- ingest_network_interface_instance_relations = """
116
- UNWIND $instance_associations AS instance_association
117
- MATCH (netinf:NetworkInterface{id: instance_association.netinf_id}),
118
- (instance:EC2Instance{id: instance_association.instance_id})
119
- MERGE (instance)-[r:NETWORK_INTERFACE]->(netinf)
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 load_network_interface_elb_relations(
132
- neo4j_session: neo4j.Session, elb_associations: List[Dict], region: str,
133
- aws_account_id: str, update_tag: int,
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
- Creates (:LoadBalancer)-[:NETWORK_INTERFACE]->(:NetworkInterface)
153
+ Private IPs as known by describe-network-interfaces.
137
154
  """
138
- ingest_network_interface_elb_relations = """
139
- UNWIND $elb_associations AS elb_association
140
- MATCH (netinf:NetworkInterface{id: elb_association.netinf_id}),
141
- (elb:LoadBalancer{name: elb_association.elb_name})
142
- MERGE (elb)-[r:NETWORK_INTERFACE]->(netinf)
143
- ON CREATE SET r.firstseen = timestamp()
144
- SET r.lastupdated = $update_tag
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 load_network_interface_elbv2_relations(
155
- neo4j_session: neo4j.Session, elb_associations_v2: List[Dict], region: str,
156
- aws_account_id: str, update_tag: int,
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
- Creates (:LoadBalancerV2)-[:NETWORK_INTERFACE]->(:NetworkInterface)
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.debug("Attaching %d ELB V2s to network interfaces in %s.", len(elb_associations_v2), region)
170
- neo4j_session.run(
171
- ingest_network_interface_elb2_relations, elb_associations=elb_associations_v2,
172
- update_tag=update_tag, region=region, aws_account_id=aws_account_id,
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 load_network_interface_instance_to_subnet_relations(neo4j_session: neo4j.Session, update_tag: int) -> None:
178
- """
179
- Creates (:EC2Instance)-[:PART_OF_SUBNET]->(:EC2Subnet) if
180
- (:EC2Instance)--(:NetworkInterface)--(:EC2Subnet).
181
- """
182
- ingest_network_interface_instance_relations = """
183
- MATCH (i:EC2Instance)-[:NETWORK_INTERFACE]-(interface:NetworkInterface)-[:PART_OF_SUBNET]-(s:EC2Subnet)
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
- ingest_network_interface_loadbalancerv2_relations = """
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.debug("-> ELBv2 to subnet")
225
- neo4j_session.run(
226
- ingest_network_interface_loadbalancerv2_relations, update_tag=update_tag,
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
- @timeit
231
- def load(neo4j_session: neo4j.Session, data: List[Dict], region: str, aws_account_id: str, update_tag: int) -> None:
232
- elb_associations = []
233
- elb_associations_v2 = []
234
- instance_associations = []
235
-
236
- for network_interface in data:
237
- # https://aws.amazon.com/premiumsupport/knowledge-center/elb-find-load-balancer-IP/
238
- matchObj = re.match(r'^ELB (?:net|app)/([^\/]+)\/(.*)', network_interface.get('Description', ''))
239
- if matchObj:
240
- elb_associations_v2.append({
241
- 'netinf_id': network_interface['NetworkInterfaceId'],
242
- 'elb_id': f'{matchObj[1]}-{matchObj[2]}.elb.{region}.amazonaws.com',
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
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
276
- update_tag: int, common_job_parameters: Dict,
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 '%s' in account '%s'.", region, current_aws_account_id)
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
- load(neo4j_session, data, region, current_aws_account_id, update_tag)
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.securitygroups import EC2SecurityGroupSchema
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(EC2SecurityGroupSchema(), common_job_parameters).run(neo4j_session)
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.subnets import EC2SubnetSchema
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(EC2SubnetSchema(), common_job_parameters).run(neo4j_session)
81
+ GraphJob.from_node_schema(EC2SubnetInstanceSchema(), common_job_parameters).run(neo4j_session)
82
82
 
83
83
 
84
84
  @timeit