cartography 0.104.0rc2__py3-none-any.whl → 0.123.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.
Files changed (642) hide show
  1. cartography/_version.py +16 -3
  2. cartography/cli.py +466 -5
  3. cartography/client/aws/__init__.py +19 -0
  4. cartography/client/aws/ecr.py +51 -0
  5. cartography/client/core/tx.py +357 -8
  6. cartography/config.py +153 -0
  7. cartography/data/azure_permission_relationships.yaml +20 -0
  8. cartography/data/gcp_permission_relationships.yaml +21 -0
  9. cartography/data/indexes.cypher +0 -186
  10. cartography/data/jobs/analysis/aws_ec2_keypair_analysis.json +2 -2
  11. cartography/data/jobs/analysis/keycloak_inheritance.json +30 -0
  12. cartography/data/jobs/cleanup/gcp_compute_vpc_cleanup.json +0 -12
  13. cartography/data/jobs/cleanup/github_repos_cleanup.json +2 -0
  14. cartography/driftdetect/cli.py +3 -2
  15. cartography/graph/cleanupbuilder.py +198 -41
  16. cartography/graph/job.py +54 -6
  17. cartography/graph/querybuilder.py +528 -27
  18. cartography/graph/statement.py +5 -1
  19. cartography/intel/airbyte/__init__.py +105 -0
  20. cartography/intel/airbyte/connections.py +120 -0
  21. cartography/intel/airbyte/destinations.py +81 -0
  22. cartography/intel/airbyte/organizations.py +59 -0
  23. cartography/intel/airbyte/sources.py +78 -0
  24. cartography/intel/airbyte/tags.py +64 -0
  25. cartography/intel/airbyte/users.py +106 -0
  26. cartography/intel/airbyte/util.py +122 -0
  27. cartography/intel/airbyte/workspaces.py +63 -0
  28. cartography/intel/aws/__init__.py +24 -9
  29. cartography/intel/aws/acm.py +124 -0
  30. cartography/intel/aws/apigateway.py +253 -22
  31. cartography/intel/aws/apigatewayv2.py +116 -0
  32. cartography/intel/aws/cloudtrail.py +17 -39
  33. cartography/intel/aws/cloudtrail_management_events.py +962 -0
  34. cartography/intel/aws/cloudwatch.py +150 -4
  35. cartography/intel/aws/codebuild.py +132 -0
  36. cartography/intel/aws/cognito.py +201 -0
  37. cartography/intel/aws/config.py +7 -3
  38. cartography/intel/aws/ec2/elastic_ip_addresses.py +3 -1
  39. cartography/intel/aws/ec2/instances.py +25 -1
  40. cartography/intel/aws/ec2/internet_gateways.py +4 -2
  41. cartography/intel/aws/ec2/load_balancer_v2s.py +11 -5
  42. cartography/intel/aws/ec2/network_interfaces.py +5 -1
  43. cartography/intel/aws/ec2/reserved_instances.py +3 -1
  44. cartography/intel/aws/ec2/security_groups.py +140 -122
  45. cartography/intel/aws/ec2/snapshots.py +47 -84
  46. cartography/intel/aws/ec2/subnets.py +37 -63
  47. cartography/intel/aws/ec2/tgw.py +11 -5
  48. cartography/intel/aws/ec2/volumes.py +1 -1
  49. cartography/intel/aws/ec2/vpc.py +140 -124
  50. cartography/intel/aws/ec2/vpc_peerings.py +262 -125
  51. cartography/intel/aws/ecr.py +269 -98
  52. cartography/intel/aws/ecr_image_layers.py +923 -0
  53. cartography/intel/aws/ecs.py +251 -380
  54. cartography/intel/aws/efs.py +179 -11
  55. cartography/intel/aws/elasticache.py +102 -79
  56. cartography/intel/aws/elasticsearch.py +13 -4
  57. cartography/intel/aws/eventbridge.py +164 -0
  58. cartography/intel/aws/glue.py +181 -0
  59. cartography/intel/aws/guardduty.py +443 -0
  60. cartography/intel/aws/iam.py +750 -493
  61. cartography/intel/aws/identitycenter.py +605 -83
  62. cartography/intel/aws/inspector.py +221 -105
  63. cartography/intel/aws/kms.py +173 -201
  64. cartography/intel/aws/lambda_function.py +272 -189
  65. cartography/intel/aws/organizations.py +10 -9
  66. cartography/intel/aws/permission_relationships.py +10 -20
  67. cartography/intel/aws/rds.py +337 -446
  68. cartography/intel/aws/redshift.py +9 -4
  69. cartography/intel/aws/resourcegroupstaggingapi.py +78 -19
  70. cartography/intel/aws/resources.py +18 -0
  71. cartography/intel/aws/route53.py +386 -332
  72. cartography/intel/aws/s3.py +322 -14
  73. cartography/intel/aws/secretsmanager.py +81 -49
  74. cartography/intel/aws/securityhub.py +3 -1
  75. cartography/intel/aws/sns.py +62 -2
  76. cartography/intel/aws/sqs.py +36 -90
  77. cartography/intel/aws/ssm.py +3 -5
  78. cartography/intel/azure/__init__.py +202 -48
  79. cartography/intel/azure/aks.py +175 -0
  80. cartography/intel/azure/app_service.py +105 -0
  81. cartography/intel/azure/compute.py +59 -112
  82. cartography/intel/azure/container_instances.py +95 -0
  83. cartography/intel/azure/cosmosdb.py +222 -361
  84. cartography/intel/azure/data_factory.py +85 -0
  85. cartography/intel/azure/data_factory_dataset.py +128 -0
  86. cartography/intel/azure/data_factory_linked_service.py +119 -0
  87. cartography/intel/azure/data_factory_pipeline.py +142 -0
  88. cartography/intel/azure/data_lake.py +124 -0
  89. cartography/intel/azure/event_grid.py +94 -0
  90. cartography/intel/azure/functions.py +124 -0
  91. cartography/intel/azure/load_balancers.py +263 -0
  92. cartography/intel/azure/logic_apps.py +101 -0
  93. cartography/intel/azure/monitor.py +105 -0
  94. cartography/intel/azure/network.py +467 -0
  95. cartography/intel/azure/permission_relationships.py +466 -0
  96. cartography/intel/azure/rbac.py +309 -0
  97. cartography/intel/azure/resource_groups.py +82 -0
  98. cartography/intel/azure/security_center.py +106 -0
  99. cartography/intel/azure/sql.py +145 -292
  100. cartography/intel/azure/storage.py +185 -262
  101. cartography/intel/azure/subscription.py +21 -43
  102. cartography/intel/azure/tenant.py +39 -30
  103. cartography/intel/azure/util/common.py +13 -0
  104. cartography/intel/azure/util/credentials.py +49 -174
  105. cartography/intel/azure/util/tag.py +41 -0
  106. cartography/intel/create_indexes.py +2 -1
  107. cartography/intel/crowdstrike/spotlight.py +5 -2
  108. cartography/intel/dns.py +5 -2
  109. cartography/intel/entra/__init__.py +100 -1
  110. cartography/intel/entra/app_role_assignments.py +284 -0
  111. cartography/intel/entra/applications.py +182 -0
  112. cartography/intel/entra/federation/__init__.py +0 -0
  113. cartography/intel/entra/federation/aws_identity_center.py +77 -0
  114. cartography/intel/entra/groups.py +198 -0
  115. cartography/intel/entra/ou.py +48 -24
  116. cartography/intel/entra/service_principals.py +217 -0
  117. cartography/intel/entra/users.py +105 -57
  118. cartography/intel/gcp/__init__.py +334 -396
  119. cartography/intel/gcp/bigtable_app_profile.py +101 -0
  120. cartography/intel/gcp/bigtable_backup.py +91 -0
  121. cartography/intel/gcp/bigtable_cluster.py +93 -0
  122. cartography/intel/gcp/bigtable_instance.py +86 -0
  123. cartography/intel/gcp/bigtable_table.py +87 -0
  124. cartography/intel/gcp/cai.py +292 -0
  125. cartography/intel/gcp/clients.py +112 -0
  126. cartography/intel/gcp/compute.py +128 -119
  127. cartography/intel/gcp/crm/__init__.py +0 -0
  128. cartography/intel/gcp/crm/folders.py +114 -0
  129. cartography/intel/gcp/crm/orgs.py +70 -0
  130. cartography/intel/gcp/crm/projects.py +120 -0
  131. cartography/intel/gcp/dns.py +83 -169
  132. cartography/intel/gcp/gke.py +72 -113
  133. cartography/intel/gcp/iam.py +111 -91
  134. cartography/intel/gcp/permission_relationships.py +394 -0
  135. cartography/intel/gcp/policy_bindings.py +225 -0
  136. cartography/intel/gcp/storage.py +75 -159
  137. cartography/intel/github/__init__.py +62 -25
  138. cartography/intel/github/commits.py +423 -0
  139. cartography/intel/github/repos.py +463 -85
  140. cartography/intel/github/teams.py +3 -3
  141. cartography/intel/github/users.py +5 -0
  142. cartography/intel/github/util.py +12 -0
  143. cartography/intel/googleworkspace/__init__.py +193 -0
  144. cartography/intel/googleworkspace/devices.py +254 -0
  145. cartography/intel/googleworkspace/groups.py +568 -0
  146. cartography/intel/googleworkspace/oauth_apps.py +259 -0
  147. cartography/intel/googleworkspace/tenant.py +85 -0
  148. cartography/intel/googleworkspace/users.py +138 -0
  149. cartography/intel/gsuite/__init__.py +17 -9
  150. cartography/intel/gsuite/groups.py +291 -0
  151. cartography/intel/gsuite/users.py +142 -0
  152. cartography/intel/jamf/computers.py +7 -1
  153. cartography/intel/keycloak/__init__.py +153 -0
  154. cartography/intel/keycloak/authenticationexecutions.py +322 -0
  155. cartography/intel/keycloak/authenticationflows.py +77 -0
  156. cartography/intel/keycloak/clients.py +187 -0
  157. cartography/intel/keycloak/groups.py +126 -0
  158. cartography/intel/keycloak/identityproviders.py +94 -0
  159. cartography/intel/keycloak/organizations.py +163 -0
  160. cartography/intel/keycloak/realms.py +61 -0
  161. cartography/intel/keycloak/roles.py +202 -0
  162. cartography/intel/keycloak/scopes.py +73 -0
  163. cartography/intel/keycloak/users.py +70 -0
  164. cartography/intel/keycloak/util.py +47 -0
  165. cartography/intel/kubernetes/__init__.py +60 -14
  166. cartography/intel/kubernetes/clusters.py +86 -0
  167. cartography/intel/kubernetes/eks.py +402 -0
  168. cartography/intel/kubernetes/namespaces.py +59 -57
  169. cartography/intel/kubernetes/pods.py +168 -75
  170. cartography/intel/kubernetes/rbac.py +597 -0
  171. cartography/intel/kubernetes/secrets.py +95 -45
  172. cartography/intel/kubernetes/services.py +131 -67
  173. cartography/intel/kubernetes/util.py +142 -14
  174. cartography/intel/oci/iam.py +23 -9
  175. cartography/intel/oci/organizations.py +3 -1
  176. cartography/intel/oci/utils.py +28 -5
  177. cartography/intel/okta/applications.py +15 -5
  178. cartography/intel/okta/awssaml.py +14 -10
  179. cartography/intel/okta/factors.py +3 -1
  180. cartography/intel/okta/groups.py +5 -2
  181. cartography/intel/okta/organization.py +3 -1
  182. cartography/intel/okta/origins.py +3 -1
  183. cartography/intel/okta/roles.py +5 -2
  184. cartography/intel/okta/users.py +10 -2
  185. cartography/intel/ontology/__init__.py +44 -0
  186. cartography/intel/ontology/devices.py +54 -0
  187. cartography/intel/ontology/users.py +54 -0
  188. cartography/intel/ontology/utils.py +176 -0
  189. cartography/intel/pagerduty/escalation_policies.py +13 -6
  190. cartography/intel/pagerduty/schedules.py +9 -4
  191. cartography/intel/pagerduty/services.py +7 -3
  192. cartography/intel/pagerduty/teams.py +5 -2
  193. cartography/intel/pagerduty/users.py +3 -1
  194. cartography/intel/pagerduty/vendors.py +3 -1
  195. cartography/intel/scaleway/__init__.py +127 -0
  196. cartography/intel/scaleway/iam/__init__.py +0 -0
  197. cartography/intel/scaleway/iam/apikeys.py +71 -0
  198. cartography/intel/scaleway/iam/applications.py +71 -0
  199. cartography/intel/scaleway/iam/groups.py +71 -0
  200. cartography/intel/scaleway/iam/users.py +71 -0
  201. cartography/intel/scaleway/instances/__init__.py +0 -0
  202. cartography/intel/scaleway/instances/flexibleips.py +86 -0
  203. cartography/intel/scaleway/instances/instances.py +92 -0
  204. cartography/intel/scaleway/projects.py +79 -0
  205. cartography/intel/scaleway/storage/__init__.py +0 -0
  206. cartography/intel/scaleway/storage/snapshots.py +86 -0
  207. cartography/intel/scaleway/storage/volumes.py +84 -0
  208. cartography/intel/scaleway/utils.py +37 -0
  209. cartography/intel/sentinelone/__init__.py +75 -0
  210. cartography/intel/sentinelone/account.py +140 -0
  211. cartography/intel/sentinelone/agent.py +139 -0
  212. cartography/intel/sentinelone/api.py +124 -0
  213. cartography/intel/sentinelone/application.py +248 -0
  214. cartography/intel/sentinelone/cve.py +119 -0
  215. cartography/intel/sentinelone/utils.py +28 -0
  216. cartography/intel/slack/__init__.py +78 -0
  217. cartography/intel/slack/channels.py +80 -0
  218. cartography/intel/slack/groups.py +90 -0
  219. cartography/intel/slack/teams.py +65 -0
  220. cartography/intel/slack/users.py +57 -0
  221. cartography/intel/slack/utils.py +29 -0
  222. cartography/intel/spacelift/__init__.py +161 -0
  223. cartography/intel/spacelift/account.py +73 -0
  224. cartography/intel/spacelift/ec2_ownership.py +280 -0
  225. cartography/intel/spacelift/runs.py +463 -0
  226. cartography/intel/spacelift/spaces.py +112 -0
  227. cartography/intel/spacelift/stacks.py +119 -0
  228. cartography/intel/spacelift/util.py +122 -0
  229. cartography/intel/spacelift/workerpools.py +131 -0
  230. cartography/intel/spacelift/workers.py +128 -0
  231. cartography/intel/trivy/__init__.py +272 -0
  232. cartography/intel/trivy/scanner.py +386 -0
  233. cartography/models/airbyte/__init__.py +0 -0
  234. cartography/models/airbyte/connection.py +138 -0
  235. cartography/models/airbyte/destination.py +75 -0
  236. cartography/models/airbyte/organization.py +19 -0
  237. cartography/models/airbyte/source.py +75 -0
  238. cartography/models/airbyte/stream.py +74 -0
  239. cartography/models/airbyte/tag.py +69 -0
  240. cartography/models/airbyte/user.py +115 -0
  241. cartography/models/airbyte/workspace.py +46 -0
  242. cartography/models/anthropic/apikey.py +4 -0
  243. cartography/models/anthropic/user.py +4 -0
  244. cartography/models/aws/acm/__init__.py +0 -0
  245. cartography/models/aws/acm/certificate.py +75 -0
  246. cartography/models/aws/apigateway/__init__.py +0 -0
  247. cartography/models/aws/apigateway/apigatewaydeployment.py +74 -0
  248. cartography/models/aws/apigateway/apigatewayintegration.py +79 -0
  249. cartography/models/aws/apigateway/apigatewaymethod.py +74 -0
  250. cartography/models/aws/apigatewayv2/__init__.py +0 -0
  251. cartography/models/aws/apigatewayv2/apigatewayv2.py +53 -0
  252. cartography/models/aws/cloudtrail/management_events.py +153 -0
  253. cartography/models/aws/cloudtrail/trail.py +45 -0
  254. cartography/models/aws/cloudwatch/log_metric_filter.py +79 -0
  255. cartography/models/aws/cloudwatch/metric_alarm.py +53 -0
  256. cartography/models/aws/codebuild/__init__.py +0 -0
  257. cartography/models/aws/codebuild/project.py +49 -0
  258. cartography/models/aws/cognito/__init__.py +0 -0
  259. cartography/models/aws/cognito/identity_pool.py +70 -0
  260. cartography/models/aws/cognito/user_pool.py +47 -0
  261. cartography/models/aws/dynamodb/tables.py +2 -0
  262. cartography/models/aws/ec2/instances.py +25 -1
  263. cartography/models/aws/ec2/networkinterfaces.py +4 -0
  264. cartography/models/aws/ec2/security_group_rules.py +109 -0
  265. cartography/models/aws/ec2/security_groups.py +90 -0
  266. cartography/models/aws/ec2/snapshots.py +58 -0
  267. cartography/models/aws/ec2/subnet_instance.py +2 -0
  268. cartography/models/aws/ec2/subnet_networkinterface.py +2 -0
  269. cartography/models/aws/ec2/subnets.py +65 -0
  270. cartography/models/aws/ec2/volumes.py +20 -0
  271. cartography/models/aws/ec2/vpc.py +46 -0
  272. cartography/models/aws/ec2/vpc_cidr.py +102 -0
  273. cartography/models/aws/ec2/vpc_peering.py +157 -0
  274. cartography/models/aws/ecr/__init__.py +0 -0
  275. cartography/models/aws/ecr/image.py +146 -0
  276. cartography/models/aws/ecr/image_layer.py +107 -0
  277. cartography/models/aws/ecr/repository.py +72 -0
  278. cartography/models/aws/ecr/repository_image.py +95 -0
  279. cartography/models/aws/ecs/__init__.py +0 -0
  280. cartography/models/aws/ecs/clusters.py +64 -0
  281. cartography/models/aws/ecs/container_definitions.py +93 -0
  282. cartography/models/aws/ecs/container_instances.py +84 -0
  283. cartography/models/aws/ecs/containers.py +101 -0
  284. cartography/models/aws/ecs/services.py +134 -0
  285. cartography/models/aws/ecs/task_definitions.py +135 -0
  286. cartography/models/aws/ecs/tasks.py +134 -0
  287. cartography/models/aws/efs/access_point.py +77 -0
  288. cartography/models/aws/efs/file_system.py +60 -0
  289. cartography/models/aws/efs/mount_target.py +29 -2
  290. cartography/models/aws/elasticache/__init__.py +0 -0
  291. cartography/models/aws/elasticache/cluster.py +65 -0
  292. cartography/models/aws/elasticache/topic.py +67 -0
  293. cartography/models/aws/eventbridge/__init__.py +0 -0
  294. cartography/models/aws/eventbridge/rule.py +77 -0
  295. cartography/models/aws/eventbridge/target.py +71 -0
  296. cartography/models/aws/glue/__init__.py +0 -0
  297. cartography/models/aws/glue/connection.py +51 -0
  298. cartography/models/aws/glue/job.py +69 -0
  299. cartography/models/aws/guardduty/__init__.py +1 -0
  300. cartography/models/aws/guardduty/detectors.py +50 -0
  301. cartography/models/aws/guardduty/findings.py +121 -0
  302. cartography/models/aws/iam/access_key.py +103 -0
  303. cartography/models/aws/iam/account_role.py +24 -0
  304. cartography/models/aws/iam/federated_principal.py +60 -0
  305. cartography/models/aws/iam/group.py +60 -0
  306. cartography/models/aws/iam/group_membership.py +27 -0
  307. cartography/models/aws/iam/inline_policy.py +78 -0
  308. cartography/models/aws/iam/managed_policy.py +51 -0
  309. cartography/models/aws/iam/policy_statement.py +57 -0
  310. cartography/models/aws/iam/role.py +83 -0
  311. cartography/models/aws/iam/root_principal.py +52 -0
  312. cartography/models/aws/iam/service_principal.py +30 -0
  313. cartography/models/aws/iam/sts_assumerole_allow.py +38 -0
  314. cartography/models/aws/iam/user.py +59 -0
  315. cartography/models/aws/identitycenter/awsidentitycenter.py +1 -0
  316. cartography/models/aws/identitycenter/awspermissionset.py +70 -0
  317. cartography/models/aws/identitycenter/awssogroup.py +70 -0
  318. cartography/models/aws/identitycenter/awsssouser.py +49 -9
  319. cartography/models/aws/inspector/findings.py +37 -0
  320. cartography/models/aws/inspector/packages.py +1 -31
  321. cartography/models/aws/kms/__init__.py +0 -0
  322. cartography/models/aws/kms/aliases.py +86 -0
  323. cartography/models/aws/kms/grants.py +65 -0
  324. cartography/models/aws/kms/keys.py +88 -0
  325. cartography/models/aws/lambda_function/__init__.py +0 -0
  326. cartography/models/aws/lambda_function/alias.py +74 -0
  327. cartography/models/aws/lambda_function/event_source_mapping.py +88 -0
  328. cartography/models/aws/lambda_function/lambda_function.py +91 -0
  329. cartography/models/aws/lambda_function/layer.py +72 -0
  330. cartography/models/aws/rds/__init__.py +0 -0
  331. cartography/models/aws/rds/cluster.py +91 -0
  332. cartography/models/aws/rds/event_subscription.py +146 -0
  333. cartography/models/aws/rds/instance.py +156 -0
  334. cartography/models/aws/rds/snapshot.py +108 -0
  335. cartography/models/aws/rds/subnet_group.py +101 -0
  336. cartography/models/aws/route53/__init__.py +0 -0
  337. cartography/models/aws/route53/dnsrecord.py +235 -0
  338. cartography/models/aws/route53/nameserver.py +63 -0
  339. cartography/models/aws/route53/subzone.py +40 -0
  340. cartography/models/aws/route53/zone.py +47 -0
  341. cartography/models/aws/s3/notification.py +24 -0
  342. cartography/models/aws/secretsmanager/secret.py +106 -0
  343. cartography/models/aws/secretsmanager/secret_version.py +0 -2
  344. cartography/models/aws/sns/topic_subscription.py +74 -0
  345. cartography/models/aws/sqs/__init__.py +0 -0
  346. cartography/models/aws/sqs/queue.py +89 -0
  347. cartography/models/azure/__init__.py +0 -0
  348. cartography/models/azure/aks_cluster.py +54 -0
  349. cartography/models/azure/aks_nodepool.py +54 -0
  350. cartography/models/azure/app_service.py +59 -0
  351. cartography/models/azure/container_instance.py +57 -0
  352. cartography/models/azure/cosmosdb/__init__.py +0 -0
  353. cartography/models/azure/cosmosdb/account.py +77 -0
  354. cartography/models/azure/cosmosdb/accountfailoverpolicy.py +77 -0
  355. cartography/models/azure/cosmosdb/cassandrakeyspace.py +82 -0
  356. cartography/models/azure/cosmosdb/cassandratable.py +81 -0
  357. cartography/models/azure/cosmosdb/corspolicy.py +74 -0
  358. cartography/models/azure/cosmosdb/dblocation.py +120 -0
  359. cartography/models/azure/cosmosdb/mongodbcollection.py +82 -0
  360. cartography/models/azure/cosmosdb/mongodbdatabase.py +78 -0
  361. cartography/models/azure/cosmosdb/privateendpointconnection.py +81 -0
  362. cartography/models/azure/cosmosdb/sqlcontainer.py +88 -0
  363. cartography/models/azure/cosmosdb/sqldatabase.py +78 -0
  364. cartography/models/azure/cosmosdb/tableresource.py +76 -0
  365. cartography/models/azure/cosmosdb/virtualnetworkrule.py +78 -0
  366. cartography/models/azure/data_factory/__init__.py +0 -0
  367. cartography/models/azure/data_factory/data_factory.py +51 -0
  368. cartography/models/azure/data_factory/data_factory_dataset.py +94 -0
  369. cartography/models/azure/data_factory/data_factory_linked_service.py +78 -0
  370. cartography/models/azure/data_factory/data_factory_pipeline.py +93 -0
  371. cartography/models/azure/data_lake_filesystem.py +51 -0
  372. cartography/models/azure/event_grid_topic.py +57 -0
  373. cartography/models/azure/function_app.py +59 -0
  374. cartography/models/azure/load_balancer/__init__.py +0 -0
  375. cartography/models/azure/load_balancer/load_balancer.py +49 -0
  376. cartography/models/azure/load_balancer/load_balancer_backend_pool.py +73 -0
  377. cartography/models/azure/load_balancer/load_balancer_frontend_ip.py +75 -0
  378. cartography/models/azure/load_balancer/load_balancer_inbound_nat_rule.py +78 -0
  379. cartography/models/azure/load_balancer/load_balancer_rule.py +108 -0
  380. cartography/models/azure/logic_apps.py +56 -0
  381. cartography/models/azure/monitor.py +54 -0
  382. cartography/models/azure/network_interface.py +112 -0
  383. cartography/models/azure/network_security_group.py +50 -0
  384. cartography/models/azure/permission_relationships.py +60 -0
  385. cartography/models/azure/principal.py +41 -0
  386. cartography/models/azure/public_ip_address.py +50 -0
  387. cartography/models/azure/rbac.py +268 -0
  388. cartography/models/azure/resource_groups.py +52 -0
  389. cartography/models/azure/security_center.py +50 -0
  390. cartography/models/azure/sql/__init__.py +0 -0
  391. cartography/models/azure/sql/databasethreatdetectionpolicy.py +85 -0
  392. cartography/models/azure/sql/elasticpool.py +77 -0
  393. cartography/models/azure/sql/failovergroup.py +73 -0
  394. cartography/models/azure/sql/recoverabledatabase.py +75 -0
  395. cartography/models/azure/sql/replicationlink.py +81 -0
  396. cartography/models/azure/sql/restorabledroppeddatabase.py +82 -0
  397. cartography/models/azure/sql/restorepoint.py +74 -0
  398. cartography/models/azure/sql/serveradadministrator.py +74 -0
  399. cartography/models/azure/sql/serverdnsalias.py +71 -0
  400. cartography/models/azure/sql/sqldatabase.py +85 -0
  401. cartography/models/azure/sql/sqlserver.py +50 -0
  402. cartography/models/azure/sql/transparentdataencryption.py +76 -0
  403. cartography/models/azure/storage/__init__.py +0 -0
  404. cartography/models/azure/storage/account.py +59 -0
  405. cartography/models/azure/storage/blobcontainer.py +85 -0
  406. cartography/models/azure/storage/blobservice.py +71 -0
  407. cartography/models/azure/storage/fileservice.py +71 -0
  408. cartography/models/azure/storage/fileshare.py +82 -0
  409. cartography/models/azure/storage/queue.py +71 -0
  410. cartography/models/azure/storage/queueservice.py +73 -0
  411. cartography/models/azure/storage/table.py +72 -0
  412. cartography/models/azure/storage/tableservice.py +73 -0
  413. cartography/models/azure/subnet.py +101 -0
  414. cartography/models/azure/subscription.py +47 -0
  415. cartography/models/azure/tags/__init__.py +0 -0
  416. cartography/models/azure/tags/storage_tag.py +40 -0
  417. cartography/models/azure/tags/tag.py +37 -0
  418. cartography/models/azure/tenant.py +17 -0
  419. cartography/models/azure/virtual_network.py +49 -0
  420. cartography/models/azure/vm/__init__.py +0 -0
  421. cartography/models/azure/vm/datadisk.py +80 -0
  422. cartography/models/azure/vm/disk.py +55 -0
  423. cartography/models/azure/vm/snapshot.py +56 -0
  424. cartography/models/azure/vm/virtualmachine.py +59 -0
  425. cartography/models/bigfix/bigfix_computer.py +1 -1
  426. cartography/models/cloudflare/member.py +4 -0
  427. cartography/models/core/common.py +1 -0
  428. cartography/models/core/nodes.py +15 -2
  429. cartography/models/core/relationships.py +44 -0
  430. cartography/models/crowdstrike/hosts.py +1 -1
  431. cartography/models/digitalocean/droplet.py +2 -0
  432. cartography/models/duo/endpoint.py +1 -1
  433. cartography/models/duo/phone.py +2 -2
  434. cartography/models/duo/user.py +4 -0
  435. cartography/models/entra/app_role_assignment.py +115 -0
  436. cartography/models/entra/application.py +49 -0
  437. cartography/models/entra/entra_user_to_aws_sso.py +41 -0
  438. cartography/models/entra/group.py +117 -0
  439. cartography/models/entra/service_principal.py +104 -0
  440. cartography/models/entra/user.py +42 -51
  441. cartography/models/gcp/__init__.py +0 -0
  442. cartography/models/gcp/bigtable/__init__.py +0 -0
  443. cartography/models/gcp/bigtable/app_profile.py +94 -0
  444. cartography/models/gcp/bigtable/backup.py +91 -0
  445. cartography/models/gcp/bigtable/cluster.py +73 -0
  446. cartography/models/gcp/bigtable/instance.py +52 -0
  447. cartography/models/gcp/bigtable/table.py +69 -0
  448. cartography/models/gcp/compute/__init__.py +0 -0
  449. cartography/models/gcp/compute/subnet.py +74 -0
  450. cartography/models/gcp/compute/vpc.py +50 -0
  451. cartography/models/gcp/crm/__init__.py +0 -0
  452. cartography/models/gcp/crm/folders.py +98 -0
  453. cartography/models/gcp/crm/organizations.py +21 -0
  454. cartography/models/gcp/crm/projects.py +100 -0
  455. cartography/models/gcp/dns.py +109 -0
  456. cartography/models/gcp/gke.py +69 -0
  457. cartography/models/gcp/iam.py +3 -0
  458. cartography/models/gcp/permission_relationships.py +61 -0
  459. cartography/models/gcp/policy_bindings.py +93 -0
  460. cartography/models/gcp/storage/__init__.py +0 -0
  461. cartography/models/gcp/storage/bucket.py +119 -0
  462. cartography/models/github/commits.py +63 -0
  463. cartography/models/github/dependencies.py +73 -0
  464. cartography/models/github/manifests.py +49 -0
  465. cartography/models/github/users.py +10 -0
  466. cartography/models/googleworkspace/__init__.py +0 -0
  467. cartography/models/googleworkspace/device.py +132 -0
  468. cartography/models/googleworkspace/group.py +382 -0
  469. cartography/models/googleworkspace/oauth_app.py +124 -0
  470. cartography/models/googleworkspace/tenant.py +30 -0
  471. cartography/models/googleworkspace/user.py +113 -0
  472. cartography/models/gsuite/__init__.py +0 -0
  473. cartography/models/gsuite/group.py +218 -0
  474. cartography/models/gsuite/tenant.py +29 -0
  475. cartography/models/gsuite/user.py +107 -0
  476. cartography/models/kandji/device.py +1 -2
  477. cartography/models/keycloak/__init__.py +0 -0
  478. cartography/models/keycloak/authenticationexecution.py +160 -0
  479. cartography/models/keycloak/authenticationflow.py +54 -0
  480. cartography/models/keycloak/client.py +179 -0
  481. cartography/models/keycloak/group.py +101 -0
  482. cartography/models/keycloak/identityprovider.py +89 -0
  483. cartography/models/keycloak/organization.py +116 -0
  484. cartography/models/keycloak/organizationdomain.py +73 -0
  485. cartography/models/keycloak/realm.py +173 -0
  486. cartography/models/keycloak/role.py +126 -0
  487. cartography/models/keycloak/scope.py +73 -0
  488. cartography/models/keycloak/user.py +55 -0
  489. cartography/models/kubernetes/__init__.py +0 -0
  490. cartography/models/kubernetes/clusterrolebindings.py +138 -0
  491. cartography/models/kubernetes/clusterroles.py +52 -0
  492. cartography/models/kubernetes/clusters.py +26 -0
  493. cartography/models/kubernetes/containers.py +133 -0
  494. cartography/models/kubernetes/groups.py +107 -0
  495. cartography/models/kubernetes/namespaces.py +51 -0
  496. cartography/models/kubernetes/oidc.py +51 -0
  497. cartography/models/kubernetes/pods.py +80 -0
  498. cartography/models/kubernetes/rolebindings.py +159 -0
  499. cartography/models/kubernetes/roles.py +76 -0
  500. cartography/models/kubernetes/secrets.py +79 -0
  501. cartography/models/kubernetes/serviceaccounts.py +77 -0
  502. cartography/models/kubernetes/services.py +108 -0
  503. cartography/models/kubernetes/users.py +105 -0
  504. cartography/models/lastpass/user.py +4 -0
  505. cartography/models/ontology/__init__.py +0 -0
  506. cartography/models/ontology/device.py +137 -0
  507. cartography/models/ontology/mapping/__init__.py +76 -0
  508. cartography/models/ontology/mapping/data/__init__.py +0 -0
  509. cartography/models/ontology/mapping/data/apikeys.py +93 -0
  510. cartography/models/ontology/mapping/data/computeinstance.py +95 -0
  511. cartography/models/ontology/mapping/data/containers.py +88 -0
  512. cartography/models/ontology/mapping/data/databases.py +182 -0
  513. cartography/models/ontology/mapping/data/devices.py +194 -0
  514. cartography/models/ontology/mapping/data/thirdpartyapps.py +140 -0
  515. cartography/models/ontology/mapping/data/useraccounts.py +416 -0
  516. cartography/models/ontology/mapping/data/users.py +63 -0
  517. cartography/models/ontology/mapping/specs.py +85 -0
  518. cartography/models/ontology/user.py +51 -0
  519. cartography/models/openai/adminapikey.py +4 -0
  520. cartography/models/openai/apikey.py +4 -0
  521. cartography/models/openai/user.py +4 -0
  522. cartography/models/scaleway/__init__.py +0 -0
  523. cartography/models/scaleway/iam/__init__.py +0 -0
  524. cartography/models/scaleway/iam/apikey.py +100 -0
  525. cartography/models/scaleway/iam/application.py +52 -0
  526. cartography/models/scaleway/iam/group.py +95 -0
  527. cartography/models/scaleway/iam/user.py +64 -0
  528. cartography/models/scaleway/instance/__init__.py +0 -0
  529. cartography/models/scaleway/instance/flexibleip.py +52 -0
  530. cartography/models/scaleway/instance/instance.py +120 -0
  531. cartography/models/scaleway/organization.py +19 -0
  532. cartography/models/scaleway/project.py +48 -0
  533. cartography/models/scaleway/storage/__init__.py +0 -0
  534. cartography/models/scaleway/storage/snapshot.py +78 -0
  535. cartography/models/scaleway/storage/volume.py +51 -0
  536. cartography/models/sentinelone/__init__.py +1 -0
  537. cartography/models/sentinelone/account.py +40 -0
  538. cartography/models/sentinelone/agent.py +50 -0
  539. cartography/models/sentinelone/application.py +44 -0
  540. cartography/models/sentinelone/application_version.py +96 -0
  541. cartography/models/sentinelone/cve.py +73 -0
  542. cartography/models/slack/__init__.py +0 -0
  543. cartography/models/slack/channels.py +92 -0
  544. cartography/models/slack/group.py +129 -0
  545. cartography/models/slack/team.py +22 -0
  546. cartography/models/slack/user.py +62 -0
  547. cartography/models/snipeit/asset.py +2 -0
  548. cartography/models/snipeit/user.py +4 -0
  549. cartography/models/spacelift/__init__.py +0 -0
  550. cartography/models/spacelift/cloudtrailevent.py +120 -0
  551. cartography/models/spacelift/run.py +162 -0
  552. cartography/models/spacelift/space.py +131 -0
  553. cartography/models/spacelift/spaceliftaccount.py +31 -0
  554. cartography/models/spacelift/spaceliftgitcommit.py +157 -0
  555. cartography/models/spacelift/stack.py +96 -0
  556. cartography/models/spacelift/user.py +63 -0
  557. cartography/models/spacelift/worker.py +97 -0
  558. cartography/models/spacelift/workerpool.py +90 -0
  559. cartography/models/tailscale/device.py +2 -1
  560. cartography/models/tailscale/user.py +6 -1
  561. cartography/models/trivy/__init__.py +0 -0
  562. cartography/models/trivy/findings.py +66 -0
  563. cartography/models/trivy/fix.py +66 -0
  564. cartography/models/trivy/package.py +71 -0
  565. cartography/rules/README.md +1 -0
  566. cartography/rules/__init__.py +0 -0
  567. cartography/rules/cli.py +261 -0
  568. cartography/rules/data/__init__.py +0 -0
  569. cartography/rules/data/rules/__init__.py +46 -0
  570. cartography/rules/data/rules/cloud_security_product_deactivated.py +49 -0
  571. cartography/rules/data/rules/compute_instance_exposed.py +51 -0
  572. cartography/rules/data/rules/database_instance_exposed.py +53 -0
  573. cartography/rules/data/rules/delegation_boundary_modifiable.py +90 -0
  574. cartography/rules/data/rules/identity_administration_privileges.py +100 -0
  575. cartography/rules/data/rules/inactive_user_active_accounts.py +48 -0
  576. cartography/rules/data/rules/malicious_npm_dependencies_shai_hulud.py +2222 -0
  577. cartography/rules/data/rules/mfa_missing.py +46 -0
  578. cartography/rules/data/rules/object_storage_public.py +100 -0
  579. cartography/rules/data/rules/policy_administration_privileges.py +104 -0
  580. cartography/rules/data/rules/unmanaged_accounts.py +43 -0
  581. cartography/rules/data/rules/workload_identity_admin_capabilities.py +193 -0
  582. cartography/rules/formatters.py +108 -0
  583. cartography/rules/runners.py +216 -0
  584. cartography/rules/spec/__init__.py +0 -0
  585. cartography/rules/spec/model.py +267 -0
  586. cartography/rules/spec/result.py +38 -0
  587. cartography/sync.py +25 -5
  588. cartography/util.py +101 -31
  589. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/METADATA +61 -22
  590. cartography-0.123.0.dist-info/RECORD +856 -0
  591. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/entry_points.txt +1 -0
  592. cartography/data/jobs/cleanup/aws_dns_cleanup.json +0 -65
  593. cartography/data/jobs/cleanup/aws_import_account_access_key_cleanup.json +0 -17
  594. cartography/data/jobs/cleanup/aws_import_ec2_security_groupinfo_cleanup.json +0 -24
  595. cartography/data/jobs/cleanup/aws_import_groups_cleanup.json +0 -13
  596. cartography/data/jobs/cleanup/aws_import_identity_center_cleanup.json +0 -16
  597. cartography/data/jobs/cleanup/aws_import_lambda_cleanup.json +0 -50
  598. cartography/data/jobs/cleanup/aws_import_principals_cleanup.json +0 -30
  599. cartography/data/jobs/cleanup/aws_import_rds_clusters_cleanup.json +0 -23
  600. cartography/data/jobs/cleanup/aws_import_rds_instances_cleanup.json +0 -47
  601. cartography/data/jobs/cleanup/aws_import_rds_snapshots_cleanup.json +0 -23
  602. cartography/data/jobs/cleanup/aws_import_roles_cleanup.json +0 -13
  603. cartography/data/jobs/cleanup/aws_import_secrets_cleanup.json +0 -8
  604. cartography/data/jobs/cleanup/aws_import_snapshots_cleanup.json +0 -30
  605. cartography/data/jobs/cleanup/aws_import_users_cleanup.json +0 -8
  606. cartography/data/jobs/cleanup/aws_import_vpc_cleanup.json +0 -23
  607. cartography/data/jobs/cleanup/aws_import_vpc_peering_cleanup.json +0 -45
  608. cartography/data/jobs/cleanup/aws_kms_details.json +0 -10
  609. cartography/data/jobs/cleanup/azure_cosmosdb_cassandra_keyspace_cleanup.json +0 -25
  610. cartography/data/jobs/cleanup/azure_cosmosdb_cors_details.json +0 -15
  611. cartography/data/jobs/cleanup/azure_cosmosdb_mongodb_database_cleanup.json +0 -25
  612. cartography/data/jobs/cleanup/azure_cosmosdb_sql_database_cleanup.json +0 -25
  613. cartography/data/jobs/cleanup/azure_cosmosdb_table_resources_cleanup.json +0 -15
  614. cartography/data/jobs/cleanup/azure_database_account_cleanup.json +0 -85
  615. cartography/data/jobs/cleanup/azure_import_disks_cleanup.json +0 -15
  616. cartography/data/jobs/cleanup/azure_import_snapshots_cleanup.json +0 -15
  617. cartography/data/jobs/cleanup/azure_import_virtual_machines_cleanup.json +0 -25
  618. cartography/data/jobs/cleanup/azure_sql_server_cleanup.json +0 -125
  619. cartography/data/jobs/cleanup/azure_storage_account_cleanup.json +0 -95
  620. cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json +0 -14
  621. cartography/data/jobs/cleanup/azure_tenant_cleanup.json +0 -9
  622. cartography/data/jobs/cleanup/gcp_compute_vpc_subnet_cleanup.json +0 -35
  623. cartography/data/jobs/cleanup/gcp_crm_folder_cleanup.json +0 -23
  624. cartography/data/jobs/cleanup/gcp_crm_organization_cleanup.json +0 -17
  625. cartography/data/jobs/cleanup/gcp_crm_project_cleanup.json +0 -23
  626. cartography/data/jobs/cleanup/gcp_dns_cleanup.json +0 -29
  627. cartography/data/jobs/cleanup/gcp_gke_cluster_cleanup.json +0 -17
  628. cartography/data/jobs/cleanup/gcp_storage_bucket_cleanup.json +0 -29
  629. cartography/data/jobs/cleanup/gsuite_ingest_groups_cleanup.json +0 -23
  630. cartography/data/jobs/cleanup/gsuite_ingest_users_cleanup.json +0 -11
  631. cartography/data/jobs/cleanup/kubernetes_import_cleanup.json +0 -70
  632. cartography/intel/gcp/crm.py +0 -355
  633. cartography/intel/gsuite/api.py +0 -342
  634. cartography-0.104.0rc2.dist-info/RECORD +0 -455
  635. /cartography/data/jobs/{analysis → scoped_analysis}/aws_s3acl_analysis.json +0 -0
  636. /cartography/models/aws/{apigateway.py → apigateway/apigateway.py} +0 -0
  637. /cartography/models/aws/{apigatewaycertificate.py → apigateway/apigatewaycertificate.py} +0 -0
  638. /cartography/models/aws/{apigatewayresource.py → apigateway/apigatewayresource.py} +0 -0
  639. /cartography/models/aws/{apigatewaystage.py → apigateway/apigatewaystage.py} +0 -0
  640. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/WHEEL +0 -0
  641. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/licenses/LICENSE +0 -0
  642. {cartography-0.104.0rc2.dist-info → cartography-0.123.0.dist-info}/top_level.txt +0 -0
