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
@@ -5,31 +5,41 @@ from typing import List
5
5
  import boto3
6
6
  import neo4j
7
7
 
8
- from .util import get_botocore_config
9
8
  from cartography.graph.job import GraphJob
10
- from cartography.models.aws.ec2.auto_scaling_groups import EC2SubnetAutoScalingGroupSchema
9
+ from cartography.models.aws.ec2.auto_scaling_groups import (
10
+ EC2SubnetAutoScalingGroupSchema,
11
+ )
11
12
  from cartography.models.aws.ec2.subnet_instance import EC2SubnetInstanceSchema
12
13
  from cartography.util import aws_handle_regions
13
14
  from cartography.util import run_cleanup_job
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
 
19
22
  @timeit
20
23
  @aws_handle_regions
21
24
  def get_subnet_data(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
22
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
23
- paginator = client.get_paginator('describe_subnets')
25
+ client = boto3_session.client(
26
+ "ec2",
27
+ region_name=region,
28
+ config=get_botocore_config(),
29
+ )
30
+ paginator = client.get_paginator("describe_subnets")
24
31
  subnets: List[Dict] = []
25
32
  for page in paginator.paginate():
26
- subnets.extend(page['Subnets'])
33
+ subnets.extend(page["Subnets"])
27
34
  return subnets
28
35
 
29
36
 
30
37
  @timeit
31
38
  def load_subnets(
32
- neo4j_session: neo4j.Session, data: List[Dict], region: str, aws_account_id: str,
39
+ neo4j_session: neo4j.Session,
40
+ data: List[Dict],
41
+ region: str,
42
+ aws_account_id: str,
33
43
  aws_update_tag: int,
34
44
  ) -> None:
35
45
 
@@ -63,33 +73,59 @@ def load_subnets(
63
73
  """
64
74
 
65
75
  neo4j_session.run(
66
- ingest_subnets, subnets=data, aws_update_tag=aws_update_tag,
67
- region=region, aws_account_id=aws_account_id,
76
+ ingest_subnets,
77
+ subnets=data,
78
+ aws_update_tag=aws_update_tag,
79
+ region=region,
80
+ aws_account_id=aws_account_id,
68
81
  )
69
82
  neo4j_session.run(
70
- ingest_subnet_vpc_relations, subnets=data, aws_update_tag=aws_update_tag,
71
- region=region, aws_account_id=aws_account_id,
83
+ ingest_subnet_vpc_relations,
84
+ subnets=data,
85
+ aws_update_tag=aws_update_tag,
86
+ region=region,
87
+ aws_account_id=aws_account_id,
72
88
  )
73
89
  neo4j_session.run(
74
- ingest_subnet_aws_account_relations, subnets=data, aws_update_tag=aws_update_tag,
75
- region=region, aws_account_id=aws_account_id,
90
+ ingest_subnet_aws_account_relations,
91
+ subnets=data,
92
+ aws_update_tag=aws_update_tag,
93
+ region=region,
94
+ aws_account_id=aws_account_id,
76
95
  )
77
96
 
78
97
 
79
98
  @timeit
80
99
  def cleanup_subnets(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
81
- run_cleanup_job('aws_ingest_subnets_cleanup.json', neo4j_session, common_job_parameters)
82
- GraphJob.from_node_schema(EC2SubnetInstanceSchema(), common_job_parameters).run(neo4j_session)
83
- GraphJob.from_node_schema(EC2SubnetAutoScalingGroupSchema(), common_job_parameters).run(neo4j_session)
100
+ run_cleanup_job(
101
+ "aws_ingest_subnets_cleanup.json",
102
+ neo4j_session,
103
+ common_job_parameters,
104
+ )
105
+ GraphJob.from_node_schema(EC2SubnetInstanceSchema(), common_job_parameters).run(
106
+ neo4j_session,
107
+ )
108
+ GraphJob.from_node_schema(
109
+ EC2SubnetAutoScalingGroupSchema(),
110
+ common_job_parameters,
111
+ ).run(neo4j_session)
84
112
 
85
113
 
86
114
  @timeit
87
115
  def sync_subnets(
88
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str],
89
- current_aws_account_id: str, update_tag: int, common_job_parameters: Dict,
116
+ neo4j_session: neo4j.Session,
117
+ boto3_session: boto3.session.Session,
118
+ regions: List[str],
119
+ current_aws_account_id: str,
120
+ update_tag: int,
121
+ common_job_parameters: Dict,
90
122
  ) -> None:
91
123
  for region in regions:
92
- logger.info("Syncing EC2 subnets for region '%s' in account '%s'.", region, current_aws_account_id)
124
+ logger.info(
125
+ "Syncing EC2 subnets for region '%s' in account '%s'.",
126
+ region,
127
+ current_aws_account_id,
128
+ )
93
129
  data = get_subnet_data(boto3_session, region)
94
130
  load_subnets(neo4j_session, data, region, current_aws_account_id, update_tag)
95
131
  cleanup_subnets(neo4j_session, common_job_parameters)
@@ -6,18 +6,26 @@ import boto3
6
6
  import botocore.exceptions
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_transit_gateways(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
20
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
20
+ def get_transit_gateways(
21
+ boto3_session: boto3.session.Session,
22
+ region: str,
23
+ ) -> List[Dict]:
24
+ client = boto3_session.client(
25
+ "ec2",
26
+ region_name=region,
27
+ config=get_botocore_config(),
28
+ )
21
29
  data: List[Dict] = []
22
30
  try:
23
31
  data = client.describe_transit_gateways()["TransitGateways"]
@@ -25,51 +33,68 @@ def get_transit_gateways(boto3_session: boto3.session.Session, region: str) -> L
25
33
  # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/error-handling.html#parsing-error-responses-and-catching-exceptions-from-aws-services
26
34
  logger.warning(
27
35
  "Could not retrieve Transit Gateways due to boto3 error %s: %s. Skipping.",
28
- e.response['Error']['Code'],
29
- e.response['Error']['Message'],
36
+ e.response["Error"]["Code"],
37
+ e.response["Error"]["Message"],
30
38
  )
31
39
  return data
32
40
 
33
41
 
34
42
  @timeit
35
43
  @aws_handle_regions
36
- def get_tgw_attachments(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
37
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
44
+ def get_tgw_attachments(
45
+ boto3_session: boto3.session.Session,
46
+ region: str,
47
+ ) -> List[Dict]:
48
+ client = boto3_session.client(
49
+ "ec2",
50
+ region_name=region,
51
+ config=get_botocore_config(),
52
+ )
38
53
  tgw_attachments: List[Dict] = []
39
54
  try:
40
- paginator = client.get_paginator('describe_transit_gateway_attachments')
55
+ paginator = client.get_paginator("describe_transit_gateway_attachments")
41
56
  for page in paginator.paginate():
42
- tgw_attachments.extend(page['TransitGatewayAttachments'])
57
+ tgw_attachments.extend(page["TransitGatewayAttachments"])
43
58
  except botocore.exceptions.ClientError as e:
44
59
  logger.warning(
45
60
  "Could not retrieve Transit Gateway Attachments due to boto3 error %s: %s. Skipping.",
46
- e.response['Error']['Code'],
47
- e.response['Error']['Message'],
61
+ e.response["Error"]["Code"],
62
+ e.response["Error"]["Message"],
48
63
  )
49
64
  return tgw_attachments
50
65
 
51
66
 
52
67
  @timeit
53
68
  @aws_handle_regions
54
- def get_tgw_vpc_attachments(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
55
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
69
+ def get_tgw_vpc_attachments(
70
+ boto3_session: boto3.session.Session,
71
+ region: str,
72
+ ) -> List[Dict]:
73
+ client = boto3_session.client(
74
+ "ec2",
75
+ region_name=region,
76
+ config=get_botocore_config(),
77
+ )
56
78
  tgw_vpc_attachments: List[Dict] = []
57
79
  try:
58
- paginator = client.get_paginator('describe_transit_gateway_vpc_attachments')
80
+ paginator = client.get_paginator("describe_transit_gateway_vpc_attachments")
59
81
  for page in paginator.paginate():
60
- tgw_vpc_attachments.extend(page['TransitGatewayVpcAttachments'])
82
+ tgw_vpc_attachments.extend(page["TransitGatewayVpcAttachments"])
61
83
  except botocore.exceptions.ClientError as e:
62
84
  logger.warning(
63
85
  "Could not retrieve Transit Gateway VPC Attachments due to boto3 error %s: %s. Skipping.",
64
- e.response['Error']['Code'],
65
- e.response['Error']['Message'],
86
+ e.response["Error"]["Code"],
87
+ e.response["Error"]["Message"],
66
88
  )
67
89
  return tgw_vpc_attachments
68
90
 
69
91
 
70
92
  @timeit
71
93
  def load_transit_gateways(
72
- neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str,
94
+ neo4j_session: neo4j.Session,
95
+ data: List[Dict],
96
+ region: str,
97
+ current_aws_account_id: str,
73
98
  update_tag: int,
74
99
  ) -> None:
75
100
  ingest_transit_gateway = """
@@ -107,13 +132,21 @@ def load_transit_gateways(
107
132
  update_tag=update_tag,
108
133
  )
109
134
  _attach_shared_transit_gateway(
110
- neo4j_session, tgw, region, current_aws_account_id, update_tag,
135
+ neo4j_session,
136
+ tgw,
137
+ region,
138
+ current_aws_account_id,
139
+ update_tag,
111
140
  )
112
141
 
113
142
 
114
143
  @timeit
115
144
  def _attach_shared_transit_gateway(
116
- neo4j_session: neo4j.Session, tgw: Dict, region: str, current_aws_account_id: str, update_tag: int,
145
+ neo4j_session: neo4j.Session,
146
+ tgw: Dict,
147
+ region: str,
148
+ current_aws_account_id: str,
149
+ update_tag: int,
117
150
  ) -> None:
118
151
  attach_tgw = """
119
152
  MERGE (tgw:AWSTransitGateway {id: $ARN})
@@ -139,7 +172,10 @@ def _attach_shared_transit_gateway(
139
172
 
140
173
  @timeit
141
174
  def load_tgw_attachments(
142
- neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str,
175
+ neo4j_session: neo4j.Session,
176
+ data: List[Dict],
177
+ region: str,
178
+ current_aws_account_id: str,
143
179
  update_tag: int,
144
180
  ) -> None:
145
181
  ingest_transit_gateway = """
@@ -178,16 +214,25 @@ def load_tgw_attachments(
178
214
  update_tag=update_tag,
179
215
  )
180
216
 
181
- if tgwa.get("VpcId"): # only attach if the TGW attachment is a VPC TGW attachment
217
+ if tgwa.get(
218
+ "VpcId",
219
+ ): # only attach if the TGW attachment is a VPC TGW attachment
182
220
  _attach_tgw_vpc_attachment_to_vpc_subnets(
183
- neo4j_session, tgwa, region, current_aws_account_id, update_tag,
221
+ neo4j_session,
222
+ tgwa,
223
+ region,
224
+ current_aws_account_id,
225
+ update_tag,
184
226
  )
185
227
 
186
228
 
187
229
  @timeit
188
230
  def _attach_tgw_vpc_attachment_to_vpc_subnets(
189
- neo4j_session: neo4j.Session, tgw_vpc_attachment: Dict, region: str,
190
- current_aws_account_id: str, update_tag: int,
231
+ neo4j_session: neo4j.Session,
232
+ tgw_vpc_attachment: Dict,
233
+ region: str,
234
+ current_aws_account_id: str,
235
+ update_tag: int,
191
236
  ) -> None:
192
237
  """
193
238
  Attach a VPC Transit Gateway Attachment to the VPC and and subnets
@@ -233,27 +278,48 @@ def _attach_tgw_vpc_attachment_to_vpc_subnets(
233
278
 
234
279
 
235
280
  @timeit
236
- def cleanup_transit_gateways(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
237
- run_cleanup_job('aws_import_tgw_cleanup.json', neo4j_session, common_job_parameters)
281
+ def cleanup_transit_gateways(
282
+ neo4j_session: neo4j.Session,
283
+ common_job_parameters: Dict,
284
+ ) -> None:
285
+ run_cleanup_job("aws_import_tgw_cleanup.json", neo4j_session, common_job_parameters)
238
286
 
239
287
 
240
288
  def sync_transit_gateways(
241
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
242
- update_tag: int, common_job_parameters: Dict,
289
+ neo4j_session: neo4j.Session,
290
+ boto3_session: boto3.session.Session,
291
+ regions: List[str],
292
+ current_aws_account_id: str,
293
+ update_tag: int,
294
+ common_job_parameters: Dict,
243
295
  ) -> None:
244
296
  for region in regions:
245
- logger.info("Syncing AWS Transit Gateways for region '%s' in account '%s'.", region, current_aws_account_id)
297
+ logger.info(
298
+ "Syncing AWS Transit Gateways for region '%s' in account '%s'.",
299
+ region,
300
+ current_aws_account_id,
301
+ )
246
302
  tgws = get_transit_gateways(boto3_session, region)
247
- load_transit_gateways(neo4j_session, tgws, region, current_aws_account_id, update_tag)
303
+ load_transit_gateways(
304
+ neo4j_session,
305
+ tgws,
306
+ region,
307
+ current_aws_account_id,
308
+ update_tag,
309
+ )
248
310
 
249
311
  logger.debug(
250
312
  "Syncing AWS Transit Gateway Attachments for region '%s' in account '%s'.",
251
- region, current_aws_account_id,
313
+ region,
314
+ current_aws_account_id,
252
315
  )
253
316
  tgw_attachments = get_tgw_attachments(boto3_session, region)
254
317
  tgw_vpc_attachments = get_tgw_vpc_attachments(boto3_session, region)
255
318
  load_tgw_attachments(
256
- neo4j_session, tgw_attachments + tgw_vpc_attachments,
257
- region, current_aws_account_id, update_tag,
319
+ neo4j_session,
320
+ tgw_attachments + tgw_vpc_attachments,
321
+ region,
322
+ current_aws_account_id,
323
+ update_tag,
258
324
  )
259
325
  cleanup_transit_gateways(neo4j_session, common_job_parameters)
@@ -6,6 +6,6 @@ def get_botocore_config() -> botocore.config.Config:
6
6
  return botocore.config.Config(
7
7
  read_timeout=360,
8
8
  retries={
9
- 'max_attempts': 10,
9
+ "max_attempts": 10,
10
10
  },
11
11
  )
@@ -18,38 +18,51 @@ logger = logging.getLogger(__name__)
18
18
 
19
19
  @timeit
20
20
  @aws_handle_regions
21
- def get_volumes(boto3_session: boto3.session.Session, region: str) -> List[Dict[str, Any]]:
22
- client = boto3_session.client('ec2', region_name=region)
23
- paginator = client.get_paginator('describe_volumes')
21
+ def get_volumes(
22
+ boto3_session: boto3.session.Session,
23
+ region: str,
24
+ ) -> List[Dict[str, Any]]:
25
+ client = boto3_session.client("ec2", region_name=region)
26
+ paginator = client.get_paginator("describe_volumes")
24
27
  volumes: List[Dict] = []
25
28
  for page in paginator.paginate():
26
- volumes.extend(page['Volumes'])
29
+ volumes.extend(page["Volumes"])
27
30
  return volumes
28
31
 
29
32
 
30
- def transform_volumes(volumes: List[Dict[str, Any]], region: str, current_aws_account_id: str) -> List[Dict[str, Any]]:
33
+ def transform_volumes(
34
+ volumes: List[Dict[str, Any]],
35
+ region: str,
36
+ current_aws_account_id: str,
37
+ ) -> List[Dict[str, Any]]:
31
38
  result = []
32
39
  for volume in volumes:
33
- attachments = volume.get('Attachments', [])
34
- active_attachments = [a for a in attachments if a['State'] == 'attached']
35
-
36
- volume_id = volume['VolumeId']
37
- raw_vol = ({
38
- 'Arn': build_arn('ec2', current_aws_account_id, 'volume', volume_id, region),
39
- 'AvailabilityZone': volume.get('AvailabilityZone'),
40
- 'CreateTime': volume.get('CreateTime'),
41
- 'Encrypted': volume.get('Encrypted'),
42
- 'Size': volume.get('Size'),
43
- 'State': volume.get('State'),
44
- 'OutpostArn': volume.get('OutpostArn'),
45
- 'SnapshotId': volume.get('SnapshotId'),
46
- 'Iops': volume.get('Iops'),
47
- 'FastRestored': volume.get('FastRestored'),
48
- 'MultiAttachEnabled': volume.get('MultiAttachEnabled'),
49
- 'VolumeType': volume.get('VolumeType'),
50
- 'VolumeId': volume_id,
51
- 'KmsKeyId': volume.get('KmsKeyId'),
52
- })
40
+ attachments = volume.get("Attachments", [])
41
+ active_attachments = [a for a in attachments if a["State"] == "attached"]
42
+
43
+ volume_id = volume["VolumeId"]
44
+ raw_vol = {
45
+ "Arn": build_arn(
46
+ "ec2",
47
+ current_aws_account_id,
48
+ "volume",
49
+ volume_id,
50
+ region,
51
+ ),
52
+ "AvailabilityZone": volume.get("AvailabilityZone"),
53
+ "CreateTime": volume.get("CreateTime"),
54
+ "Encrypted": volume.get("Encrypted"),
55
+ "Size": volume.get("Size"),
56
+ "State": volume.get("State"),
57
+ "OutpostArn": volume.get("OutpostArn"),
58
+ "SnapshotId": volume.get("SnapshotId"),
59
+ "Iops": volume.get("Iops"),
60
+ "FastRestored": volume.get("FastRestored"),
61
+ "MultiAttachEnabled": volume.get("MultiAttachEnabled"),
62
+ "VolumeType": volume.get("VolumeType"),
63
+ "VolumeId": volume_id,
64
+ "KmsKeyId": volume.get("KmsKeyId"),
65
+ }
53
66
 
54
67
  if not active_attachments:
55
68
  result.append(raw_vol)
@@ -57,7 +70,7 @@ def transform_volumes(volumes: List[Dict[str, Any]], region: str, current_aws_ac
57
70
 
58
71
  for attachment in active_attachments:
59
72
  vol_with_attachment = raw_vol.copy()
60
- vol_with_attachment['InstanceId'] = attachment['InstanceId']
73
+ vol_with_attachment["InstanceId"] = attachment["InstanceId"]
61
74
  result.append(vol_with_attachment)
62
75
 
63
76
  return result
@@ -65,11 +78,11 @@ def transform_volumes(volumes: List[Dict[str, Any]], region: str, current_aws_ac
65
78
 
66
79
  @timeit
67
80
  def load_volumes(
68
- neo4j_session: neo4j.Session,
69
- ebs_data: List[Dict[str, Any]],
70
- region: str,
71
- current_aws_account_id: str,
72
- update_tag: int,
81
+ neo4j_session: neo4j.Session,
82
+ ebs_data: List[Dict[str, Any]],
83
+ region: str,
84
+ current_aws_account_id: str,
85
+ update_tag: int,
73
86
  ) -> None:
74
87
  load(
75
88
  neo4j_session,
@@ -82,22 +95,37 @@ def load_volumes(
82
95
 
83
96
 
84
97
  @timeit
85
- def cleanup_volumes(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None:
86
- GraphJob.from_node_schema(EBSVolumeSchema(), common_job_parameters).run(neo4j_session)
98
+ def cleanup_volumes(
99
+ neo4j_session: neo4j.Session,
100
+ common_job_parameters: Dict[str, Any],
101
+ ) -> None:
102
+ GraphJob.from_node_schema(EBSVolumeSchema(), common_job_parameters).run(
103
+ neo4j_session,
104
+ )
87
105
 
88
106
 
89
107
  @timeit
90
108
  def sync_ebs_volumes(
91
- neo4j_session: neo4j.Session,
92
- boto3_session: boto3.session.Session,
93
- regions: List[str],
94
- current_aws_account_id: str,
95
- update_tag: int,
96
- common_job_parameters: Dict[str, Any],
109
+ neo4j_session: neo4j.Session,
110
+ boto3_session: boto3.session.Session,
111
+ regions: List[str],
112
+ current_aws_account_id: str,
113
+ update_tag: int,
114
+ common_job_parameters: Dict[str, Any],
97
115
  ) -> None:
98
116
  for region in regions:
99
- logger.debug("Syncing volumes for region '%s' in account '%s'.", region, current_aws_account_id)
117
+ logger.debug(
118
+ "Syncing volumes for region '%s' in account '%s'.",
119
+ region,
120
+ current_aws_account_id,
121
+ )
100
122
  data = get_volumes(boto3_session, region)
101
123
  transformed_data = transform_volumes(data, region, current_aws_account_id)
102
- load_volumes(neo4j_session, transformed_data, region, current_aws_account_id, update_tag)
124
+ load_volumes(
125
+ neo4j_session,
126
+ transformed_data,
127
+ region,
128
+ current_aws_account_id,
129
+ update_tag,
130
+ )
103
131
  cleanup_volumes(neo4j_session, common_job_parameters)
@@ -6,23 +6,29 @@ from typing import List
6
6
  import boto3
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
20
  def get_ec2_vpcs(boto3_session: boto3.session.Session, region: str) -> List[Dict]:
20
- client = boto3_session.client('ec2', region_name=region, config=get_botocore_config())
21
- return client.describe_vpcs()['Vpcs']
21
+ client = boto3_session.client(
22
+ "ec2",
23
+ region_name=region,
24
+ config=get_botocore_config(),
25
+ )
26
+ return client.describe_vpcs()["Vpcs"]
22
27
 
23
28
 
24
29
  def _get_cidr_association_statement(block_type: str) -> str:
25
- INGEST_CIDR_TEMPLATE = Template("""
30
+ INGEST_CIDR_TEMPLATE = Template(
31
+ """
26
32
  MATCH (vpc:AWSVpc{id: $VpcId})
27
33
  WITH vpc
28
34
  UNWIND $CidrBlock as block_data
@@ -36,7 +42,8 @@ def _get_cidr_association_statement(block_type: str) -> str:
36
42
  WITH vpc, new_block
37
43
  MERGE (vpc)-[r:BLOCK_ASSOCIATION]->(new_block)
38
44
  ON CREATE SET r.firstseen = timestamp()
39
- SET r.lastupdated = $update_tag""")
45
+ SET r.lastupdated = $update_tag""",
46
+ )
40
47
 
41
48
  BLOCK_CIDR = "CidrBlock"
42
49
  STATE_NAME = "CidrBlockState"
@@ -53,12 +60,19 @@ def _get_cidr_association_statement(block_type: str) -> str:
53
60
  else:
54
61
  raise ValueError(f"Unsupported block type specified - {block_type}")
55
62
 
56
- return INGEST_CIDR_TEMPLATE.safe_substitute(block_label=BLOCK_TYPE, block_cidr=BLOCK_CIDR, state_name=STATE_NAME)
63
+ return INGEST_CIDR_TEMPLATE.safe_substitute(
64
+ block_label=BLOCK_TYPE,
65
+ block_cidr=BLOCK_CIDR,
66
+ state_name=STATE_NAME,
67
+ )
57
68
 
58
69
 
59
70
  @timeit
60
71
  def load_cidr_association_set(
61
- neo4j_session: neo4j.Session, vpc_id: str, vpc_data: Dict, block_type: str,
72
+ neo4j_session: neo4j.Session,
73
+ vpc_id: str,
74
+ vpc_data: Dict,
75
+ block_type: str,
62
76
  update_tag: int,
63
77
  ) -> None:
64
78
  ingest_statement = _get_cidr_association_statement(block_type)
@@ -78,7 +92,10 @@ def load_cidr_association_set(
78
92
 
79
93
  @timeit
80
94
  def load_ec2_vpcs(
81
- neo4j_session: neo4j.Session, data: List[Dict], region: str, current_aws_account_id: str,
95
+ neo4j_session: neo4j.Session,
96
+ data: List[Dict],
97
+ region: str,
98
+ current_aws_account_id: str,
82
99
  update_tag: int,
83
100
  ) -> None:
84
101
  # https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-vpcs.html
@@ -161,16 +178,24 @@ def load_ec2_vpcs(
161
178
 
162
179
  @timeit
163
180
  def cleanup_ec2_vpcs(neo4j_session: neo4j.Session, common_job_parameters: Dict) -> None:
164
- run_cleanup_job('aws_import_vpc_cleanup.json', neo4j_session, common_job_parameters)
181
+ run_cleanup_job("aws_import_vpc_cleanup.json", neo4j_session, common_job_parameters)
165
182
 
166
183
 
167
184
  @timeit
168
185
  def sync_vpc(
169
- neo4j_session: neo4j.Session, boto3_session: boto3.session.Session, regions: List[str], current_aws_account_id: str,
170
- update_tag: int, common_job_parameters: Dict,
186
+ neo4j_session: neo4j.Session,
187
+ boto3_session: boto3.session.Session,
188
+ regions: List[str],
189
+ current_aws_account_id: str,
190
+ update_tag: int,
191
+ common_job_parameters: Dict,
171
192
  ) -> None:
172
193
  for region in regions:
173
- logger.info("Syncing EC2 VPC for region '%s' in account '%s'.", region, current_aws_account_id)
194
+ logger.info(
195
+ "Syncing EC2 VPC for region '%s' in account '%s'.",
196
+ region,
197
+ current_aws_account_id,
198
+ )
174
199
  data = get_ec2_vpcs(boto3_session, region)
175
200
  load_ec2_vpcs(neo4j_session, data, region, current_aws_account_id, update_tag)
176
201
  cleanup_ec2_vpcs(neo4j_session, common_job_parameters)