cartography 0.102.0rc2__py3-none-any.whl → 0.103.0__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 (297) hide show
  1. cartography/__main__.py +1 -2
  2. cartography/_version.py +2 -2
  3. cartography/cli.py +376 -249
  4. cartography/client/core/tx.py +39 -18
  5. cartography/config.py +28 -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/cloudwatch.py +93 -0
  23. cartography/intel/aws/config.py +56 -20
  24. cartography/intel/aws/dynamodb.py +108 -40
  25. cartography/intel/aws/ec2/__init__.py +2 -2
  26. cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
  27. cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
  28. cartography/intel/aws/ec2/images.py +49 -20
  29. cartography/intel/aws/ec2/instances.py +234 -136
  30. cartography/intel/aws/ec2/internet_gateways.py +40 -11
  31. cartography/intel/aws/ec2/key_pairs.py +44 -20
  32. cartography/intel/aws/ec2/launch_templates.py +101 -59
  33. cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
  34. cartography/intel/aws/ec2/load_balancers.py +82 -42
  35. cartography/intel/aws/ec2/network_acls.py +89 -65
  36. cartography/intel/aws/ec2/network_interfaces.py +146 -87
  37. cartography/intel/aws/ec2/reserved_instances.py +45 -16
  38. cartography/intel/aws/ec2/route_tables.py +138 -98
  39. cartography/intel/aws/ec2/security_groups.py +71 -21
  40. cartography/intel/aws/ec2/snapshots.py +61 -22
  41. cartography/intel/aws/ec2/subnets.py +54 -18
  42. cartography/intel/aws/ec2/tgw.py +100 -34
  43. cartography/intel/aws/ec2/util.py +1 -1
  44. cartography/intel/aws/ec2/volumes.py +69 -41
  45. cartography/intel/aws/ec2/vpc.py +37 -12
  46. cartography/intel/aws/ec2/vpc_peerings.py +83 -24
  47. cartography/intel/aws/ecr.py +88 -32
  48. cartography/intel/aws/ecs.py +83 -47
  49. cartography/intel/aws/efs.py +93 -0
  50. cartography/intel/aws/eks.py +55 -29
  51. cartography/intel/aws/elasticache.py +42 -18
  52. cartography/intel/aws/elasticsearch.py +57 -20
  53. cartography/intel/aws/emr.py +61 -23
  54. cartography/intel/aws/iam.py +401 -145
  55. cartography/intel/aws/iam_instance_profiles.py +22 -22
  56. cartography/intel/aws/identitycenter.py +71 -37
  57. cartography/intel/aws/inspector.py +159 -89
  58. cartography/intel/aws/kms.py +92 -38
  59. cartography/intel/aws/lambda_function.py +103 -34
  60. cartography/intel/aws/organizations.py +30 -10
  61. cartography/intel/aws/permission_relationships.py +133 -51
  62. cartography/intel/aws/rds.py +249 -85
  63. cartography/intel/aws/redshift.py +107 -46
  64. cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
  65. cartography/intel/aws/resources.py +57 -46
  66. cartography/intel/aws/route53.py +108 -61
  67. cartography/intel/aws/s3.py +168 -83
  68. cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
  69. cartography/intel/aws/secretsmanager.py +24 -12
  70. cartography/intel/aws/securityhub.py +20 -9
  71. cartography/intel/aws/sns.py +166 -0
  72. cartography/intel/aws/sqs.py +60 -28
  73. cartography/intel/aws/ssm.py +70 -30
  74. cartography/intel/aws/util/arns.py +7 -7
  75. cartography/intel/aws/util/common.py +31 -4
  76. cartography/intel/azure/__init__.py +78 -19
  77. cartography/intel/azure/compute.py +101 -27
  78. cartography/intel/azure/cosmosdb.py +496 -170
  79. cartography/intel/azure/sql.py +296 -105
  80. cartography/intel/azure/storage.py +322 -113
  81. cartography/intel/azure/subscription.py +39 -23
  82. cartography/intel/azure/tenant.py +13 -4
  83. cartography/intel/azure/util/credentials.py +95 -55
  84. cartography/intel/bigfix/__init__.py +2 -2
  85. cartography/intel/bigfix/computers.py +93 -65
  86. cartography/intel/cloudflare/__init__.py +74 -0
  87. cartography/intel/cloudflare/accounts.py +57 -0
  88. cartography/intel/cloudflare/dnsrecords.py +64 -0
  89. cartography/intel/cloudflare/members.py +75 -0
  90. cartography/intel/cloudflare/roles.py +65 -0
  91. cartography/intel/cloudflare/zones.py +64 -0
  92. cartography/intel/create_indexes.py +3 -2
  93. cartography/intel/crowdstrike/__init__.py +11 -9
  94. cartography/intel/crowdstrike/endpoints.py +5 -1
  95. cartography/intel/crowdstrike/spotlight.py +8 -3
  96. cartography/intel/cve/__init__.py +46 -13
  97. cartography/intel/cve/feed.py +48 -12
  98. cartography/intel/digitalocean/__init__.py +22 -13
  99. cartography/intel/digitalocean/compute.py +75 -108
  100. cartography/intel/digitalocean/management.py +44 -80
  101. cartography/intel/digitalocean/platform.py +48 -43
  102. cartography/intel/dns.py +36 -10
  103. cartography/intel/duo/__init__.py +21 -16
  104. cartography/intel/duo/api_host.py +14 -9
  105. cartography/intel/duo/endpoints.py +50 -45
  106. cartography/intel/duo/groups.py +18 -14
  107. cartography/intel/duo/phones.py +37 -34
  108. cartography/intel/duo/tokens.py +26 -23
  109. cartography/intel/duo/users.py +54 -50
  110. cartography/intel/duo/web_authn_credentials.py +30 -25
  111. cartography/intel/entra/__init__.py +25 -7
  112. cartography/intel/entra/ou.py +112 -0
  113. cartography/intel/entra/users.py +69 -63
  114. cartography/intel/gcp/__init__.py +185 -49
  115. cartography/intel/gcp/compute.py +418 -231
  116. cartography/intel/gcp/crm.py +96 -43
  117. cartography/intel/gcp/dns.py +60 -19
  118. cartography/intel/gcp/gke.py +72 -38
  119. cartography/intel/gcp/iam.py +61 -41
  120. cartography/intel/gcp/storage.py +84 -55
  121. cartography/intel/github/__init__.py +13 -11
  122. cartography/intel/github/repos.py +270 -137
  123. cartography/intel/github/teams.py +170 -88
  124. cartography/intel/github/users.py +70 -39
  125. cartography/intel/github/util.py +36 -34
  126. cartography/intel/gsuite/__init__.py +47 -26
  127. cartography/intel/gsuite/api.py +73 -30
  128. cartography/intel/jamf/__init__.py +19 -1
  129. cartography/intel/jamf/computers.py +30 -7
  130. cartography/intel/jamf/util.py +7 -2
  131. cartography/intel/kandji/__init__.py +6 -3
  132. cartography/intel/kandji/devices.py +14 -8
  133. cartography/intel/kubernetes/namespaces.py +7 -4
  134. cartography/intel/kubernetes/pods.py +7 -4
  135. cartography/intel/kubernetes/services.py +8 -4
  136. cartography/intel/lastpass/__init__.py +2 -2
  137. cartography/intel/lastpass/users.py +23 -12
  138. cartography/intel/oci/__init__.py +44 -11
  139. cartography/intel/oci/iam.py +134 -38
  140. cartography/intel/oci/organizations.py +13 -6
  141. cartography/intel/oci/utils.py +43 -20
  142. cartography/intel/okta/__init__.py +66 -15
  143. cartography/intel/okta/applications.py +42 -20
  144. cartography/intel/okta/awssaml.py +93 -33
  145. cartography/intel/okta/factors.py +16 -4
  146. cartography/intel/okta/groups.py +56 -29
  147. cartography/intel/okta/organization.py +5 -1
  148. cartography/intel/okta/origins.py +6 -2
  149. cartography/intel/okta/roles.py +15 -5
  150. cartography/intel/okta/users.py +20 -8
  151. cartography/intel/okta/utils.py +6 -4
  152. cartography/intel/openai/__init__.py +86 -0
  153. cartography/intel/openai/adminapikeys.py +90 -0
  154. cartography/intel/openai/apikeys.py +96 -0
  155. cartography/intel/openai/projects.py +94 -0
  156. cartography/intel/openai/serviceaccounts.py +82 -0
  157. cartography/intel/openai/users.py +78 -0
  158. cartography/intel/openai/util.py +29 -0
  159. cartography/intel/pagerduty/__init__.py +8 -7
  160. cartography/intel/pagerduty/escalation_policies.py +18 -6
  161. cartography/intel/pagerduty/schedules.py +12 -4
  162. cartography/intel/pagerduty/services.py +11 -4
  163. cartography/intel/pagerduty/teams.py +8 -3
  164. cartography/intel/pagerduty/users.py +3 -1
  165. cartography/intel/pagerduty/vendors.py +3 -1
  166. cartography/intel/semgrep/__init__.py +24 -6
  167. cartography/intel/semgrep/dependencies.py +50 -28
  168. cartography/intel/semgrep/deployment.py +3 -1
  169. cartography/intel/semgrep/findings.py +42 -18
  170. cartography/intel/snipeit/__init__.py +17 -3
  171. cartography/intel/snipeit/asset.py +12 -6
  172. cartography/intel/snipeit/user.py +8 -5
  173. cartography/intel/snipeit/util.py +9 -4
  174. cartography/intel/tailscale/__init__.py +77 -0
  175. cartography/intel/tailscale/acls.py +146 -0
  176. cartography/intel/tailscale/devices.py +127 -0
  177. cartography/intel/tailscale/postureintegrations.py +81 -0
  178. cartography/intel/tailscale/tailnets.py +76 -0
  179. cartography/intel/tailscale/users.py +80 -0
  180. cartography/intel/tailscale/utils.py +132 -0
  181. cartography/models/aws/apigateway.py +21 -17
  182. cartography/models/aws/apigatewaycertificate.py +28 -22
  183. cartography/models/aws/apigatewayresource.py +28 -20
  184. cartography/models/aws/apigatewaystage.py +33 -25
  185. cartography/models/aws/cloudtrail/__init__.py +0 -0
  186. cartography/models/aws/cloudtrail/trail.py +61 -0
  187. cartography/models/aws/cloudwatch/__init__.py +0 -0
  188. cartography/models/aws/cloudwatch/loggroup.py +52 -0
  189. cartography/models/aws/dynamodb/gsi.py +30 -22
  190. cartography/models/aws/dynamodb/tables.py +25 -17
  191. cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
  192. cartography/models/aws/ec2/images.py +36 -34
  193. cartography/models/aws/ec2/instances.py +51 -45
  194. cartography/models/aws/ec2/keypair.py +21 -16
  195. cartography/models/aws/ec2/keypair_instance.py +28 -21
  196. cartography/models/aws/ec2/launch_configurations.py +30 -26
  197. cartography/models/aws/ec2/launch_template_versions.py +48 -38
  198. cartography/models/aws/ec2/launch_templates.py +21 -17
  199. cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
  200. cartography/models/aws/ec2/load_balancers.py +47 -37
  201. cartography/models/aws/ec2/network_acl_rules.py +38 -30
  202. cartography/models/aws/ec2/network_acls.py +38 -29
  203. cartography/models/aws/ec2/networkinterface_instance.py +52 -39
  204. cartography/models/aws/ec2/networkinterfaces.py +53 -37
  205. cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
  206. cartography/models/aws/ec2/reservations.py +18 -14
  207. cartography/models/aws/ec2/route_table_associations.py +44 -34
  208. cartography/models/aws/ec2/route_tables.py +50 -43
  209. cartography/models/aws/ec2/routes.py +45 -37
  210. cartography/models/aws/ec2/securitygroup_instance.py +29 -20
  211. cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
  212. cartography/models/aws/ec2/subnet_instance.py +24 -19
  213. cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
  214. cartography/models/aws/ec2/volumes.py +47 -40
  215. cartography/models/aws/efs/__init__.py +0 -0
  216. cartography/models/aws/efs/mount_target.py +52 -0
  217. cartography/models/aws/eks/clusters.py +23 -21
  218. cartography/models/aws/emr.py +32 -30
  219. cartography/models/aws/iam/instanceprofile.py +33 -24
  220. cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
  221. cartography/models/aws/identitycenter/awspermissionset.py +37 -29
  222. cartography/models/aws/identitycenter/awsssouser.py +23 -21
  223. cartography/models/aws/inspector/findings.py +77 -65
  224. cartography/models/aws/inspector/packages.py +35 -29
  225. cartography/models/aws/s3/__init__.py +0 -0
  226. cartography/models/aws/s3/account_public_access_block.py +51 -0
  227. cartography/models/aws/sns/__init__.py +0 -0
  228. cartography/models/aws/sns/topic.py +50 -0
  229. cartography/models/aws/ssm/instance_information.py +51 -39
  230. cartography/models/aws/ssm/instance_patch.py +32 -26
  231. cartography/models/bigfix/bigfix_computer.py +42 -38
  232. cartography/models/bigfix/bigfix_root.py +3 -3
  233. cartography/models/cloudflare/__init__.py +0 -0
  234. cartography/models/cloudflare/account.py +25 -0
  235. cartography/models/cloudflare/dnsrecord.py +55 -0
  236. cartography/models/cloudflare/member.py +82 -0
  237. cartography/models/cloudflare/role.py +44 -0
  238. cartography/models/cloudflare/zone.py +59 -0
  239. cartography/models/core/common.py +12 -10
  240. cartography/models/core/nodes.py +5 -2
  241. cartography/models/core/relationships.py +14 -6
  242. cartography/models/crowdstrike/hosts.py +37 -35
  243. cartography/models/cve/cve.py +34 -32
  244. cartography/models/cve/cve_feed.py +6 -6
  245. cartography/models/digitalocean/__init__.py +0 -0
  246. cartography/models/digitalocean/account.py +21 -0
  247. cartography/models/digitalocean/droplet.py +56 -0
  248. cartography/models/digitalocean/project.py +48 -0
  249. cartography/models/duo/api_host.py +3 -3
  250. cartography/models/duo/endpoint.py +43 -41
  251. cartography/models/duo/group.py +14 -14
  252. cartography/models/duo/phone.py +27 -27
  253. cartography/models/duo/token.py +16 -16
  254. cartography/models/duo/user.py +46 -44
  255. cartography/models/duo/web_authn_credential.py +27 -19
  256. cartography/models/entra/ou.py +48 -0
  257. cartography/models/entra/tenant.py +24 -18
  258. cartography/models/entra/user.py +64 -48
  259. cartography/models/gcp/iam.py +23 -23
  260. cartography/models/github/orgs.py +5 -4
  261. cartography/models/github/teams.py +37 -31
  262. cartography/models/github/users.py +34 -23
  263. cartography/models/kandji/device.py +22 -16
  264. cartography/models/kandji/tenant.py +6 -4
  265. cartography/models/lastpass/tenant.py +3 -3
  266. cartography/models/lastpass/user.py +32 -28
  267. cartography/models/openai/__init__.py +0 -0
  268. cartography/models/openai/adminapikey.py +90 -0
  269. cartography/models/openai/apikey.py +84 -0
  270. cartography/models/openai/organization.py +17 -0
  271. cartography/models/openai/project.py +70 -0
  272. cartography/models/openai/serviceaccount.py +50 -0
  273. cartography/models/openai/user.py +49 -0
  274. cartography/models/semgrep/dependencies.py +36 -24
  275. cartography/models/semgrep/deployment.py +5 -5
  276. cartography/models/semgrep/findings.py +58 -42
  277. cartography/models/semgrep/locations.py +27 -21
  278. cartography/models/snipeit/asset.py +30 -21
  279. cartography/models/snipeit/tenant.py +6 -4
  280. cartography/models/snipeit/user.py +19 -12
  281. cartography/models/tailscale/__init__.py +0 -0
  282. cartography/models/tailscale/device.py +95 -0
  283. cartography/models/tailscale/group.py +86 -0
  284. cartography/models/tailscale/postureintegration.py +58 -0
  285. cartography/models/tailscale/tag.py +102 -0
  286. cartography/models/tailscale/tailnet.py +29 -0
  287. cartography/models/tailscale/user.py +52 -0
  288. cartography/stats.py +3 -3
  289. cartography/sync.py +113 -31
  290. cartography/util.py +84 -62
  291. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/METADATA +8 -15
  292. cartography-0.103.0.dist-info/RECORD +442 -0
  293. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
  294. cartography-0.102.0rc2.dist-info/RECORD +0 -381
  295. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
  296. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
  297. {cartography-0.102.0rc2.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,6 @@ import logging
3
3
  import boto3
4
4
  import neo4j
5
5
 
6
- from .util import get_botocore_config
7
6
  from cartography.client.core.tx import load
8
7
  from cartography.graph.job import GraphJob
9
8
  from cartography.models.aws.ec2.load_balancer_listeners import ELBListenerSchema
@@ -11,6 +10,8 @@ from cartography.models.aws.ec2.load_balancers import LoadBalancerSchema
11
10
  from cartography.util import aws_handle_regions
12
11
  from cartography.util import timeit
13
12
 
13
+ from .util import get_botocore_config
14
+
14
15
  logger = logging.getLogger(__name__)
15
16
 
16
17
 
@@ -29,7 +30,9 @@ def _get_listener_id(load_balancer_id: str, port: int, protocol: str) -> str:
29
30
  return f"{load_balancer_id}{port}{protocol}"
30
31
 
31
32
 
32
- def transform_load_balancer_listener_data(load_balancer_id: str, listener_data: list[dict]) -> list[dict]:
33
+ def transform_load_balancer_listener_data(
34
+ load_balancer_id: str, listener_data: list[dict]
35
+ ) -> list[dict]:
33
36
  """
34
37
  Transform load balancer listener data into a format suitable for cartography ingestion.
35
38
 
@@ -42,21 +45,27 @@ def transform_load_balancer_listener_data(load_balancer_id: str, listener_data:
42
45
  """
43
46
  transformed = []
44
47
  for listener in listener_data:
45
- listener_info = listener['Listener']
48
+ listener_info = listener["Listener"]
46
49
  transformed_listener = {
47
- 'id': _get_listener_id(load_balancer_id, listener_info['LoadBalancerPort'], listener_info['Protocol']),
48
- 'port': listener_info.get('LoadBalancerPort'),
49
- 'protocol': listener_info.get('Protocol'),
50
- 'instance_port': listener_info.get('InstancePort'),
51
- 'instance_protocol': listener_info.get('InstanceProtocol'),
52
- 'policy_names': listener.get('PolicyNames', []),
53
- 'LoadBalancerId': load_balancer_id,
50
+ "id": _get_listener_id(
51
+ load_balancer_id,
52
+ listener_info["LoadBalancerPort"],
53
+ listener_info["Protocol"],
54
+ ),
55
+ "port": listener_info.get("LoadBalancerPort"),
56
+ "protocol": listener_info.get("Protocol"),
57
+ "instance_port": listener_info.get("InstancePort"),
58
+ "instance_protocol": listener_info.get("InstanceProtocol"),
59
+ "policy_names": listener.get("PolicyNames", []),
60
+ "LoadBalancerId": load_balancer_id,
54
61
  }
55
62
  transformed.append(transformed_listener)
56
63
  return transformed
57
64
 
58
65
 
59
- def transform_load_balancer_data(load_balancers: list[dict]) -> tuple[list[dict], list[dict]]:
66
+ def transform_load_balancer_data(
67
+ load_balancers: list[dict],
68
+ ) -> tuple[list[dict], list[dict]]:
60
69
  """
61
70
  Transform load balancer data into a format suitable for cartography ingestion.
62
71
 
@@ -70,35 +79,38 @@ def transform_load_balancer_data(load_balancers: list[dict]) -> tuple[list[dict]
70
79
  listener_data = []
71
80
 
72
81
  for lb in load_balancers:
73
- load_balancer_id = lb['DNSName']
82
+ load_balancer_id = lb["DNSName"]
74
83
  transformed_lb = {
75
- 'id': load_balancer_id,
76
- 'name': lb['LoadBalancerName'],
77
- 'dnsname': lb['DNSName'],
78
- 'canonicalhostedzonename': lb.get('CanonicalHostedZoneName'),
79
- 'canonicalhostedzonenameid': lb.get('CanonicalHostedZoneNameID'),
80
- 'scheme': lb.get('Scheme'),
81
- 'createdtime': str(lb['CreatedTime']),
82
- 'GROUP_NAME': lb.get('SourceSecurityGroup', {}).get('GroupName'),
83
- 'GROUP_IDS': [str(group) for group in lb.get('SecurityGroups', [])],
84
- 'INSTANCE_IDS': [instance['InstanceId'] for instance in lb.get('Instances', [])],
85
- 'LISTENER_IDS': [
84
+ "id": load_balancer_id,
85
+ "name": lb["LoadBalancerName"],
86
+ "dnsname": lb["DNSName"],
87
+ "canonicalhostedzonename": lb.get("CanonicalHostedZoneName"),
88
+ "canonicalhostedzonenameid": lb.get("CanonicalHostedZoneNameID"),
89
+ "scheme": lb.get("Scheme"),
90
+ "createdtime": str(lb["CreatedTime"]),
91
+ "GROUP_NAME": lb.get("SourceSecurityGroup", {}).get("GroupName"),
92
+ "GROUP_IDS": [str(group) for group in lb.get("SecurityGroups", [])],
93
+ "INSTANCE_IDS": [
94
+ instance["InstanceId"] for instance in lb.get("Instances", [])
95
+ ],
96
+ "LISTENER_IDS": [
86
97
  _get_listener_id(
87
98
  load_balancer_id,
88
- listener['Listener']['LoadBalancerPort'],
89
- listener['Listener']['Protocol'],
90
- ) for listener in lb.get('ListenerDescriptions', [])
99
+ listener["Listener"]["LoadBalancerPort"],
100
+ listener["Listener"]["Protocol"],
101
+ )
102
+ for listener in lb.get("ListenerDescriptions", [])
91
103
  ],
92
104
  }
93
105
  transformed.append(transformed_lb)
94
106
 
95
107
  # Classic ELB listeners are not returned anywhere else in AWS, so we must parse them out
96
108
  # of the describe_load_balancers response.
97
- if lb.get('ListenerDescriptions'):
109
+ if lb.get("ListenerDescriptions"):
98
110
  listener_data.extend(
99
111
  transform_load_balancer_listener_data(
100
112
  load_balancer_id,
101
- lb.get('ListenerDescriptions', []),
113
+ lb.get("ListenerDescriptions", []),
102
114
  ),
103
115
  )
104
116
 
@@ -107,18 +119,25 @@ def transform_load_balancer_data(load_balancers: list[dict]) -> tuple[list[dict]
107
119
 
108
120
  @timeit
109
121
  @aws_handle_regions
110
- def get_loadbalancer_data(boto3_session: boto3.session.Session, region: str) -> list[dict]:
111
- client = boto3_session.client('elb', region_name=region, config=get_botocore_config())
112
- paginator = client.get_paginator('describe_load_balancers')
122
+ def get_loadbalancer_data(
123
+ boto3_session: boto3.session.Session, region: str
124
+ ) -> list[dict]:
125
+ client = boto3_session.client(
126
+ "elb", region_name=region, config=get_botocore_config()
127
+ )
128
+ paginator = client.get_paginator("describe_load_balancers")
113
129
  elbs: list[dict] = []
114
130
  for page in paginator.paginate():
115
- elbs.extend(page['LoadBalancerDescriptions'])
131
+ elbs.extend(page["LoadBalancerDescriptions"])
116
132
  return elbs
117
133
 
118
134
 
119
135
  @timeit
120
136
  def load_load_balancers(
121
- neo4j_session: neo4j.Session, data: list[dict], region: str, current_aws_account_id: str,
137
+ neo4j_session: neo4j.Session,
138
+ data: list[dict],
139
+ region: str,
140
+ current_aws_account_id: str,
122
141
  update_tag: int,
123
142
  ) -> None:
124
143
  load(
@@ -133,7 +152,10 @@ def load_load_balancers(
133
152
 
134
153
  @timeit
135
154
  def load_load_balancer_listeners(
136
- neo4j_session: neo4j.Session, data: list[dict], region: str, current_aws_account_id: str,
155
+ neo4j_session: neo4j.Session,
156
+ data: list[dict],
157
+ region: str,
158
+ current_aws_account_id: str,
137
159
  update_tag: int,
138
160
  ) -> None:
139
161
  load(
@@ -147,22 +169,40 @@ def load_load_balancer_listeners(
147
169
 
148
170
 
149
171
  @timeit
150
- def cleanup_load_balancers(neo4j_session: neo4j.Session, common_job_parameters: dict) -> None:
151
- GraphJob.from_node_schema(ELBListenerSchema(), common_job_parameters).run(neo4j_session)
152
- GraphJob.from_node_schema(LoadBalancerSchema(), common_job_parameters).run(neo4j_session)
172
+ def cleanup_load_balancers(
173
+ neo4j_session: neo4j.Session, common_job_parameters: dict
174
+ ) -> None:
175
+ GraphJob.from_node_schema(ELBListenerSchema(), common_job_parameters).run(
176
+ neo4j_session
177
+ )
178
+ GraphJob.from_node_schema(LoadBalancerSchema(), common_job_parameters).run(
179
+ neo4j_session
180
+ )
153
181
 
154
182
 
155
183
  @timeit
156
184
  def sync_load_balancers(
157
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: list[str], current_aws_account_id: str,
158
- update_tag: int, common_job_parameters: dict,
185
+ neo4j_session: neo4j.Session,
186
+ boto3_session: boto3.session.Session,
187
+ regions: list[str],
188
+ current_aws_account_id: str,
189
+ update_tag: int,
190
+ common_job_parameters: dict,
159
191
  ) -> None:
160
192
  for region in regions:
161
- logger.info("Syncing EC2 load balancers for region '%s' in account '%s'.", region, current_aws_account_id)
193
+ logger.info(
194
+ "Syncing EC2 load balancers for region '%s' in account '%s'.",
195
+ region,
196
+ current_aws_account_id,
197
+ )
162
198
  data = get_loadbalancer_data(boto3_session, region)
163
199
  transformed_data, listener_data = transform_load_balancer_data(data)
164
200
 
165
- load_load_balancers(neo4j_session, transformed_data, region, current_aws_account_id, update_tag)
166
- load_load_balancer_listeners(neo4j_session, listener_data, region, current_aws_account_id, update_tag)
201
+ load_load_balancers(
202
+ neo4j_session, transformed_data, region, current_aws_account_id, update_tag
203
+ )
204
+ load_load_balancer_listeners(
205
+ neo4j_session, listener_data, region, current_aws_account_id, update_tag
206
+ )
167
207
 
168
208
  cleanup_load_balancers(neo4j_session, common_job_parameters)
@@ -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(