@@ -1,260 +1,80 @@
1
1
  import logging
2
- from typing import Dict
3
- from typing import List
4
- from typing import Optional
5
- from typing import Tuple
2
+ from collections import namedtuple
3
+ from typing import Any
6
4
 
7
5
  import boto3
8
6
  import botocore
9
7
  import neo4j
10
8
 
11
- from cartography.util import run_cleanup_job
9
+ from cartography.client.core.tx import load
10
+ from cartography.client.core.tx import load_matchlinks
11
+ from cartography.client.core.tx import read_list_of_dicts_tx
12
+ from cartography.graph.job import GraphJob
13
+ from cartography.models.aws.route53.dnsrecord import AWSDNSRecordSchema
14
+ from cartography.models.aws.route53.nameserver import NameServerSchema
15
+ from cartography.models.aws.route53.subzone import AWSDNSZoneSubzoneMatchLink
16
+ from cartography.models.aws.route53.zone import AWSDNSZoneSchema
17
+ from cartography.util import aws_handle_regions
12
18
  from cartography.util import timeit
13
19
 
14
20
  logger = logging.getLogger(__name__)
15
21
 
22
+ DnsData = namedtuple(
23
+ "DnsData",
24
+ [
25
+ "zones",
26
+ "a_records",
27
+ "aaaa_records",
28
+ "alias_records",
29
+ "cname_records",
30
+ "ns_records",
31
+ "name_servers",
32
+ ],
33
+ )
16
34
 
