cartography 0.102.0rc1__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 +327 -0
  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 -44
  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 +97 -0
  208. cartography/models/aws/ec2/route_tables.py +128 -0
  209. cartography/models/aws/ec2/routes.py +85 -0
  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.0rc1.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.0rc1.dist-info → cartography-0.103.0.dist-info}/WHEEL +1 -1
  294. cartography-0.102.0rc1.dist-info/RECORD +0 -377
  295. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/entry_points.txt +0 -0
  296. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/licenses/LICENSE +0 -0
  297. {cartography-0.102.0rc1.dist-info → cartography-0.103.0.dist-info}/top_level.txt +0 -0
@@ -17,34 +17,43 @@ logger = logging.getLogger(__name__)
17
17
 
18
18
  @timeit
19
19
  @aws_handle_regions
20
- def get_ec2_key_pairs(boto3_session: boto3.session.Session, region: str) -> list[dict[str, Any]]:
21
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
22
- return client.describe_key_pairs()['KeyPairs']
20
+ def get_ec2_key_pairs(
21
+ boto3_session: boto3.session.Session,
22
+ region: str,
23
+ ) -> list[dict[str, Any]]:
24
+ client = boto3_session.client(
25
+ "ec2",
26
+ region_name=region,
27
+ config=get_botocore_config(),
28
+ )
29
+ return client.describe_key_pairs()["KeyPairs"]
23
30
 
24
31
 
25
32
  def transform_ec2_key_pairs(
26
- key_pairs: list[dict[str, Any]],
27
- region: str,
28
- current_aws_account_id: str,
33
+ key_pairs: list[dict[str, Any]],
34
+ region: str,
35
+ current_aws_account_id: str,
29
36
  ) -> list[dict[str, Any]]:
30
37
  transformed_key_pairs = []
31
38
  for key_pair in key_pairs:
32
39
  key_name = key_pair["KeyName"]
33
- transformed_key_pairs.append({
34
- 'KeyPairArn': f'arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}',
35
- 'KeyName': key_name,
36
- 'KeyFingerprint': key_pair.get("KeyFingerprint"),
37
- })
40
+ transformed_key_pairs.append(
41
+ {
42
+ "KeyPairArn": f"arn:aws:ec2:{region}:{current_aws_account_id}:key-pair/{key_name}",
43
+ "KeyName": key_name,
44
+ "KeyFingerprint": key_pair.get("KeyFingerprint"),
45
+ },
46
+ )
38
47
  return transformed_key_pairs
39
48
 
40
49
 
41
50
  @timeit
42
51
  def load_ec2_key_pairs(
43
- neo4j_session: neo4j.Session,
44
- data: list[dict[str, Any]],
45
- region: str,
46
- current_aws_account_id: str,
47
- update_tag: int,
52
+ neo4j_session: neo4j.Session,
53
+ data: list[dict[str, Any]],
54
+ region: str,
55
+ current_aws_account_id: str,
56
+ update_tag: int,
48
57
  ) -> None:
49
58
  # Load EC2 keypairs as known by describe-key-pairs
50
59
  logger.info(f"Loading {len(data)} EC2 keypairs for region '{region}' into graph.")
