cartography 0.102.0rc1__py3-none-any.whl → 0.103.0rc1__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 (251) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +302 -253
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +4 -0
  6. cartography/driftdetect/__main__.py +1 -2
  7. cartography/driftdetect/add_shortcut.py +10 -2
  8. cartography/driftdetect/cli.py +71 -75
  9. cartography/driftdetect/detect_deviations.py +7 -3
  10. cartography/driftdetect/get_states.py +20 -8
  11. cartography/driftdetect/model.py +5 -5
  12. cartography/driftdetect/serializers.py +8 -6
  13. cartography/driftdetect/storage.py +2 -2
  14. cartography/graph/cleanupbuilder.py +35 -15
  15. cartography/graph/job.py +46 -17
  16. cartography/graph/querybuilder.py +165 -80
  17. cartography/graph/statement.py +35 -26
  18. cartography/intel/analysis.py +4 -1
  19. cartography/intel/aws/__init__.py +114 -55
  20. cartography/intel/aws/apigateway.py +134 -63
  21. cartography/intel/aws/cloudtrail.py +127 -0
  22. cartography/intel/aws/config.py +56 -20
  23. cartography/intel/aws/dynamodb.py +108 -40
  24. cartography/intel/aws/ec2/__init__.py +2 -2
  25. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  26. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  27. cartography/intel/aws/ec2/images.py +49 -20
  28. cartography/intel/aws/ec2/instances.py +234 -136
  29. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  30. cartography/intel/aws/ec2/key_pairs.py +44 -20
  31. cartography/intel/aws/ec2/launch_templates.py +101 -59
  32. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  33. cartography/intel/aws/ec2/load_balancers.py +82 -42
  34. cartography/intel/aws/ec2/network_acls.py +89 -65
  35. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  36. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  37. cartography/intel/aws/ec2/route_tables.py +327 -0
  38. cartography/intel/aws/ec2/security_groups.py +71 -21
  39. cartography/intel/aws/ec2/snapshots.py +61 -22
  40. cartography/intel/aws/ec2/subnets.py +54 -18
  41. cartography/intel/aws/ec2/tgw.py +100 -34
  42. cartography/intel/aws/ec2/util.py +1 -1
  43. cartography/intel/aws/ec2/volumes.py +69 -41
  44. cartography/intel/aws/ec2/vpc.py +37 -12
  45. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  46. cartography/intel/aws/ecr.py +88 -32
  47. cartography/intel/aws/ecs.py +83 -47
  48. cartography/intel/aws/eks.py +55 -29
  49. cartography/intel/aws/elasticache.py +42 -18
  50. cartography/intel/aws/elasticsearch.py +57 -20
  51. cartography/intel/aws/emr.py +61 -23
  52. cartography/intel/aws/iam.py +401 -145
  53. cartography/intel/aws/iam_instance_profiles.py +22 -22
  54. cartography/intel/aws/identitycenter.py +71 -37
  55. cartography/intel/aws/inspector.py +159 -89
  56. cartography/intel/aws/kms.py +92 -38
  57. cartography/intel/aws/lambda_function.py +103 -34
  58. cartography/intel/aws/organizations.py +30 -10
  59. cartography/intel/aws/permission_relationships.py +133 -51
  60. cartography/intel/aws/rds.py +249 -85
  61. cartography/intel/aws/redshift.py +107 -46
  62. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  63. cartography/intel/aws/resources.py +53 -44
  64. cartography/intel/aws/route53.py +108 -61
  65. cartography/intel/aws/s3.py +168 -83
  66. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  67. cartography/intel/aws/secretsmanager.py +24 -12
  68. cartography/intel/aws/securityhub.py +20 -9
  69. cartography/intel/aws/sns.py +166 -0
  70. cartography/intel/aws/sqs.py +60 -28
  71. cartography/intel/aws/ssm.py +70 -30
  72. cartography/intel/aws/util/arns.py +7 -7
  73. cartography/intel/aws/util/common.py +31 -4
  74. cartography/intel/azure/__init__.py +78 -19
  75. cartography/intel/azure/compute.py +101 -27
  76. cartography/intel/azure/cosmosdb.py +496 -170
  77. cartography/intel/azure/sql.py +296 -105
  78. cartography/intel/azure/storage.py +322 -113
  79. cartography/intel/azure/subscription.py +39 -23
  80. cartography/intel/azure/tenant.py +13 -4
  81. cartography/intel/azure/util/credentials.py +95 -55
  82. cartography/intel/bigfix/__init__.py +2 -2
  83. cartography/intel/bigfix/computers.py +93 -65
  84. cartography/intel/create_indexes.py +3 -2
  85. cartography/intel/crowdstrike/__init__.py +11 -9
  86. cartography/intel/crowdstrike/endpoints.py +5 -1
  87. cartography/intel/crowdstrike/spotlight.py +8 -3
  88. cartography/intel/cve/__init__.py +46 -13
  89. cartography/intel/cve/feed.py +48 -12
  90. cartography/intel/digitalocean/__init__.py +22 -13
  91. cartography/intel/digitalocean/compute.py +75 -108
  92. cartography/intel/digitalocean/management.py +44 -80
  93. cartography/intel/digitalocean/platform.py +48 -43
  94. cartography/intel/dns.py +36 -10
  95. cartography/intel/duo/__init__.py +21 -16
  96. cartography/intel/duo/api_host.py +14 -9
  97. cartography/intel/duo/endpoints.py +50 -45
  98. cartography/intel/duo/groups.py +18 -14
  99. cartography/intel/duo/phones.py +37 -34
  100. cartography/intel/duo/tokens.py +26 -23
  101. cartography/intel/duo/users.py +54 -50
  102. cartography/intel/duo/web_authn_credentials.py +30 -25
  103. cartography/intel/entra/__init__.py +25 -7
  104. cartography/intel/entra/ou.py +112 -0
  105. cartography/intel/entra/users.py +69 -63
  106. cartography/intel/gcp/__init__.py +185 -49
  107. cartography/intel/gcp/compute.py +418 -231
  108. cartography/intel/gcp/crm.py +96 -43
  109. cartography/intel/gcp/dns.py +60 -19
  110. cartography/intel/gcp/gke.py +72 -38
  111. cartography/intel/gcp/iam.py +61 -41
  112. cartography/intel/gcp/storage.py +84 -55
  113. cartography/intel/github/__init__.py +13 -11
  114. cartography/intel/github/repos.py +270 -137
  115. cartography/intel/github/teams.py +170 -88
  116. cartography/intel/github/users.py +70 -39
  117. cartography/intel/github/util.py +36 -34
  118. cartography/intel/gsuite/__init__.py +47 -26
  119. cartography/intel/gsuite/api.py +73 -30
  120. cartography/intel/jamf/__init__.py +19 -1
  121. cartography/intel/jamf/computers.py +30 -7
  122. cartography/intel/jamf/util.py +7 -2
  123. cartography/intel/kandji/__init__.py +6 -3
  124. cartography/intel/kandji/devices.py +14 -8
  125. cartography/intel/kubernetes/namespaces.py +7 -4
  126. cartography/intel/kubernetes/pods.py +7 -4
  127. cartography/intel/kubernetes/services.py +8 -4
  128. cartography/intel/lastpass/__init__.py +2 -2
  129. cartography/intel/lastpass/users.py +23 -12
  130. cartography/intel/oci/__init__.py +44 -11
  131. cartography/intel/oci/iam.py +134 -38
  132. cartography/intel/oci/organizations.py +13 -6
  133. cartography/intel/oci/utils.py +43 -20
  134. cartography/intel/okta/__init__.py +66 -15
  135. cartography/intel/okta/applications.py +42 -20
  136. cartography/intel/okta/awssaml.py +93 -33
  137. cartography/intel/okta/factors.py +16 -4
  138. cartography/intel/okta/groups.py +56 -29
  139. cartography/intel/okta/organization.py +5 -1
  140. cartography/intel/okta/origins.py +6 -2
  141. cartography/intel/okta/roles.py +15 -5
  142. cartography/intel/okta/users.py +20 -8
  143. cartography/intel/okta/utils.py +6 -4
  144. cartography/intel/pagerduty/__init__.py +8 -7
  145. cartography/intel/pagerduty/escalation_policies.py +18 -6
  146. cartography/intel/pagerduty/schedules.py +12 -4
  147. cartography/intel/pagerduty/services.py +11 -4
  148. cartography/intel/pagerduty/teams.py +8 -3
  149. cartography/intel/pagerduty/users.py +3 -1
  150. cartography/intel/pagerduty/vendors.py +3 -1
  151. cartography/intel/semgrep/__init__.py +24 -6
  152. cartography/intel/semgrep/dependencies.py +50 -28
  153. cartography/intel/semgrep/deployment.py +3 -1
  154. cartography/intel/semgrep/findings.py +42 -18
  155. cartography/intel/snipeit/__init__.py +17 -3
  156. cartography/intel/snipeit/asset.py +12 -6
  157. cartography/intel/snipeit/user.py +8 -5
  158. cartography/intel/snipeit/util.py +9 -4
  159. cartography/models/aws/apigateway.py +21 -17
  160. cartography/models/aws/apigatewaycertificate.py +28 -22
  161. cartography/models/aws/apigatewayresource.py +28 -20
  162. cartography/models/aws/apigatewaystage.py +33 -25
  163. cartography/models/aws/cloudtrail/__init__.py +0 -0
  164. cartography/models/aws/cloudtrail/trail.py +61 -0
  165. cartography/models/aws/dynamodb/gsi.py +30 -22
  166. cartography/models/aws/dynamodb/tables.py +25 -17
  167. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  168. cartography/models/aws/ec2/images.py +36 -34
  169. cartography/models/aws/ec2/instances.py +51 -45
  170. cartography/models/aws/ec2/keypair.py +21 -16
  171. cartography/models/aws/ec2/keypair_instance.py +28 -21
  172. cartography/models/aws/ec2/launch_configurations.py +30 -26
  173. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  174. cartography/models/aws/ec2/launch_templates.py +21 -17
  175. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  176. cartography/models/aws/ec2/load_balancers.py +47 -37
  177. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  178. cartography/models/aws/ec2/network_acls.py +38 -29
  179. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  180. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  181. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  182. cartography/models/aws/ec2/reservations.py +18 -14
  183. cartography/models/aws/ec2/route_table_associations.py +97 -0
  184. cartography/models/aws/ec2/route_tables.py +128 -0
  185. cartography/models/aws/ec2/routes.py +85 -0
  186. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  187. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  188. cartography/models/aws/ec2/subnet_instance.py +24 -19
  189. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  190. cartography/models/aws/ec2/volumes.py +47 -40
  191. cartography/models/aws/eks/clusters.py +23 -21
  192. cartography/models/aws/emr.py +32 -30
  193. cartography/models/aws/iam/instanceprofile.py +33 -24
  194. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  195. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  196. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  197. cartography/models/aws/inspector/findings.py +77 -65
  198. cartography/models/aws/inspector/packages.py +35 -29
  199. cartography/models/aws/s3/__init__.py +0 -0
  200. cartography/models/aws/s3/account_public_access_block.py +51 -0
  201. cartography/models/aws/sns/__init__.py +0 -0
  202. cartography/models/aws/sns/topic.py +50 -0
  203. cartography/models/aws/ssm/instance_information.py +51 -39
  204. cartography/models/aws/ssm/instance_patch.py +32 -26
  205. cartography/models/bigfix/bigfix_computer.py +42 -38
  206. cartography/models/bigfix/bigfix_root.py +3 -3
  207. cartography/models/core/common.py +12 -10
  208. cartography/models/core/nodes.py +5 -2
  209. cartography/models/core/relationships.py +14 -6
  210. cartography/models/crowdstrike/hosts.py +37 -35
  211. cartography/models/cve/cve.py +34 -32
  212. cartography/models/cve/cve_feed.py +6 -6
  213. cartography/models/digitalocean/__init__.py +0 -0
  214. cartography/models/digitalocean/account.py +21 -0
  215. cartography/models/digitalocean/droplet.py +56 -0
  216. cartography/models/digitalocean/project.py +48 -0
  217. cartography/models/duo/api_host.py +3 -3
  218. cartography/models/duo/endpoint.py +43 -41
  219. cartography/models/duo/group.py +14 -14
  220. cartography/models/duo/phone.py +27 -27
  221. cartography/models/duo/token.py +16 -16
  222. cartography/models/duo/user.py +46 -44
  223. cartography/models/duo/web_authn_credential.py +27 -19
  224. cartography/models/entra/ou.py +48 -0
  225. cartography/models/entra/tenant.py +24 -18
  226. cartography/models/entra/user.py +64 -48
  227. cartography/models/gcp/iam.py +23 -23
  228. cartography/models/github/orgs.py +5 -4
  229. cartography/models/github/teams.py +37 -31
  230. cartography/models/github/users.py +34 -23
  231. cartography/models/kandji/device.py +22 -16
  232. cartography/models/kandji/tenant.py +6 -4
  233. cartography/models/lastpass/tenant.py +3 -3
  234. cartography/models/lastpass/user.py +32 -28
  235. cartography/models/semgrep/dependencies.py +36 -24
  236. cartography/models/semgrep/deployment.py +5 -5
  237. cartography/models/semgrep/findings.py +58 -42
  238. cartography/models/semgrep/locations.py +27 -21
  239. cartography/models/snipeit/asset.py +30 -21
  240. cartography/models/snipeit/tenant.py +6 -4
  241. cartography/models/snipeit/user.py +19 -12
  242. cartography/stats.py +3 -3
  243. cartography/sync.py +107 -31
  244. cartography/util.py +84 -62
  245. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
  246. cartography-0.103.0rc1.dist-info/RECORD +396 -0
  247. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
  248. cartography-0.102.0rc1.dist-info/RECORD +0 -377
  249. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
  250. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
  251. {cartography-0.102.0rc1.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ from typing import Any
5
5
  import boto3
6
6
  import neo4j
7
7
 
8
- from .util import get_botocore_config
9
8
  from cartography.client.core.tx import load
10
9
  from cartography.graph.job import GraphJob
11
10
  from cartography.models.aws.ec2.network_acl_rules import EC2NetworkAclEgressRuleSchema
@@ -14,51 +13,63 @@ from cartography.models.aws.ec2.network_acls import EC2NetworkAclSchema
14
13
  from cartography.util import aws_handle_regions
15
14
  from cartography.util import timeit
16
15
 
16
+ from .util import get_botocore_config
17
+
17
18
  logger = logging.getLogger(__name__)
18
19
 
19
20
  Ec2AclObjects = namedtuple(
20
- "Ec2AclObjects", [
21
- 'network_acls',
22
- 'inbound_rules',
23
- 'outbound_rules',
21
+ "Ec2AclObjects",
22
+ [
23
+ "network_acls",
24
+ "inbound_rules",
25
+ "outbound_rules",
24
26
  ],
25
27
  )
26
28
 
27
29
 
28
30
  @timeit
29
31
  @aws_handle_regions
30
- def get_network_acl_data(boto3_session: boto3.session.Session, region: str) -> list[dict[str, Any]]:
31
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
32
- paginator = client.get_paginator('describe_network_acls')
32
+ def get_network_acl_data(
33
+ boto3_session: boto3.session.Session,
34
+ region: str,
35
+ ) -> list[dict[str, Any]]:
36
+ client = boto3_session.client(
37
+ "ec2",
38
+ region_name=region,
39
+ config=get_botocore_config(),
40
+ )
41
+ paginator = client.get_paginator("describe_network_acls")
33
42
  acls = []
34
43
  for page in paginator.paginate():
35
- acls.extend(page['NetworkAcls'])
44
+ acls.extend(page["NetworkAcls"])
36
45
  return acls
37
46
 
38
47
 
39
48
  def transform_network_acl_data(
40
- data_list: list[dict[str, Any]],
41
- region: str,
42
- current_aws_account_id: str,
49
+ data_list: list[dict[str, Any]],
50
+ region: str,
51
+ current_aws_account_id: str,
43
52
  ) -> Ec2AclObjects:
44
53
  network_acls = []
45
54
  inbound_rules = []
46
55
  outbound_rules = []
47
56
 
48
57
  for network_acl in data_list:
49
- network_acl_id = network_acl['NetworkAclId']
58
+ network_acl_id = network_acl["NetworkAclId"]
50
59
  base_network_acl = {
51
- 'Id': network_acl_id,
52
- 'Arn': f'arn:aws:ec2:{region}:{current_aws_account_id}:network-acl/{network_acl_id}',
53
- 'IsDefault': network_acl['IsDefault'],
54
- 'VpcId': network_acl['VpcId'],
55
- 'OwnerId': network_acl['OwnerId'],
60
+ "Id": network_acl_id,
61
+ "Arn": f"arn:aws:ec2:{region}:{current_aws_account_id}:network-acl/{network_acl_id}",
62
+ "IsDefault": network_acl["IsDefault"],
63
+ "VpcId": network_acl["VpcId"],
64
+ "OwnerId": network_acl["OwnerId"],
56
65
  }
57
- if network_acl.get('Associations') and network_acl['Associations']:
66
+ if network_acl.get("Associations") and network_acl["Associations"]:
58
67
  # Include subnet associations in the data object if they exist
59
- for association in network_acl['Associations']:
60
- base_network_acl['NetworkAclAssociationId'] = association['NetworkAclAssociationId']
61
- base_network_acl['SubnetId'] = association['SubnetId']
68
+ for association in network_acl["Associations"]:
69
+ base_network_acl["NetworkAclAssociationId"] = association[
70
+ "NetworkAclAssociationId"
71
+ ]
72
+ base_network_acl["SubnetId"] = association["SubnetId"]
62
73
  network_acls.append(base_network_acl)
63
74
  else:
64
75
  # Otherwise if there's no associations then don't include that in the data object
@@ -66,21 +77,21 @@ def transform_network_acl_data(
66
77
 
67
78
  if network_acl.get("Entries"):
68
79
  for rule in network_acl["Entries"]:
69
- direction = 'egress' if rule['Egress'] else 'inbound'
80
+ direction = "egress" if rule["Egress"] else "inbound"
70
81
  transformed_rule = {
71
- 'Id': f"{network_acl['NetworkAclId']}/{direction}/{rule['RuleNumber']}",
72
- 'CidrBlock': rule.get('CidrBlock'),
73
- 'Ipv6CidrBlock': rule.get('Ipv6CidrBlock'),
74
- 'Egress': rule['Egress'],
75
- 'Protocol': rule['Protocol'],
76
- 'RuleAction': rule['RuleAction'],
77
- 'RuleNumber': rule['RuleNumber'],
82
+ "Id": f"{network_acl['NetworkAclId']}/{direction}/{rule['RuleNumber']}",
83
+ "CidrBlock": rule.get("CidrBlock"),
84
+ "Ipv6CidrBlock": rule.get("Ipv6CidrBlock"),
85
+ "Egress": rule["Egress"],
86
+ "Protocol": rule["Protocol"],
87
+ "RuleAction": rule["RuleAction"],
88
+ "RuleNumber": rule["RuleNumber"],
78
89
  # Add pointer back to the nacl to create an edge
79
- 'NetworkAclId': network_acl_id,
80
- 'FromPort': rule.get('PortRange', {}).get('FromPort'),
81
- 'ToPort': rule.get('PortRange', {}).get('ToPort'),
90
+ "NetworkAclId": network_acl_id,
91
+ "FromPort": rule.get("PortRange", {}).get("FromPort"),
92
+ "ToPort": rule.get("PortRange", {}).get("ToPort"),
82
93
  }
83
- if transformed_rule['Egress']:
94
+ if transformed_rule["Egress"]:
84
95
  outbound_rules.append(transformed_rule)
85
96
  else:
86
97
  inbound_rules.append(transformed_rule)
@@ -93,11 +104,11 @@ def transform_network_acl_data(
93
104
 
94
105
  @timeit
95
106
  def load_all_nacl_data(
96
- neo4j_session: neo4j.Session,
97
- ec2_acl_objects: Ec2AclObjects,
98
- region: str,
99
- aws_account_id: str,
100
- update_tag: int,
107
+ neo4j_session: neo4j.Session,
108
+ ec2_acl_objects: Ec2AclObjects,
109
+ region: str,
110
+ aws_account_id: str,
111
+ update_tag: int,
101
112
  ) -> None:
102
113
  load_network_acls(
103
114
  neo4j_session,
@@ -124,11 +135,11 @@ def load_all_nacl_data(
124
135
 
125
136
  @timeit
126
137
  def load_network_acls(
127
- neo4j_session: neo4j.Session,
128
- data: list[dict[str, Any]],
129
- region: str,
130
- aws_account_id: str,
131
- update_tag: int,
138
+ neo4j_session: neo4j.Session,
139
+ data: list[dict[str, Any]],
140
+ region: str,
141
+ aws_account_id: str,
142
+ update_tag: int,
132
143
  ) -> None:
133
144
  logger.info(f"Loading {len(data)} network acls in {region}.")
134
145
  load(
@@ -143,11 +154,11 @@ def load_network_acls(
143
154
 
144
155
  @timeit
145
156
  def load_network_acl_inbound_rules(
146
- neo4j_session: neo4j.Session,
147
- data: list[dict[str, Any]],
148
- region: str,
149
- aws_account_id: str,
150
- update_tag: int,
157
+ neo4j_session: neo4j.Session,
158
+ data: list[dict[str, Any]],
159
+ region: str,
160
+ aws_account_id: str,
161
+ update_tag: int,
151
162
  ) -> None:
152
163
  logger.info(f"Loading {len(data)} network acl inbound rules in {region}.")
153
164
  load(
@@ -162,11 +173,11 @@ def load_network_acl_inbound_rules(
162
173
 
163
174
  @timeit
164
175
  def load_network_acl_egress_rules(
165
- neo4j_session: neo4j.Session,
166
- data: list[dict[str, Any]],
167
- region: str,
168
- aws_account_id: str,
169
- update_tag: int,
176
+ neo4j_session: neo4j.Session,
177
+ data: list[dict[str, Any]],
178
+ region: str,
179
+ aws_account_id: str,
180
+ update_tag: int,
170
181
  ) -> None:
171
182
  logger.info(f"Loading {len(data)} network acl egress rules in {region}.")
172
183
  load(
@@ -180,23 +191,36 @@ def load_network_acl_egress_rules(
180
191
 
181
192
 
182
193
  @timeit
183
- def cleanup_network_acls(neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
184
- GraphJob.from_node_schema(EC2NetworkAclSchema(), common_job_parameters).run(neo4j_session)
185
- GraphJob.from_node_schema(EC2NetworkAclInboundRuleSchema(), common_job_parameters).run(neo4j_session)
186
- GraphJob.from_node_schema(EC2NetworkAclEgressRuleSchema(), common_job_parameters).run(neo4j_session)
194
+ def cleanup_network_acls(
195
+ neo4j_session: neo4j.Session,
196
+ common_job_parameters: dict[str, Any],
197
+ ) -> None:
198
+ GraphJob.from_node_schema(EC2NetworkAclSchema(), common_job_parameters).run(
199
+ neo4j_session,
200
+ )
201
+ GraphJob.from_node_schema(
202
+ EC2NetworkAclInboundRuleSchema(),
203
+ common_job_parameters,
204
+ ).run(neo4j_session)
205
+ GraphJob.from_node_schema(
206
+ EC2NetworkAclEgressRuleSchema(),
207
+ common_job_parameters,
208
+ ).run(neo4j_session)
187
209
 
188
210
 
189
211
  @timeit
190
212
  def sync_network_acls(
191
- neo4j_session: neo4j.Session,
192
- boto3_session: boto3.session.Session,
193
- regions: list[str],
194
- current_aws_account_id: str,
195
- update_tag: int,
196
- common_job_parameters: dict[str, Any],
213
+ neo4j_session: neo4j.Session,
214
+ boto3_session: boto3.session.Session,
215
+ regions: list[str],
216
+ current_aws_account_id: str,
217
+ update_tag: int,
218
+ common_job_parameters: dict[str, Any],
197
219
  ) -> None:
198
220
  for region in regions:
199
- logger.info(f"Syncing EC2 network ACLs for region '{region}' in account '{current_aws_account_id}'.")
221
+ logger.info(
222
+ f"Syncing EC2 network ACLs for region '{region}' in account '{current_aws_account_id}'.",
223
+ )
200
224
  data = get_network_acl_data(boto3_session, region)
201
225
  ec2_acl_data = transform_network_acl_data(data, region, current_aws_account_id)
202
226
  load_all_nacl_data(
@@ -8,20 +8,28 @@ from typing import List
8
8
  import boto3
9
9
  import neo4j
10
10
 
11
- from .util import get_botocore_config
12
11
  from cartography.client.core.tx import load
13
12
  from cartography.graph.job import GraphJob
14
13
  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
14
+ from cartography.models.aws.ec2.privateip_networkinterface import (
15
+ EC2PrivateIpNetworkInterfaceSchema,
16
+ )
17
+ from cartography.models.aws.ec2.securitygroup_networkinterface import (
18
+ EC2SecurityGroupNetworkInterfaceSchema,
19
+ )
20
+ from cartography.models.aws.ec2.subnet_networkinterface import (
21
+ EC2SubnetNetworkInterfaceSchema,
22
+ )
18
23
  from cartography.util import aws_handle_regions
19
24
  from cartography.util import timeit
20
25
 
26
+ from .util import get_botocore_config
27
+
21
28
  logger = logging.getLogger(__name__)
22
29
 
23
30
  Ec2NetworkData = namedtuple(
24
- "Ec2NetworkData", [
31
+ "Ec2NetworkData",
32
+ [
25
33
  "network_interface_list",
26
34
  "private_ip_list",
27
35
  "sg_list",
@@ -32,16 +40,26 @@ Ec2NetworkData = namedtuple(
32
40
 
33
41
  @timeit
34
42
  @aws_handle_regions
35
- def get_network_interface_data(boto3_session: boto3.session.Session, region: str) -> List[Dict[str, Any]]:
36
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
37
- paginator = client.get_paginator('describe_network_interfaces')
43
+ def get_network_interface_data(
44
+ boto3_session: boto3.session.Session,
45
+ region: str,
46
+ ) -> List[Dict[str, Any]]:
47
+ client = boto3_session.client(
48
+ "ec2",
49
+ region_name=region,
50
+ config=get_botocore_config(),
51
+ )
52
+ paginator = client.get_paginator("describe_network_interfaces")
38
53
  subnets: List[Dict] = []
39
54
  for page in paginator.paginate():
40
- subnets.extend(page['NetworkInterfaces'])
55
+ subnets.extend(page["NetworkInterfaces"])
41
56
  return subnets
42
57
 
43
58
 
44
- def transform_network_interface_data(data_list: List[Dict[str, Any]], region: str) -> Ec2NetworkData:
59
+ def transform_network_interface_data(
60
+ data_list: List[Dict[str, Any]],
61
+ region: str,
62
+ ) -> Ec2NetworkData:
45
63
  network_interface_list = []
46
64
  private_ip_list = []
47
65
  sg_list = []
@@ -52,45 +70,52 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
52
70
  # https://aws.amazon.com/premiumsupport/knowledge-center/elb-find-load-balancer-IP/
53
71
  elb_v1_id = None
54
72
  elb_v2_id = None
55
- elb_match = re.match(r'^ELB (?:net|app)/([^\/]+)\/(.*)', network_interface.get('Description', ''))
73
+ elb_match = re.match(
74
+ r"^ELB (?:net|app)/([^\/]+)\/(.*)",
75
+ network_interface.get("Description", ""),
76
+ )
56
77
  if elb_match:
57
- elb_v1_id = f'{elb_match[1]}-{elb_match[2]}.elb.{region}.amazonaws.com'
78
+ elb_v1_id = f"{elb_match[1]}-{elb_match[2]}.elb.{region}.amazonaws.com"
58
79
  else:
59
- elb_match = re.match(r'^ELB (.*)', network_interface.get('Description', ''))
80
+ elb_match = re.match(r"^ELB (.*)", network_interface.get("Description", ""))
60
81
  if elb_match:
61
82
  elb_v2_id = elb_match[1]
62
83
  # TODO issue #1024 change this to arn when ready
63
- network_interface_id = network_interface['NetworkInterfaceId']
84
+ network_interface_id = network_interface["NetworkInterfaceId"]
64
85
  network_interface_list.append(
65
86
  {
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.get('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,
87
+ "Id": network_interface_id,
88
+ "NetworkInterfaceId": network_interface["NetworkInterfaceId"],
89
+ "Description": network_interface["Description"],
90
+ "InstanceId": network_interface.get("Attachment", {}).get("InstanceId"),
91
+ "InterfaceType": network_interface["InterfaceType"],
92
+ "MacAddress": network_interface["MacAddress"],
93
+ "PrivateDnsName": network_interface.get("PrivateDnsName"),
94
+ "PrivateIpAddress": network_interface["PrivateIpAddress"],
95
+ "PublicIp": network_interface.get("Association", {}).get("PublicIp"),
96
+ "RequesterId": network_interface.get("RequesterId"),
97
+ "RequesterManaged": network_interface["RequesterManaged"],
98
+ "SourceDestCheck": network_interface["SourceDestCheck"],
99
+ "Status": network_interface["Status"],
100
+ "SubnetId": network_interface["SubnetId"],
101
+ "ElbV1Id": elb_v1_id,
102
+ "ElbV2Id": elb_v2_id,
82
103
  },
83
104
  )
84
- if network_interface.get('PrivateIpAddresses'):
85
- for private_ip_address in network_interface['PrivateIpAddresses']:
105
+ if network_interface.get("PrivateIpAddresses"):
106
+ for private_ip_address in network_interface["PrivateIpAddresses"]:
86
107
  private_ip_list.append(
87
108
  {
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'),
109
+ "Id": f"{network_interface['NetworkInterfaceId']}:{private_ip_address['PrivateIpAddress']}",
110
+ "NetworkInterfaceId": network_interface["NetworkInterfaceId"],
111
+ "IpOwnerId": private_ip_address.get("Association", {}).get(
112
+ "IpOwnerId",
113
+ ),
114
+ "Primary": private_ip_address["Primary"],
115
+ "PrivateIpAddress": private_ip_address["PrivateIpAddress"],
116
+ "PublicIp": private_ip_address.get("Association", {}).get(
117
+ "PublicIp",
118
+ ),
94
119
  },
95
120
  )
96
121
 
@@ -98,19 +123,19 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
98
123
  for group in network_interface["Groups"]:
99
124
  sg_list.append(
100
125
  {
101
- 'GroupId': group['GroupId'],
102
- 'NetworkInterfaceId': network_interface_id,
126
+ "GroupId": group["GroupId"],
127
+ "NetworkInterfaceId": network_interface_id,
103
128
  },
104
129
  )
105
130
 
106
- subnet_id = network_interface.get('SubnetId')
131
+ subnet_id = network_interface.get("SubnetId")
107
132
  if subnet_id:
108
133
  subnet_list.append(
109
134
  {
110
- 'NetworkInterfaceId': network_interface_id,
111
- 'SubnetId': subnet_id,
112
- 'ElbV1Id': elb_v1_id,
113
- 'ElbV2Id': elb_v2_id,
135
+ "NetworkInterfaceId": network_interface_id,
136
+ "SubnetId": subnet_id,
137
+ "ElbV1Id": elb_v1_id,
138
+ "ElbV2Id": elb_v2_id,
114
139
  },
115
140
  )
116
141
 
@@ -124,11 +149,11 @@ def transform_network_interface_data(data_list: List[Dict[str, Any]], region: st
124
149
 
125
150
  @timeit
126
151
  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,
152
+ neo4j_session: neo4j.Session,
153
+ data: List[Dict[str, Any]],
154
+ region: str,
155
+ aws_account_id: str,
156
+ update_tag: int,
132
157
  ) -> None:
133
158
  logger.info(f"Loading {len(data)} network interfaces in {region}.")
134
159
  load(
@@ -143,11 +168,11 @@ def load_network_interfaces(
143
168
 
144
169
  @timeit
145
170
  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,
171
+ neo4j_session: neo4j.Session,
172
+ data: List[Dict[str, Any]],
173
+ region: str,
174
+ aws_account_id: str,
175
+ update_tag: int,
151
176
  ) -> None:
152
177
  """
153
178
  Private IPs as known by describe-network-interfaces.
@@ -165,11 +190,11 @@ def load_private_ip_network_interface(
165
190
 
166
191
  @timeit
167
192
  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,
193
+ neo4j_session: neo4j.Session,
194
+ data: List[Dict[str, Any]],
195
+ region: str,
196
+ aws_account_id: str,
197
+ update_tag: int,
173
198
  ) -> None:
174
199
  """
175
200
  Security groups as known by describe-network-interfaces.
@@ -187,11 +212,11 @@ def load_security_group_network_interface(
187
212
 
188
213
  @timeit
189
214
  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,
215
+ neo4j_session: neo4j.Session,
216
+ data: List[Dict[str, Any]],
217
+ region: str,
218
+ aws_account_id: str,
219
+ update_tag: int,
195
220
  ) -> None:
196
221
  """
197
222
  Subnets as known by describe-network-interfaces.
@@ -208,38 +233,72 @@ def load_subnet_network_interface(
208
233
 
209
234
 
210
235
  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]],
236
+ neo4j_session: neo4j.Session,
237
+ region: str,
238
+ current_aws_account_id: str,
239
+ update_tag: int,
240
+ network_interface_list: List[Dict[str, Any]],
241
+ private_ip_list: List[Dict[str, Any]],
242
+ subnet_list: List[Dict[str, Any]],
243
+ sg_list: List[Dict[str, Any]],
219
244
  ) -> 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)
245
+ load_network_interfaces(
246
+ neo4j_session,
247
+ network_interface_list,
248
+ region,
249
+ current_aws_account_id,
250
+ update_tag,
251
+ )
252
+ load_private_ip_network_interface(
253
+ neo4j_session,
254
+ private_ip_list,
255
+ region,
256
+ current_aws_account_id,
257
+ update_tag,
258
+ )
259
+ load_subnet_network_interface(
260
+ neo4j_session,
261
+ subnet_list,
262
+ region,
263
+ current_aws_account_id,
264
+ update_tag,
265
+ )
266
+ load_security_group_network_interface(
267
+ neo4j_session,
268
+ sg_list,
269
+ region,
270
+ current_aws_account_id,
271
+ update_tag,
272
+ )
224
273
 
225
274
 
226
275
  @timeit
227
- def cleanup_network_interfaces(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
228
- GraphJob.from_node_schema(EC2NetworkInterfaceSchema(), common_job_parameters).run(neo4j_session)
229
- GraphJob.from_node_schema(EC2PrivateIpNetworkInterfaceSchema(), common_job_parameters).run(neo4j_session)
276
+ def cleanup_network_interfaces(
277
+ neo4j_session: neo4j.Session,
278
+ common_job_parameters: Dict,
279
+ ) -> None:
280
+ GraphJob.from_node_schema(EC2NetworkInterfaceSchema(), common_job_parameters).run(
281
+ neo4j_session,
282
+ )
283
+ GraphJob.from_node_schema(
284
+ EC2PrivateIpNetworkInterfaceSchema(),
285
+ common_job_parameters,
286
+ ).run(neo4j_session)
230
287
 
231
288
 
232
289
  @timeit
233
290
  def sync_network_interfaces(
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,
291
+ neo4j_session: neo4j.Session,
292
+ boto3_session: boto3.session.Session,
293
+ regions: List[str],
294
+ current_aws_account_id: str,
295
+ update_tag: int,
296
+ common_job_parameters: Dict,
240
297
  ) -> None:
241
298
  for region in regions:
242
- logger.info(f"Syncing EC2 network interfaces for region '{region}' in account '{current_aws_account_id}'.")
299
+ logger.info(
300
+ f"Syncing EC2 network interfaces for region '{region}' in account '{current_aws_account_id}'.",
301
+ )
243
302
  data = get_network_interface_data(boto3_session, region)
244
303
  ec2_network_data = transform_network_interface_data(data, region)
245
304
  load_network_data(