17
- @timeit
18
- def link_aws_resources(neo4j_session: neo4j.Session, update_tag: int) -> None:
19
- # find records that point to other records
20
- link_records = """
21
- MATCH (n:AWSDNSRecord) WITH n MATCH (v:AWSDNSRecord{value: n.name})
22
- WHERE NOT n = v
23
- MERGE (v)-[p:DNS_POINTS_TO]->(n)
24
- ON CREATE SET p.firstseen = timestamp()
25
- SET p.lastupdated = $update_tag
26
- """
27
- neo4j_session.run(link_records, update_tag=update_tag)
28
-
29
- # find records that point to AWS LoadBalancers
30
- link_elb = """
31
- MATCH (n:AWSDNSRecord) WITH n MATCH (l:LoadBalancer{dnsname: n.value})
32
- MERGE (n)-[p:DNS_POINTS_TO]->(l)
33
- ON CREATE SET p.firstseen = timestamp()
34
- SET p.lastupdated = $update_tag
35
- """
36
- neo4j_session.run(link_elb, update_tag=update_tag)
37
-
38
- # find records that point to AWS LoadBalancersV2
39
- link_elbv2 = """
40
- MATCH (n:AWSDNSRecord) WITH n MATCH (l:LoadBalancerV2{dnsname: n.value})
41
- MERGE (n)-[p:DNS_POINTS_TO]->(l)
42
- ON CREATE SET p.firstseen = timestamp()
43
- SET p.lastupdated = $update_tag
44
- """
45
- neo4j_session.run(link_elbv2, update_tag=update_tag)
46
-
47
- # find records that point to AWS EC2 Instances
48
- link_ec2 = """
49
- MATCH (n:AWSDNSRecord) WITH n MATCH (e:EC2Instance{publicdnsname: n.value})
50
- MERGE (n)-[p:DNS_POINTS_TO]->(e)
51
- ON CREATE SET p.firstseen = timestamp()
52
- SET p.lastupdated = $update_tag
53
- """
54
- neo4j_session.run(link_ec2, update_tag=update_tag)
55
-
56
-
57
- @timeit
58
- def load_a_records(
59
- neo4j_session: neo4j.Session,
60
- records: List[Dict],
61
- update_tag: int,
62
- ) -> None:
63
- ingest_records = """
64
- UNWIND $records as record
65
- MERGE (a:DNSRecord:AWSDNSRecord{id: record.id})
66
- ON CREATE SET
67
- a.firstseen = timestamp(),
68
- a.name = record.name,
69
- a.type = record.type
70
- SET
71
- a.lastupdated = $update_tag,
72
- a.value = record.value
73
- WITH a,record
74
- MATCH (zone:AWSDNSZone{zoneid: record.zoneid})
75
- MERGE (a)-[r:MEMBER_OF_DNS_ZONE]->(zone)
76
- ON CREATE SET r.firstseen = timestamp()
77
- SET r.lastupdated = $update_tag
78
- """
79
- neo4j_session.run(
80
- ingest_records,
81
- records=records,
82
- update_tag=update_tag,
83
- )
84
35
 