@@ -59,8 +68,13 @@ def load_ec2_key_pairs(
59
68
 
60
69
 
61
70
  @timeit
62
- def cleanup_ec2_key_pairs(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
63
- GraphJob.from_node_schema(EC2KeyPairSchema(), common_job_parameters).run(neo4j_session)
71
+ def cleanup_ec2_key_pairs(
72
+ neo4j_session: neo4j.Session,
73
+ common_job_parameters: Dict,
74
+ ) -> None:
75
+ GraphJob.from_node_schema(EC2KeyPairSchema(), common_job_parameters).run(
76
+ neo4j_session,
77
+ )
64
78
 
65
79
 
66
80
  @timeit
@@ -73,8 +87,18 @@ def sync_ec2_key_pairs(
73
87
  common_job_parameters: dict[str, Any],
74
88
  ) -> None:
75
89
  for region in regions:
76
- logger.info("Syncing EC2 key pairs for region '%s' in account '%s'.", region, current_aws_account_id)
90
+ logger.info(
91
+ "Syncing EC2 key pairs for region '%s' in account '%s'.",
92
+ region,
93
+ current_aws_account_id,
94
+ )
77
95
  data = get_ec2_key_pairs(boto3_session, region)
78
96
  transformed_data = transform_ec2_key_pairs(data, region, current_aws_account_id)
79
- load_ec2_key_pairs(neo4j_session, transformed_data, region, current_aws_account_id, update_tag)
97
+ load_ec2_key_pairs(
98
+ neo4j_session,
99
+ transformed_data,
100
+ region,
101
+ current_aws_account_id,
102
+ update_tag,
103
+ )
80
104
  cleanup_ec2_key_pairs(neo4j_session, common_job_parameters)
@@ -5,14 +5,17 @@ import boto3
5
5
  import botocore
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
- from cartography.models.aws.ec2.launch_template_versions import LaunchTemplateVersionSchema
10
+ from cartography.models.aws.ec2.launch_template_versions import (
11
+ LaunchTemplateVersionSchema,
12
+ )
12
13
  from cartography.models.aws.ec2.launch_templates import LaunchTemplateSchema
13
14
  from cartography.util import aws_handle_regions
14
15
  from cartography.util import timeit
15
16
 
17
+ from .util import get_botocore_config
18
+
16
19
  logger = logging.getLogger(__name__)
17
20
 
18
21
 
@@ -22,11 +25,13 @@ def get_launch_templates(
22
25
  boto3_session: boto3.session.Session,
23
26
  region: str,
24
27
  ) -> list[dict[str, Any]]:
25
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
26
- paginator = client.get_paginator('describe_launch_templates')
28
+ client = boto3_session.client(
29
+ "ec2", region_name=region, config=get_botocore_config()
30
+ )
31
+ paginator = client.get_paginator("describe_launch_templates")
27
32
  templates: list[dict[str, Any]] = []
28
33
  for page in paginator.paginate():
29
- paginated_templates = page['LaunchTemplates']
34
+ paginated_templates = page["LaunchTemplates"]
30
35
  templates.extend(paginated_templates)
31
36
  return templates
32
37
 
@@ -40,8 +45,10 @@ def get_launch_template_versions(
40
45
  ) -> list[dict[str, Any]]:
41
46
  template_versions: list[dict[str, Any]] = []
42
47
  for template in launch_templates:
43
- launch_template_id = template['LaunchTemplateId']
44
- versions = get_launch_template_versions_by_template(boto3_session, launch_template_id, region)
48
+ launch_template_id = template["LaunchTemplateId"]
49
+ versions = get_launch_template_versions_by_template(
50
+ boto3_session, launch_template_id, region
51
+ )
45
52
  template_versions.extend(versions)
46
53
 
47
54
  return template_versions
@@ -50,46 +57,54 @@ def get_launch_template_versions(
50
57
  @timeit
51
58
  @aws_handle_regions
52
59
  def get_launch_template_versions_by_template(
53
- boto3_session: boto3.session.Session,
54
- launch_template_id: str,
55
- region: str,
60
+ boto3_session: boto3.session.Session,
61
+ launch_template_id: str,
62
+ region: str,
56
63
  ) -> list[dict[str, Any]]:
57
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
58
- v_paginator = client.get_paginator('describe_launch_template_versions')
64
+ client = boto3_session.client(
65
+ "ec2", region_name=region, config=get_botocore_config()
66
+ )
67
+ v_paginator = client.get_paginator("describe_launch_template_versions")
59
68
  template_versions = []
60
69
  try:
61
70
  for versions in v_paginator.paginate(LaunchTemplateId=launch_template_id):
62
- template_versions.extend(versions['LaunchTemplateVersions'])
71
+ template_versions.extend(versions["LaunchTemplateVersions"])
63
72
  except botocore.exceptions.ClientError as e:
64
- error_code = e.response['Error']['Code']
65
- if error_code == 'InvalidLaunchTemplateId.NotFound':
66
- logger.warning("Launch template %s no longer exists in region %s", launch_template_id, region)
73
+ error_code = e.response["Error"]["Code"]
74
+ if error_code == "InvalidLaunchTemplateId.NotFound":
75
+ logger.warning(
76
+ "Launch template %s no longer exists in region %s",
77
+ launch_template_id,
78
+ region,
79
+ )
67
80
  else:
68
81
  raise
69
82
  return template_versions
70
83
 
71
84
 
72
- def transform_launch_templates(templates: list[dict[str, Any]], versions: list[dict[str, Any]]) -> list[dict[str, Any]]:
73
- valid_template_ids = {v['LaunchTemplateId'] for v in versions}
85
+ def transform_launch_templates(
86
+ templates: list[dict[str, Any]], versions: list[dict[str, Any]]
87
+ ) -> list[dict[str, Any]]:
88
+ valid_template_ids = {v["LaunchTemplateId"] for v in versions}
74
89
  result: list[dict[str, Any]] = []
75
90
  for template in templates:
76
- if template['LaunchTemplateId'] not in valid_template_ids:
91
+ if template["LaunchTemplateId"] not in valid_template_ids:
77
92
  continue
78
93
 
79
94
  current = template.copy()
80
95
  # Convert CreateTime to timestamp string
81
- current['CreateTime'] = str(int(current['CreateTime'].timestamp()))
96
+ current["CreateTime"] = str(int(current["CreateTime"].timestamp()))
82
97
  result.append(current)
83
98
  return result
84
99
 
85
100
 
86
101
  @timeit
87
102
  def load_launch_templates(
88
- neo4j_session: neo4j.Session,
89
- data: list[dict[str, Any]],
90
- region: str,
91
- current_aws_account_id: str,
92
- update_tag: int,
103
+ neo4j_session: neo4j.Session,
104
+ data: list[dict[str, Any]],
105
+ region: str,
106
+ current_aws_account_id: str,
107
+ update_tag: int,
93
108
  ) -> None:
94
109
  load(
95
110
  neo4j_session,
@@ -101,41 +116,45 @@ def load_launch_templates(
101
116
  )
102
117
 
103
118
 
104
- def transform_launch_template_versions(versions: list[dict[str, Any]]) -> list[dict[str, Any]]:
119
+ def transform_launch_template_versions(
120
+ versions: list[dict[str, Any]],
121
+ ) -> list[dict[str, Any]]:
105
122
  result: list[dict[str, Any]] = []
106
123
  for version in versions:
107
124
  current = version.copy()
108
125
 
109
126
  # Reformat some fields
110
- current['Id'] = f"{version['LaunchTemplateId']}-{version['VersionNumber']}"
111
- current['CreateTime'] = str(int(version['CreateTime'].timestamp()))
127
+ current["Id"] = f"{version['LaunchTemplateId']}-{version['VersionNumber']}"
128
+ current["CreateTime"] = str(int(version["CreateTime"].timestamp()))
112
129
 
113
130
  # Handle the nested object returned from boto
114
- ltd = version['LaunchTemplateData']
115
- current['KernelId'] = ltd.get('KernelId')
116
- current['EbsOptimized'] = ltd.get('EbsOptimized')
117
- current['IamInstanceProfileArn'] = ltd.get('IamInstanceProfileArn')
118
- current['IamInstanceProfileName'] = ltd.get('IamInstanceProfileName')
119
- current['ImageId'] = ltd.get('ImageId')
120
- current['InstanceType'] = ltd.get('InstanceType')
121
- current['KeyName'] = ltd.get('KeyName')
122
- current['MonitoringEnabled'] = ltd.get('MonitoringEnabled')
123
- current['RamdiskId'] = ltd.get('RamdiskId')
124
- current['DisableApiTermination'] = ltd.get('DisableApiTermination')
125
- current['InstanceInitiatedShutDownBehavior'] = ltd.get('InstanceInitiatedShutDownBehavior')
126
- current['SecurityGroupIds'] = ltd.get('SecurityGroupIds')
127
- current['SecurityGroups'] = ltd.get('SecurityGroups')
131
+ ltd = version["LaunchTemplateData"]
132
+ current["KernelId"] = ltd.get("KernelId")
133
+ current["EbsOptimized"] = ltd.get("EbsOptimized")
134
+ current["IamInstanceProfileArn"] = ltd.get("IamInstanceProfileArn")
135
+ current["IamInstanceProfileName"] = ltd.get("IamInstanceProfileName")
136
+ current["ImageId"] = ltd.get("ImageId")
137
+ current["InstanceType"] = ltd.get("InstanceType")
138
+ current["KeyName"] = ltd.get("KeyName")
139
+ current["MonitoringEnabled"] = ltd.get("MonitoringEnabled")
140
+ current["RamdiskId"] = ltd.get("RamdiskId")
141
+ current["DisableApiTermination"] = ltd.get("DisableApiTermination")
142
+ current["InstanceInitiatedShutDownBehavior"] = ltd.get(
143
+ "InstanceInitiatedShutDownBehavior",
144
+ )
145
+ current["SecurityGroupIds"] = ltd.get("SecurityGroupIds")
146
+ current["SecurityGroups"] = ltd.get("SecurityGroups")
128
147
  result.append(current)
129
148
  return result
130
149
 
131
150
 
132
151
  @timeit
133
152
  def load_launch_template_versions(
134
- neo4j_session: neo4j.Session,
135
- data: list[dict[str, Any]],
136
- region: str,
137
- current_aws_account_id: str,
138
- update_tag: int,
153
+ neo4j_session: neo4j.Session,
154
+ data: list[dict[str, Any]],
155
+ region: str,
156
+ current_aws_account_id: str,
157
+ update_tag: int,
139
158
  ) -> None:
140
159
  load(
141
160
  neo4j_session,
@@ -148,35 +167,58 @@ def load_launch_template_versions(
148
167
 
149
168
 
150
169
  @timeit
151
- def cleanup(neo4j_session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
170
+ def cleanup(
171
+ neo4j_session: neo4j.Session,
172
+ common_job_parameters: dict[str, Any],
173
+ ) -> None:
152
174
  logger.info("Running launch template cleanup job.")
153
- cleanup_job = GraphJob.from_node_schema(LaunchTemplateSchema(), common_job_parameters)
175
+ cleanup_job = GraphJob.from_node_schema(
176
+ LaunchTemplateSchema(),
177
+ common_job_parameters,
178
+ )
154
179
  cleanup_job.run(neo4j_session)
155
180
 
156
- cleanup_job = GraphJob.from_node_schema(LaunchTemplateVersionSchema(), common_job_parameters)
181
+ cleanup_job = GraphJob.from_node_schema(
182
+ LaunchTemplateVersionSchema(),
183
+ common_job_parameters,
184
+ )
157
185
  cleanup_job.run(neo4j_session)
158
186
 
159
187
 
160
188
  @timeit
161
189
  def sync_ec2_launch_templates(
162
- neo4j_session: neo4j.Session,
163
- boto3_session: boto3.session.Session,
164
- regions: list[str],
165
- current_aws_account_id: str,
166
- update_tag: int,
167
- common_job_parameters: dict[str, Any],
190
+ neo4j_session: neo4j.Session,
191
+ boto3_session: boto3.session.Session,
192
+ regions: list[str],
193
+ current_aws_account_id: str,
194
+ update_tag: int,
195
+ common_job_parameters: dict[str, Any],
168
196
  ) -> None:
169
197
  for region in regions:
170
- logger.info(f"Syncing launch templates for region '{region}' in account '{current_aws_account_id}'.")
198
+ logger.info(
199
+ f"Syncing launch templates for region '{region}' in account '{current_aws_account_id}'."
200
+ )
171
201
  templates = get_launch_templates(boto3_session, region)
172
202
  versions = get_launch_template_versions(boto3_session, region, templates)
173
203
 
174
204
  # Transform and load the templates that have versions
175
205
  transformed_templates = transform_launch_templates(templates, versions)
176
- load_launch_templates(neo4j_session, transformed_templates, region, current_aws_account_id, update_tag)
206
+ load_launch_templates(
207
+ neo4j_session,
208
+ transformed_templates,
209
+ region,
210
+ current_aws_account_id,
211
+ update_tag,
212
+ )
177
213
 
178
214
  # Transform and load the versions
179
215
  transformed_versions = transform_launch_template_versions(versions)
180
- load_launch_template_versions(neo4j_session, transformed_versions, region, current_aws_account_id, update_tag)
216
+ load_launch_template_versions(
217
+ neo4j_session,
218
+ transformed_versions,
219
+ region,
220
+ current_aws_account_id,
221
+ update_tag,
222
+ )
181
223
 
182
224
  cleanup(neo4j_session, common_job_parameters)
@@ -6,38 +6,47 @@ import boto3
6
6
  import botocore
7
7
  import neo4j
8
8
 
9
- from .util import get_botocore_config
10
9
  from cartography.util import aws_handle_regions
11
10
  from cartography.util import run_cleanup_job
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
 
17
18
  @timeit
18
19
  @aws_handle_regions
19
- def get_load_balancer_v2_listeners(client: botocore.client.BaseClient, load_balancer_arn: str) -> List[Dict]:
20
- paginator = client.get_paginator('describe_listeners')
20
+ def get_load_balancer_v2_listeners(
21
+ client: botocore.client.BaseClient,
22
+ load_balancer_arn: str,
23
+ ) -> List[Dict]:
24
+ paginator = client.get_paginator("describe_listeners")
21
25
  listeners: List[Dict] = []
22
26
  for page in paginator.paginate(LoadBalancerArn=load_balancer_arn):
23
- listeners.extend(page['Listeners'])
27
+ listeners.extend(page["Listeners"])
24
28
 
25
29
  return listeners
26
30
 
27
31
 
28
32
  @timeit
29
- def get_load_balancer_v2_target_groups(client: botocore.client.BaseClient, load_balancer_arn: str) -> List[Dict]:
30
- paginator = client.get_paginator('describe_target_groups')
33
+ def get_load_balancer_v2_target_groups(
34
+ client: botocore.client.BaseClient,
35
+ load_balancer_arn: str,
36
+ ) -> List[Dict]:
37
+ paginator = client.get_paginator("describe_target_groups")
31
38
  target_groups: List[Dict] = []
32
39
  for page in paginator.paginate(LoadBalancerArn=load_balancer_arn):
33
- target_groups.extend(page['TargetGroups'])
40
+ target_groups.extend(page["TargetGroups"])
34
41
 
35
42
  # Add instance data
36
43
  for target_group in target_groups:
37
- target_group['Targets'] = []
38
- target_health = client.describe_target_health(TargetGroupArn=target_group['TargetGroupArn'])
39
- for target_health_description in target_health['TargetHealthDescriptions']:
40
- target_group['Targets'].append(target_health_description['Target']['Id'])
44
+ target_group["Targets"] = []
45
+ target_health = client.describe_target_health(
46
+ TargetGroupArn=target_group["TargetGroupArn"],
47
+ )
48
+ for target_health_description in target_health["TargetHealthDescriptions"]:
49
+ target_group["Targets"].append(target_health_description["Target"]["Id"])
41
50
 
42
51
  return target_groups
43
52
 
@@ -45,22 +54,35 @@ def get_load_balancer_v2_target_groups(client: botocore.client.BaseClient, load_
45
54
  @timeit
46
55
  @aws_handle_regions
47
56
  def get_loadbalancer_v2_data(boto3_session: boto3.Session, region: str) -> List[Dict]:
48
- client = boto3_session.client('elbv2', region_name=region, config=get_botocore_config())
49
- paginator = client.get_paginator('describe_load_balancers')
57
+ client = boto3_session.client(
58
+ "elbv2",
59
+ region_name=region,
60
+ config=get_botocore_config(),
61
+ )
62
+ paginator = client.get_paginator("describe_load_balancers")
50
63
  elbv2s: List[Dict] = []
51
64
  for page in paginator.paginate():
52
- elbv2s.extend(page['LoadBalancers'])
65
+ elbv2s.extend(page["LoadBalancers"])
53
66
 
54
67
  # Make extra calls to get listeners
55
68
  for elbv2 in elbv2s:
56
- elbv2['Listeners'] = get_load_balancer_v2_listeners(client, elbv2['LoadBalancerArn'])
57
- elbv2['TargetGroups'] = get_load_balancer_v2_target_groups(client, elbv2['LoadBalancerArn'])
69
+ elbv2["Listeners"] = get_load_balancer_v2_listeners(
70
+ client,
71
+ elbv2["LoadBalancerArn"],
72
+ )
73
+ elbv2["TargetGroups"] = get_load_balancer_v2_target_groups(
74
+ client,
75
+ elbv2["LoadBalancerArn"],
76
+ )
58
77
  return elbv2s
59
78
 
60
79
 
61
80
  @timeit
62
81
  def load_load_balancer_v2s(
63
- neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str,
82
+ neo4j_session: neo4j.Session,
83
+ data: List[Dict],
84
+ region: str,
85
+ current_aws_account_id: str,
64
86
  update_tag: int,
65
87
  ) -> None:
66
88
  ingest_load_balancer_v2 = """
@@ -95,10 +117,16 @@ def load_load_balancer_v2s(
95
117
 
96
118
  if lb["AvailabilityZones"]:
97
119
  az = lb["AvailabilityZones"]
98
- load_load_balancer_v2_subnets(neo4j_session, load_balancer_id, az, region, update_tag)
120
+ load_load_balancer_v2_subnets(
121
+ neo4j_session,
122
+ load_balancer_id,
123
+ az,
124
+ region,
125
+ update_tag,
126
+ )
99
127
 
100
128
  # NLB's don't have SecurityGroups, so check for one first.
101
- if 'SecurityGroups' in lb and lb["SecurityGroups"]:
129
+ if "SecurityGroups" in lb and lb["SecurityGroups"]:
102
130
  ingest_load_balancer_v2_security_group = """
103
131
  MATCH (elbv2:LoadBalancerV2{id: $ID}),
104
132
  (group:EC2SecurityGroup{groupid: $GROUP_ID})
@@ -114,20 +142,31 @@ def load_load_balancer_v2s(
114
142
  update_tag=update_tag,
115
143
  )
116
144
 
117
- if lb['Listeners']:
118
- load_load_balancer_v2_listeners(neo4j_session, load_balancer_id, lb['Listeners'], update_tag)
145
+ if lb["Listeners"]:
146
+ load_load_balancer_v2_listeners(
147
+ neo4j_session,
148
+ load_balancer_id,
149
+ lb["Listeners"],
150
+ update_tag,
151
+ )
119
152
 
120
- if lb['TargetGroups']:
153
+ if lb["TargetGroups"]:
121
154
  load_load_balancer_v2_target_groups(
122
- neo4j_session, load_balancer_id, lb['TargetGroups'],
123
- current_aws_account_id, update_tag,
155
+ neo4j_session,
156
+ load_balancer_id,
157
+ lb["TargetGroups"],
158
+ current_aws_account_id,
159
+ update_tag,
124
160
  )
125
161
 
126
162
 
127
163
  @timeit
128
164
  def load_load_balancer_v2_subnets(
129
- neo4j_session: neo4j.Session, load_balancer_id: str, az_data: List[Dict],
130
- region: str, update_tag: int,
165
+ neo4j_session: neo4j.Session,
166
+ load_balancer_id: str,
167
+ az_data: List[Dict],
168
+ region: str,
169
+ update_tag: int,
131
170
  ) -> None:
132
171
  ingest_load_balancer_subnet = """
133
172
  MATCH (elbv2:LoadBalancerV2{id: $ID})
@@ -143,7 +182,7 @@ def load_load_balancer_v2_subnets(
143
182
  neo4j_session.run(
144
183
  ingest_load_balancer_subnet,
145
184
  ID=load_balancer_id,
146
- SubnetId=az['SubnetId'],
185
+ SubnetId=az["SubnetId"],
147
186
  region=region,
148
187
  update_tag=update_tag,
149
188
  )
@@ -151,7 +190,10 @@ def load_load_balancer_v2_subnets(
151
190
 
152
191
  @timeit
153
192
  def load_load_balancer_v2_target_groups(
154
- neo4j_session: neo4j.Session, load_balancer_id: str, target_groups: List[Dict], current_aws_account_id: str,
193
+ neo4j_session: neo4j.Session,
194
+ load_balancer_id: str,
195
+ target_groups: List[Dict],
196
+ current_aws_account_id: str,
155
197
  update_tag: int,
156
198
  ) -> None:
157
199
  ingest_instances = """
@@ -169,7 +211,7 @@ def load_load_balancer_v2_target_groups(
169
211
  """
170
212
  for target_group in target_groups:
171
213
 
172
- if not target_group['TargetType'] == 'instance':
214
+ if not target_group["TargetType"] == "instance":
173
215
  # Only working on EC2 Instances now. TODO: Add IP & Lambda EXPOSE.
174
216
  continue
175
217
 
@@ -179,16 +221,18 @@ def load_load_balancer_v2_target_groups(
179
221
  ID=load_balancer_id,
180
222
  INSTANCE_ID=instance,
181
223
  AWS_ACCOUNT_ID=current_aws_account_id,
182
- TARGET_GROUP_ARN=target_group.get('TargetGroupArn'),
183
- PORT=target_group.get('Port'),
184
- PROTOCOL=target_group.get('Protocol'),
224
+ TARGET_GROUP_ARN=target_group.get("TargetGroupArn"),
225
+ PORT=target_group.get("Port"),
226
+ PROTOCOL=target_group.get("Protocol"),
185
227
  update_tag=update_tag,
186
228
  )
187
229
 
188
230
 
189
231
  @timeit
190
232
  def load_load_balancer_v2_listeners(
191
- neo4j_session: neo4j.Session, load_balancer_id: str, listener_data: List[Dict],
233
+ neo4j_session: neo4j.Session,
234
+ load_balancer_id: str,
235
+ listener_data: List[Dict],
192
236
  update_tag: int,
193
237
  ) -> None:
194
238
  ingest_listener = """
@@ -215,18 +259,39 @@ def load_load_balancer_v2_listeners(
215
259
 
216
260
 
217
261
  @timeit
218
- def cleanup_load_balancer_v2s(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
262
+ def cleanup_load_balancer_v2s(
263
+ neo4j_session: neo4j.Session,
264
+ common_job_parameters: Dict,
265
+ ) -> None:
219
266
  """Delete elbv2's and dependent resources in the DB without the most recent lastupdated tag."""
220
- run_cleanup_job('aws_ingest_load_balancers_v2_cleanup.json', neo4j_session, common_job_parameters)
267
+ run_cleanup_job(
268
+ "aws_ingest_load_balancers_v2_cleanup.json",
269
+ neo4j_session,
270
+ common_job_parameters,
271
+ )
221
272
 
222
273
 
223
274
  @timeit
224
275
  def sync_load_balancer_v2s(
225
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
226
- update_tag: int, common_job_parameters: Dict,
276
+ neo4j_session: neo4j.Session,
277
+ boto3_session: boto3.session.Session,
278
+ regions: List[str],
279
+ current_aws_account_id: str,
280
+ update_tag: int,
281
+ common_job_parameters: Dict,
227
282
  ) -> None:
228
283
  for region in regions:
229
- logger.info("Syncing EC2 load balancers v2 for region '%s' in account '%s'.", region, current_aws_account_id)
284
+ logger.info(
285
+ "Syncing EC2 load balancers v2 for region '%s' in account '%s'.",
286
+ region,
287
+ current_aws_account_id,
288
+ )
230
289
  data = get_loadbalancer_v2_data(boto3_session, region)
231
- load_load_balancer_v2s(neo4j_session, data, region, current_aws_account_id, update_tag)
290
+ load_load_balancer_v2s(
291
+ neo4j_session,
292
+ data,
293
+ region,
294
+ current_aws_account_id,
295
+ update_tag,
296
+ )
232
297
  cleanup_load_balancer_v2s(neo4j_session, common_job_parameters)