85
-
86
- @timeit
87
- def load_alias_records(
88
- neo4j_session: neo4j.Session,
89
- records: List[Dict],
90
- update_tag: int,
91
- ) -> None:
92
- # create the DNSRecord nodes and link them to matching DNSZone and S3Bucket nodes
93
- ingest_records = """
94
- UNWIND $records as record
95
- MERGE (a:DNSRecord:AWSDNSRecord{id: record.id})
96
- ON CREATE SET
97
- a.firstseen = timestamp(),
98
- a.name = record.name,
99
- a.type = record.type
100
- SET
101
- a.lastupdated = $update_tag,
102
- a.value = record.value
103
- WITH a,record
104
- MATCH (zone:AWSDNSZone{zoneid: record.zoneid})
105
- MERGE (a)-[r:MEMBER_OF_DNS_ZONE]->(zone)
106
- ON CREATE SET r.firstseen = timestamp()
107
- SET r.lastupdated = $update_tag
108
- """
109
- neo4j_session.run(
110
- ingest_records,
111
- records=records,
112
- update_tag=update_tag,
113
- )
36
+ def _create_dns_record_id(zoneid: str, name: str, record_type: str) -> str:
37
+ return "/".join([zoneid, name, record_type])
114
38
 
115
39
 
116
- @timeit
117
- def load_cname_records(
118
- neo4j_session: neo4j.Session,
119
- records: List[Dict],
120
- update_tag: int,
121
- ) -> None:
122
- ingest_records = """
123
- UNWIND $records as record
124
- MERGE (a:DNSRecord:AWSDNSRecord{id: record.id})
125
- ON CREATE SET
126
- a.firstseen = timestamp(),
127
- a.name = record.name,
128
- a.type = record.type
129
- SET
130
- a.lastupdated = $update_tag,
131
- a.value = record.value
132
- WITH a,record
133
- MATCH (zone:AWSDNSZone{zoneid: record.zoneid})
134
- MERGE (a)-[r:MEMBER_OF_DNS_ZONE]->(zone)
135
- ON CREATE SET r.firstseen = timestamp()
136
- SET r.lastupdated = $update_tag
137
- """
138
- neo4j_session.run(
139
- ingest_records,
140
- records=records,
141
- update_tag=update_tag,
142
- )
40
+ def _normalize_dns_address(address: str) -> str:
41
+ return address.rstrip(".")
143
42
 
144
43
 
145
44
  @timeit
146
- def load_zone(
147
- neo4j_session: neo4j.Session,
148
- zone: Dict,
149
- current_aws_id: str,
150
- update_tag: int,
151
- ) -> None:
152
- ingest_z = """
153
- MERGE (zone:DNSZone:AWSDNSZone{zoneid:$ZoneId})
154
- ON CREATE SET
155
- zone.firstseen = timestamp(),
156
- zone.name = $ZoneName
157
- SET
158
- zone.lastupdated = $update_tag,
159
- zone.comment = $Comment,
160
- zone.privatezone = $PrivateZone
161
- WITH zone
162
- MATCH (aa:AWSAccount{id: $AWS_ACCOUNT_ID})
163
- MERGE (aa)-[r:RESOURCE]->(zone)
164
- ON CREATE SET r.firstseen = timestamp()
165
- SET r.lastupdated = $update_tag
166
- """
167
- neo4j_session.run(
168
- ingest_z,
169
- ZoneName=zone["name"][:-1],
170
- ZoneId=zone["zoneid"],
171
- Comment=zone["comment"],
172
- PrivateZone=zone["privatezone"],
173
- AWS_ACCOUNT_ID=current_aws_id,
174
- update_tag=update_tag,
175
- )
45
+ def get_zone_record_sets(
46
+ client: botocore.client.BaseClient,
47
+ zone_id: str,
48
+ ) -> list[dict[str, Any]]:
49
+ resource_record_sets: list[dict[str, Any]] = []
50
+ paginator = client.get_paginator("list_resource_record_sets")
51
+ pages = paginator.paginate(HostedZoneId=zone_id)
52
+ for page in pages:
53
+ resource_record_sets.extend(page["ResourceRecordSets"])
54
+ return resource_record_sets
176
55
 
177
56
 
57
+ @aws_handle_regions
178
58
  @timeit
179
- def load_ns_records(
180
- neo4j_session: neo4j.Session,
181
- records: List[Dict],
182
- zone_name: str,
183
- update_tag: int,
184
- ) -> None:
185
- ingest_records = """
186
- UNWIND $records as record
187
- MERGE (a:DNSRecord:AWSDNSRecord{id: record.id})
188
- ON CREATE SET
189
- a.firstseen = timestamp(),
190
- a.name = record.name,
191
- a.type = record.type
192
- SET
193
- a.lastupdated = $update_tag,
194
- a.value = record.name
195
- WITH a,record
196
- MATCH (zone:AWSDNSZone{zoneid: record.zoneid})
197
- MERGE (a)-[r:MEMBER_OF_DNS_ZONE]->(zone)
198
- ON CREATE SET r.firstseen = timestamp()
199
- SET r.lastupdated = $update_tag
200
- WITH a,record
201
- UNWIND record.servers as server
202
- MERGE (ns:NameServer{id:server})
203
- ON CREATE SET ns.firstseen = timestamp()
204
- SET
205
- ns.lastupdated = $update_tag,
206
- ns.name = server
207
- MERGE (a)-[pt:DNS_POINTS_TO]->(ns)
208
- SET pt.lastupdated = $update_tag
209
- """
210
- neo4j_session.run(
211
- ingest_records,
212
- records=records,
213
- update_tag=update_tag,
214
- )
215
-
216
- # Map the official name servers for a domain.
217
- map_ns_records = """
218
- UNWIND $servers as server
219
- MATCH (ns:NameServer{id:server})
220
- MATCH (zone:AWSDNSZone{zoneid:$zoneid})
221
- MERGE (ns)<-[r:NAMESERVER]-(zone)
222
- SET r.lastupdated = $update_tag
223
- """
224
- for record in records:
225
- if zone_name == record["name"]:
226
- neo4j_session.run(
227
- map_ns_records,
228
- servers=record["servers"],
229
- zoneid=record["zoneid"],
230
- update_tag=update_tag,
231
- )
232
-
59
+ def get_zones(
60
+ client: botocore.client.BaseClient,
61
+ ) -> list[tuple[dict[str, Any], list[dict[str, Any]]]]:
62
+ paginator = client.get_paginator("list_hosted_zones")
63
+ hosted_zones: list[dict[str, Any]] = []
64
+ for page in paginator.paginate():
65
+ hosted_zones.extend(page["HostedZones"])
233
66
 
234
- @timeit
235
- def link_sub_zones(neo4j_session: neo4j.Session, update_tag: int) -> None:
236
- query = """
237
- match (z:AWSDNSZone)
238
- <-[:MEMBER_OF_DNS_ZONE]-
239
- (record:DNSRecord{type:"NS"})
240
- -[:DNS_POINTS_TO]->
241
- (ns:NameServer)
242
- <-[:NAMESERVER]-
243
- (z2)
244
- WHERE record.name=z2.name AND NOT z=z2
245
- MERGE (z2)<-[r:SUBZONE]-(z)
246
- ON CREATE SET r.firstseen = timestamp()
247
- SET r.lastupdated = $update_tag
248
- """
249
- neo4j_session.run(
250
- query,
251
- update_tag=update_tag,
252
- )
67
+ results: list[tuple[dict[str, Any], list[dict[str, Any]]]] = []
68
+ for hosted_zone in hosted_zones:
69
+ record_sets = get_zone_record_sets(client, hosted_zone["Id"])
70
+ results.append((hosted_zone, record_sets))
71
+ return results
253
72
 
254
73
 
255
- @timeit
256
- def transform_record_set(record_set: Dict, zone_id: str, name: str) -> Optional[Dict]:
257
- # process CNAME, ALIAS and A records
74
+ def transform_record_set(
75
+ record_set: dict[str, Any], zone_id: str, name: str
76
+ ) -> dict[str, Any] | None:
77
+ # process CNAME, ALIAS, A, and AAAA records
258
78
  if record_set["Type"] == "CNAME":
259
79
  if "AliasTarget" in record_set:
260
80
  # this is a weighted CNAME record
@@ -295,27 +115,53 @@ def transform_record_set(record_set: Dict, zone_id: str, name: str) -> Optional[
295
115
  else:
296
116
  # this is a real A record
297
117
  # loop and add each value (IP address) to a comma separated string
298
- # don't forget to trim that trailing comma!
299
- # TODO can this be replaced with a string join?
300
- value = ""
301
- for a_value in record_set["ResourceRecords"]:
302
- value = value + a_value["Value"] + ","
118
+ # TODO if there are many IPs, this string will be long. we should change this.
119
+ ip_addresses = [record["Value"] for record in record_set["ResourceRecords"]]
120
+ value = ",".join(ip_addresses)
303
121
 
304
122
  return {
305
123
  "name": name,
306
124
  "type": "A",
307
125
  "zoneid": zone_id,
308
- "value": value[:-1],
126
+ # Include the IPs for relationships
127
+ "ip_addresses": ip_addresses,
128
+ "value": value,
309
129
  "id": _create_dns_record_id(zone_id, name, "A"),
310
130
  }
131
+ elif record_set["Type"] == "AAAA":
132
+ if "AliasTarget" in record_set:
133
+ # AAAA alias records follow the same pattern as A aliases but map to IPv6 targets
134
+ value = record_set["AliasTarget"]["DNSName"]
135
+ if value.endswith("."):
136
+ value = value[:-1]
137
+ return {
138
+ "name": name,
139
+ "type": "ALIAS",
140
+ "zoneid": zone_id,
141
+ "value": value,
142
+ "id": _create_dns_record_id(zone_id, name, "ALIAS_AAAA"),
143
+ }
144
+ else:
145
+ ip_addresses = [record["Value"] for record in record_set["ResourceRecords"]]
146
+ value = ",".join(ip_addresses)
311
147
 
312
- else:
313
- return None
314
-
148
+ return {
149
+ "name": name,
150
+ "type": "AAAA",
151
+ "zoneid": zone_id,
152
+ "ip_addresses": ip_addresses,
153
+ "value": value,
154
+ "id": _create_dns_record_id(zone_id, name, "AAAA"),
155
+ }
156
+ # This should never happen since we only call this for A and CNAME records,
157
+ # but we'll log it and return None.
158
+ logger.warning(f"Unsupported record type: {record_set['Type']}")
159
+ return None
315
160
 
316
- @timeit
317
- def transform_ns_record_set(record_set: Dict, zone_id: str) -> Optional[Dict]:
318
161
 
162
+ def transform_ns_record_set(
163
+ record_set: dict[str, Any], zone_id: str
164
+ ) -> dict[str, Any] | None:
319
165
  if "ResourceRecords" in record_set:
320
166
  # Sometimes the value records have a trailing period, sometimes they dont.
321
167
  servers = [
@@ -331,118 +177,292 @@ def transform_ns_record_set(record_set: Dict, zone_id: str) -> Optional[Dict]:
331
177
  "id": _create_dns_record_id(zone_id, record_set["Name"][:-1], "NS"),
332
178
  }
333
179
  else:
180
+ # This should never happen since we only call this for NS records
181
+ # but we'll log it and return None.
182
+ logger.warning(f"NS record set missing ResourceRecords: {record_set}")
334
183
  return None
335
184
 
336
185
 
337
- @timeit
338
- def transform_zone(zone: Dict) -> Dict:
339
- # TODO simplify this
340
- if "Comment" in zone["Config"]:
341
- comment = zone["Config"]["Comment"]
342
- else:
343
- comment = ""
186
+ def transform_zone(zone: dict[str, Any]) -> dict[str, Any]:
187
+ comment = zone["Config"].get("Comment")
188
+
189
+ # Remove trailing dot from name for schema compatibility
190
+ zone_name = zone["Name"]
191
+ if zone_name.endswith("."):
192
+ zone_name = zone_name[:-1]
344
193
 
345
194
  return {
346
195
  "zoneid": zone["Id"],
347
- "name": zone["Name"],
196
+ "name": zone_name,
348
197
  "privatezone": zone["Config"]["PrivateZone"],
349
198
  "comment": comment,
350
199
  "count": zone["ResourceRecordSetCount"],
351
200
  }
352
201
 
353
202
 
203
+ def transform_all_dns_data(
204
+ zones: list[tuple[dict[str, Any], list[dict[str, Any]]]],
205
+ ) -> DnsData:
206
+ """
207
+ Transform all DNS data into flat lists for loading.
208
+ Returns: (zones, a_records, aaaa_records, alias_records, cname_records, ns_records)
209
+ """
210
+ transformed_zones = []
211
+ all_a_records = []
212
+ all_aaaa_records = []
213
+ all_alias_records = []
214
+ all_cname_records = []
215
+ all_ns_records = []
216
+ all_name_servers = []
217
+
218
+ for zone, zone_record_sets in zones:
219
+ parsed_zone = transform_zone(zone)
220
+ transformed_zones.append(parsed_zone)
221
+
222
+ zone_id = zone["Id"]
223
+ zone_name = parsed_zone["name"]
224
+
225
+ for rs in zone_record_sets:
226
+ if rs["Type"] in {"A", "AAAA", "CNAME"}:
227
+ transformed_rs = transform_record_set(
228
+ rs,
229
+ zone_id,
230
+ rs["Name"][:-1],
231
+ )
232
+ if transformed_rs is None:
233
+ continue
234
+
235
+ if transformed_rs["type"] == "A":
236
+ all_a_records.append(transformed_rs)
237
+ # TODO consider creating IPs as a first-class node from here.
238
+ # Right now we just match on them from the A record.
239
+ elif transformed_rs["type"] == "AAAA":
240
+ all_aaaa_records.append(transformed_rs)
241
+ elif transformed_rs["type"] == "ALIAS":
242
+ all_alias_records.append(transformed_rs)
243
+ elif transformed_rs["type"] == "CNAME":
244
+ all_cname_records.append(transformed_rs)
245
+
246
+ elif rs["Type"] == "NS":
247
+ transformed_rs = transform_ns_record_set(rs, zone_id)
248
+ if transformed_rs is None:
249
+ continue
250
+
251
+ # Add zone name to NS records for loading
252
+ transformed_rs["zone_name"] = zone_name
253
+ all_ns_records.append(transformed_rs)
254
+ all_name_servers.extend(
255
+ [
256
+ {"id": server, "zoneid": zone_id}
257
+ for server in transformed_rs["servers"]
258
+ ]
259
+ )
260
+
261
+ return DnsData(
262
+ zones=transformed_zones,
263
+ a_records=all_a_records,
264
+ aaaa_records=all_aaaa_records,
265
+ alias_records=all_alias_records,
266
+ cname_records=all_cname_records,
267
+ ns_records=all_ns_records,
268
+ name_servers=all_name_servers,
269
+ )
270
+
271
+
272
+ @timeit
273
+ def _load_dns_details_flat(
274
+ neo4j_session: neo4j.Session,
275
+ zones: list[dict[str, Any]],
276
+ a_records: list[dict[str, Any]],
277
+ aaaa_records: list[dict[str, Any]],
278
+ alias_records: list[dict[str, Any]],
279
+ cname_records: list[dict[str, Any]],
280
+ ns_records: list[dict[str, Any]],
281
+ name_servers: list[dict[str, Any]],
282
+ current_aws_id: str,
283
+ update_tag: int,
284
+ ) -> None:
285
+ load_zones(neo4j_session, zones, current_aws_id, update_tag)
286
+ load_a_records(neo4j_session, a_records, update_tag, current_aws_id)
287
+ load_aaaa_records(neo4j_session, aaaa_records, update_tag, current_aws_id)
288
+ load_alias_records(neo4j_session, alias_records, update_tag, current_aws_id)
289
+ load_cname_records(neo4j_session, cname_records, update_tag, current_aws_id)
290
+ load_name_servers(neo4j_session, name_servers, update_tag, current_aws_id)
291
+ load_ns_records(neo4j_session, ns_records, update_tag, current_aws_id)
292
+
293
+
354
294
  @timeit
355
295
  def load_dns_details(
356
296
  neo4j_session: neo4j.Session,
357
- dns_details: List[Tuple[Dict, List[Dict]]],
297
+ dns_details: list[tuple[dict[str, Any], list[dict[str, Any]]]],
358
298
  current_aws_id: str,
359
299
  update_tag: int,
360
300
  ) -> None:
361
301
  """
362
- Create the paths
363
- (:AWSAccount)--(:AWSDNSZone)--(:AWSDNSRecord),
364
- (:AWSDNSZone)--(:NameServer),
365
- (:AWSDNSRecord{type:"NS"})-[:DNS_POINTS_TO]->(:NameServer),
366
- (:AWSDNSRecord)-[:DNS_POINTS_TO]->(:AWSDNSRecord).
302
+ Backward-compatible wrapper
367
303
  """
368
- for zone, zone_record_sets in dns_details:
369
- zone_a_records = []
370
- zone_alias_records = []
371
- zone_cname_records = []
372
- zone_ns_records = []
373
- parsed_zone = transform_zone(zone)
304
+ transformed_data = transform_all_dns_data(dns_details)
305
+ _load_dns_details_flat(
306
+ neo4j_session,
307
+ transformed_data.zones,
308
+ transformed_data.a_records,
309
+ transformed_data.aaaa_records,
310
+ transformed_data.alias_records,
311
+ transformed_data.cname_records,
312
+ transformed_data.ns_records,
313
+ transformed_data.name_servers,
314
+ current_aws_id,
315
+ update_tag,
316
+ )
374
317
 
375
- load_zone(neo4j_session, parsed_zone, current_aws_id, update_tag)
376
318
 
377
- for record_set in zone_record_sets:
378
- if record_set["Type"] == "A" or record_set["Type"] == "CNAME":
379
- record = transform_record_set(
380
- record_set,
381
- zone["Id"],
382
- record_set["Name"][:-1],
383
- )
319
+ @timeit
320
+ def load_a_records(
321
+ neo4j_session: neo4j.Session,
322
+ records: list[dict[str, Any]],
323
+ update_tag: int,
324
+ current_aws_id: str,
325
+ ) -> None:
326
+ load(
327
+ neo4j_session,
328
+ AWSDNSRecordSchema(),
329
+ records,
330
+ lastupdated=update_tag,
331
+ AWS_ID=current_aws_id,
332
+ )
384
333
 
385
- if record["type"] == "A":
386
- zone_a_records.append(record)
387
- elif record["type"] == "ALIAS":
388
- zone_alias_records.append(record)
389
- elif record["type"] == "CNAME":
390
- zone_cname_records.append(record)
391
-
392
- if record_set["Type"] == "NS":
393
- record = transform_ns_record_set(record_set, zone["Id"])
394
- zone_ns_records.append(record)
395
- if zone_a_records:
396
- load_a_records(neo4j_session, zone_a_records, update_tag)
397
-
398
- if zone_alias_records:
399
- load_alias_records(neo4j_session, zone_alias_records, update_tag)
400
-
401
- if zone_cname_records:
402
- load_cname_records(neo4j_session, zone_cname_records, update_tag)
403
- if zone_ns_records:
404
- load_ns_records(
405
- neo4j_session,
406
- zone_ns_records,
407
- parsed_zone["name"][:-1],
408
- update_tag,
409
- )
410
- link_aws_resources(neo4j_session, update_tag)
334
+
335
+ @timeit
336
+ def load_aaaa_records(
337
+ neo4j_session: neo4j.Session,
338
+ records: list[dict[str, Any]],
339
+ update_tag: int,
340
+ current_aws_id: str,
341
+ ) -> None:
342
+ load(
343
+ neo4j_session,
344
+ AWSDNSRecordSchema(),
345
+ records,
346
+ lastupdated=update_tag,
347
+ AWS_ID=current_aws_id,
348
+ )
411
349
 
412
350
 
413
351
  @timeit
414
- def get_zone_record_sets(
415
- client: botocore.client.BaseClient,
416
- zone_id: str,
417
- ) -> List[Dict]:
418
- resource_record_sets: List[Dict] = []
419
- paginator = client.get_paginator("list_resource_record_sets")
420
- pages = paginator.paginate(HostedZoneId=zone_id)
421
- for page in pages:
422
- resource_record_sets.extend(page["ResourceRecordSets"])
423
- return resource_record_sets
352
+ def load_alias_records(
353
+ neo4j_session: neo4j.Session,
354
+ records: list[dict[str, Any]],
355
+ update_tag: int,
356
+ current_aws_id: str,
357
+ ) -> None:
358
+ load(
359
+ neo4j_session,
360
+ AWSDNSRecordSchema(),
361
+ records,
362
+ lastupdated=update_tag,
363
+ AWS_ID=current_aws_id,
364
+ )
424
365
 
425
366
 
426
367
  @timeit
427
- def get_zones(client: botocore.client.BaseClient) -> List[Tuple[Dict, List[Dict]]]:
428
- paginator = client.get_paginator("list_hosted_zones")
429
- hosted_zones: List[Dict] = []
430
- for page in paginator.paginate():
431
- hosted_zones.extend(page["HostedZones"])
368
+ def load_cname_records(
369
+ neo4j_session: neo4j.Session,
370
+ records: list[dict[str, Any]],
371
+ update_tag: int,
372
+ current_aws_id: str,
373
+ ) -> None:
374
+ load(
375
+ neo4j_session,
376
+ AWSDNSRecordSchema(),
377
+ records,
378
+ lastupdated=update_tag,
379
+ AWS_ID=current_aws_id,
380
+ )
432
381
 
433
- results: List[Tuple[Dict, List[Dict]]] = []
434
- for hosted_zone in hosted_zones:
435
- record_sets = get_zone_record_sets(client, hosted_zone["Id"])
436
- results.append((hosted_zone, record_sets))
437
- return results
438
382
 
383
+ @timeit
384
+ def load_zones(
385
+ neo4j_session: neo4j.Session,
386
+ zones: list[dict[str, Any]],
387
+ current_aws_id: str,
388
+ update_tag: int,
389
+ ) -> None:
390
+ load(
391
+ neo4j_session,
392
+ AWSDNSZoneSchema(),
393
+ zones,
394
+ lastupdated=update_tag,
395
+ AWS_ID=current_aws_id,
396
+ )
439
397
 
440
- def _create_dns_record_id(zoneid: str, name: str, record_type: str) -> str:
441
- return "/".join([zoneid, name, record_type])
398
+
399
+ @timeit
400
+ def load_ns_records(
401
+ neo4j_session: neo4j.Session,
402
+ records: list[dict[str, Any]],
403
+ update_tag: int,
404
+ current_aws_id: str,
405
+ ) -> None:
406
+ load(
407
+ neo4j_session,
408
+ AWSDNSRecordSchema(),
409
+ records,
410
+ lastupdated=update_tag,
411
+ AWS_ID=current_aws_id,
412
+ )
442
413
 
443
414
 
444
- def _normalize_dns_address(address: str) -> str:
445
- return address.rstrip(".")
415
+ @timeit
416
+ def load_name_servers(
417
+ neo4j_session: neo4j.Session,
418
+ name_servers: list[dict[str, Any]],
419
+ update_tag: int,
420
+ current_aws_id: str,
421
+ ) -> None:
422
+ load(
423
+ neo4j_session,
424
+ NameServerSchema(),
425
+ name_servers,
426
+ lastupdated=update_tag,
427
+ AWS_ID=current_aws_id,
428
+ )
429
+
430
+
431
+ @timeit
432
+ def link_sub_zones(
433
+ neo4j_session: neo4j.Session, update_tag: int, current_aws_id: str
434
+ ) -> None:
435
+ """
436
+ Create SUBZONE relationships between DNS zones using matchlinks.
437
+
438
+ A DNS zone B is a sub zone of A if:
439
+ 1. DNS zone A has an NS record that points to a nameserver
440
+ 2. That nameserver is associated with DNS zone B
441
+ 3. The NS record's name matches the name of DNS zone B
442
+
443
+ We use matchlinks instead of a regular relationship because the hierarchy
444
+ isn't known ahead of time.
445
+ """
446
+ query = """
447
+ MATCH (:AWSAccount{id: $AWS_ID})-[:RESOURCE]->(z:AWSDNSZone)
448
+ <-[:MEMBER_OF_DNS_ZONE]-(record:DNSRecord{type:"NS"})
449
+ -[:DNS_POINTS_TO]->(ns:NameServer)<-[:NAMESERVER]-(z2:AWSDNSZone)
450
+ WHERE record.name = z2.name AND
451
+ z2.name ENDS WITH '.' + z.name AND
452
+ NOT z = z2
453
+ RETURN z.id as zone_id, z2.id as subzone_id
454
+ """
455
+ zone_to_subzone = neo4j_session.read_transaction(
456
+ read_list_of_dicts_tx, query, AWS_ID=current_aws_id
457
+ )
458
+ load_matchlinks(
459
+ neo4j_session,
460
+ AWSDNSZoneSubzoneMatchLink(),
461
+ zone_to_subzone,
462
+ lastupdated=update_tag,
463
+ _sub_resource_label="AWSAccount",
464
+ _sub_resource_id=current_aws_id,
465
+ )
446
466
 
447
467
 
448
468
  @timeit
@@ -451,25 +471,59 @@ def cleanup_route53(
451
471
  current_aws_id: str,
452
472
  update_tag: int,
453
473
  ) -> None:
454
- run_cleanup_job(
455
- "aws_dns_cleanup.json",
456
- neo4j_session,
457
- {"UPDATE_TAG": update_tag, "AWS_ID": current_aws_id},
458
- )
474
+ common_job_parameters = {
475
+ "UPDATE_TAG": update_tag,
476
+ "AWS_ID": current_aws_id,
477
+ }
478
+ GraphJob.from_node_schema(
479
+ AWSDNSRecordSchema(),
480
+ common_job_parameters,
481
+ ).run(neo4j_session)
482
+
483
+ GraphJob.from_node_schema(
484
+ NameServerSchema(),
485
+ common_job_parameters,
486
+ ).run(neo4j_session)
487
+
488
+ GraphJob.from_node_schema(
489
+ AWSDNSZoneSchema(),
490
+ common_job_parameters,
491
+ ).run(neo4j_session)
492
+
493
+ GraphJob.from_matchlink(
494
+ AWSDNSZoneSubzoneMatchLink(),
495
+ "AWSAccount",
496
+ current_aws_id,
497
+ update_tag,
498
+ ).run(neo4j_session)
459
499
 
460
500
 
461
501
  @timeit
462
502
  def sync(
463
503
  neo4j_session: neo4j.Session,
464
504
  boto3_session: boto3.session.Session,
465
- regions: List[str],
505
+ regions: list[str],
466
506
  current_aws_account_id: str,
467
507
  update_tag: int,
468
- common_job_parameters: Dict,
508
+ common_job_parameters: dict[str, Any],
469
509
  ) -> None:
470
510
  logger.info("Syncing Route53 for account '%s'.", current_aws_account_id)
471
511
  client = boto3_session.client("route53")
472
512
  zones = get_zones(client)
473
- load_dns_details(neo4j_session, zones, current_aws_account_id, update_tag)
474
- link_sub_zones(neo4j_session, update_tag)
513
+
514
+ transformed_data = transform_all_dns_data(zones)
515
+
516
+ _load_dns_details_flat(
517
+ neo4j_session,
518
+ transformed_data.zones,
519
+ transformed_data.a_records,
520
+ transformed_data.aaaa_records,
521
+ transformed_data.alias_records,
522
+ transformed_data.cname_records,
523
+ transformed_data.ns_records,
524
+ transformed_data.name_servers,
525
+ current_aws_account_id,
526
+ update_tag,
527
+ )
528
+ link_sub_zones(neo4j_session, update_tag, current_aws_account_id)
475
529
  cleanup_route53(neo4j_session, current_aws_account_id, update_tag)