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
@@ -6,12 +6,18 @@ from typing import List
6
6
  import boto3
7
7
  import neo4j
8
8
 
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.aws.rds.cluster import RDSClusterSchema
12
+ from cartography.models.aws.rds.event_subscription import RDSEventSubscriptionSchema
13
+ from cartography.models.aws.rds.instance import RDSInstanceSchema
14
+ from cartography.models.aws.rds.snapshot import RDSSnapshotSchema
15
+ from cartography.models.aws.rds.subnet_group import DBSubnetGroupSchema
9
16
  from cartography.stats import get_stats_client
10
17
  from cartography.util import aws_handle_regions
11
18
  from cartography.util import aws_paginate
12
19
  from cartography.util import dict_value_to_str
13
20
  from cartography.util import merge_module_sync_metadata
14
- from cartography.util import run_cleanup_job
15
21
  from cartography.util import timeit
16
22
 
17
23
  logger = logging.getLogger(__name__)
@@ -39,7 +45,7 @@ def get_rds_cluster_data(
39
45
  @timeit
40
46
  def load_rds_clusters(
41
47
  neo4j_session: neo4j.Session,
42
- data: Dict,
48
+ data: List[Dict],
43
49
  region: str,
44
50
  current_aws_account_id: str,
45
51
  aws_update_tag: int,
@@ -47,91 +53,13 @@ def load_rds_clusters(
47
53
  """
48
54
  Ingest the RDS clusters to neo4j and link them to necessary nodes.
49
55
  """
50
- ingest_rds_cluster = """
51
- UNWIND $Clusters as rds_cluster
52
- MERGE (cluster:RDSCluster{id: rds_cluster.DBClusterArn})
53
- ON CREATE SET cluster.firstseen = timestamp(),
54
- cluster.arn = rds_cluster.DBClusterArn
55
- SET cluster.allocated_storage = rds_cluster.AllocatedStorage,
56
- cluster.availability_zones = rds_cluster.AvailabilityZones,
57
- cluster.backup_retention_period = rds_cluster.BackupRetentionPeriod,
58
- cluster.character_set_name = rds_cluster.CharacterSetName,
59
- cluster.database_name = rds_cluster.DatabaseName,
60
- cluster.db_cluster_identifier = rds_cluster.DBClusterIdentifier,
61
- cluster.db_parameter_group = rds_cluster.DBClusterParameterGroup,
62
- cluster.status = rds_cluster.Status,
63
- cluster.earliest_restorable_time = rds_cluster.EarliestRestorableTime,
64
- cluster.endpoint = rds_cluster.Endpoint,
65
- cluster.reader_endpoint = rds_cluster.ReaderEndpoint,
66
- cluster.multi_az = rds_cluster.MultiAZ,
67
- cluster.engine = rds_cluster.Engine,
68
- cluster.engine_version = rds_cluster.EngineVersion,
69
- cluster.latest_restorable_time = rds_cluster.LatestRestorableTime,
70
- cluster.port = rds_cluster.Port,
71
- cluster.master_username = rds_cluster.MasterUsername,
72
- cluster.preferred_backup_window = rds_cluster.PreferredBackupWindow,
73
- cluster.preferred_maintenance_window = rds_cluster.PreferredMaintenanceWindow,
74
- cluster.hosted_zone_id = rds_cluster.HostedZoneId,
75
- cluster.storage_encrypted = rds_cluster.StorageEncrypted,
76
- cluster.kms_key_id = rds_cluster.KmsKeyId,
77
- cluster.db_cluster_resource_id = rds_cluster.DbClusterResourceId,
78
- cluster.clone_group_id = rds_cluster.CloneGroupId,
79
- cluster.cluster_create_time = rds_cluster.ClusterCreateTime,
80
- cluster.earliest_backtrack_time = rds_cluster.EarliestBacktrackTime,
81
- cluster.backtrack_window = rds_cluster.BacktrackWindow,
82
- cluster.backtrack_consumed_change_records = rds_cluster.BacktrackConsumedChangeRecords,
83
- cluster.capacity = rds_cluster.Capacity,
84
- cluster.engine_mode = rds_cluster.EngineMode,
85
- cluster.scaling_configuration_info_min_capacity = rds_cluster.ScalingConfigurationInfoMinCapacity,
86
- cluster.scaling_configuration_info_max_capacity = rds_cluster.ScalingConfigurationInfoMaxCapacity,
87
- cluster.scaling_configuration_info_auto_pause = rds_cluster.ScalingConfigurationInfoAutoPause,
88
- cluster.deletion_protection = rds_cluster.DeletionProtection,
89
- cluster.region = $Region,
90
- cluster.lastupdated = $aws_update_tag
91
- WITH cluster
92
- MATCH (aa:AWSAccount{id: $AWS_ACCOUNT_ID})
93
- MERGE (aa)-[r:RESOURCE]->(cluster)
94
- ON CREATE SET r.firstseen = timestamp()
95
- SET r.lastupdated = $aws_update_tag
96
- """
97
- for cluster in data:
98
- # TODO: track read replicas
99
- # TODO: track associated roles
100
- # TODO: track security groups
101
- # TODO: track subnet groups
102
-
103
- cluster["EarliestRestorableTime"] = dict_value_to_str(
104
- cluster,
105
- "EarliestRestorableTime",
106
- )
107
- cluster["LatestRestorableTime"] = dict_value_to_str(
108
- cluster,
109
- "LatestRestorableTime",
110
- )
111
- cluster["ClusterCreateTime"] = dict_value_to_str(cluster, "ClusterCreateTime")
112
- cluster["EarliestBacktrackTime"] = dict_value_to_str(
113
- cluster,
114
- "EarliestBacktrackTime",
115
- )
116
- cluster["ScalingConfigurationInfoMinCapacity"] = cluster.get(
117
- "ScalingConfigurationInfo",
118
- {},
119
- ).get("MinCapacity")
120
- cluster["ScalingConfigurationInfoMaxCapacity"] = cluster.get(
121
- "ScalingConfigurationInfo",
122
- {},
123
- ).get("MaxCapacity")
124
- cluster["ScalingConfigurationInfoAutoPause"] = cluster.get(
125
- "ScalingConfigurationInfo",
126
- {},
127
- ).get("AutoPause")
128
-
129
- neo4j_session.run(
130
- ingest_rds_cluster,
131
- Clusters=data,
56
+ load(
57
+ neo4j_session,
58
+ RDSClusterSchema(),
59
+ data,
60
+ lastupdated=aws_update_tag,
132
61
  Region=region,
133
- AWS_ACCOUNT_ID=current_aws_account_id,
134
- aws_update_tag=aws_update_tag,
62
+ AWS_ID=current_aws_account_id,
135
63
  )
136
64
 
137
65
 
@@ -156,101 +84,22 @@ def get_rds_instance_data(
156
84
  @timeit
157
85
  def load_rds_instances(
158
86
  neo4j_session: neo4j.Session,
159
- data: Dict,
87
+ data: List[Dict],
160
88
  region: str,
161
89
  current_aws_account_id: str,
162
90
  aws_update_tag: int,
163
91
  ) -> None:
164
92
  """
165
- Ingest the RDS instances to neo4j and link them to necessary nodes.
166
- """
167
- ingest_rds_instance = """
168
- UNWIND $Instances as rds_instance
169
- MERGE (rds:RDSInstance{id: rds_instance.DBInstanceArn})
170
- ON CREATE SET rds.firstseen = timestamp(),
171
- rds.arn = rds_instance.DBInstanceArn
172
- SET rds.db_instance_identifier = rds_instance.DBInstanceIdentifier,
173
- rds.db_instance_class = rds_instance.DBInstanceClass,
174
- rds.engine = rds_instance.Engine,
175
- rds.master_username = rds_instance.MasterUsername,
176
- rds.db_name = rds_instance.DBName,
177
- rds.instance_create_time = rds_instance.InstanceCreateTime,
178
- rds.availability_zone = rds_instance.AvailabilityZone,
179
- rds.multi_az = rds_instance.MultiAZ,
180
- rds.engine_version = rds_instance.EngineVersion,
181
- rds.publicly_accessible = rds_instance.PubliclyAccessible,
182
- rds.db_cluster_identifier = rds_instance.DBClusterIdentifier,
183
- rds.storage_encrypted = rds_instance.StorageEncrypted,
184
- rds.kms_key_id = rds_instance.KmsKeyId,
185
- rds.dbi_resource_id = rds_instance.DbiResourceId,
186
- rds.ca_certificate_identifier = rds_instance.CACertificateIdentifier,
187
- rds.enhanced_monitoring_resource_arn = rds_instance.EnhancedMonitoringResourceArn,
188
- rds.monitoring_role_arn = rds_instance.MonitoringRoleArn,
189
- rds.performance_insights_enabled = rds_instance.PerformanceInsightsEnabled,
190
- rds.performance_insights_kms_key_id = rds_instance.PerformanceInsightsKMSKeyId,
191
- rds.region = rds_instance.Region,
192
- rds.deletion_protection = rds_instance.DeletionProtection,
193
- rds.preferred_backup_window = rds_instance.PreferredBackupWindow,
194
- rds.latest_restorable_time = rds_instance.LatestRestorableTime,
195
- rds.preferred_maintenance_window = rds_instance.PreferredMaintenanceWindow,
196
- rds.backup_retention_period = rds_instance.BackupRetentionPeriod,
197
- rds.endpoint_address = rds_instance.EndpointAddress,
198
- rds.endpoint_hostedzoneid = rds_instance.EndpointHostedZoneId,
199
- rds.endpoint_port = rds_instance.EndpointPort,
200
- rds.iam_database_authentication_enabled = rds_instance.IAMDatabaseAuthenticationEnabled,
201
- rds.auto_minor_version_upgrade = rds_instance.AutoMinorVersionUpgrade,
202
- rds.lastupdated = $aws_update_tag
203
- WITH rds
204
- MATCH (aa:AWSAccount{id: $AWS_ACCOUNT_ID})
205
- MERGE (aa)-[r:RESOURCE]->(rds)
206
- ON CREATE SET r.firstseen = timestamp()
207
- SET r.lastupdated = $aws_update_tag
208
- """
209
- read_replicas = []
210
- clusters = []
211
- secgroups = []
212
- subnets = []
213
-
214
- for rds in data:
215
- ep = _validate_rds_endpoint(rds)
216
-
217
- # Keep track of instances that are read replicas so we can attach them to their source instances later
218
- if rds.get("ReadReplicaSourceDBInstanceIdentifier"):
219
- read_replicas.append(rds)
220
-
221
- # Keep track of instances that are cluster members so we can attach them to their source clusters later
222
- if rds.get("DBClusterIdentifier"):
223
- clusters.append(rds)
224
-
225
- if rds.get("VpcSecurityGroups"):
226
- secgroups.append(rds)
227
-
228
- if rds.get("DBSubnetGroup"):
229
- subnets.append(rds)
230
-
231
- rds["InstanceCreateTime"] = dict_value_to_str(rds, "InstanceCreateTime")
232
- rds["LatestRestorableTime"] = dict_value_to_str(rds, "LatestRestorableTime")
233
- rds["EndpointAddress"] = ep.get("Address")
234
- rds["EndpointHostedZoneId"] = ep.get("HostedZoneId")
235
- rds["EndpointPort"] = ep.get("Port")
236
-
237
- neo4j_session.run(
238
- ingest_rds_instance,
239
- Instances=data,
240
- Region=region,
241
- AWS_ACCOUNT_ID=current_aws_account_id,
242
- aws_update_tag=aws_update_tag,
243
- )
244
- _attach_ec2_security_groups(neo4j_session, secgroups, aws_update_tag)
245
- _attach_ec2_subnet_groups(
93
+ Ingest the RDS instances to Neo4j and link them to necessary nodes.
94
+ """
95
+ load(
246
96
  neo4j_session,
247
- subnets,
248
- region,
249
- current_aws_account_id,
250
- aws_update_tag,
97
+ RDSInstanceSchema(),
98
+ data,
99
+ lastupdated=aws_update_tag,
100
+ Region=region,
101
+ AWS_ID=current_aws_account_id,
251
102
  )
252
- _attach_read_replicas(neo4j_session, read_replicas, aws_update_tag)
253
- _attach_clusters(neo4j_session, clusters, aws_update_tag)
254
103
 
255
104
 
256
105
  @timeit
@@ -263,13 +112,14 @@ def get_rds_snapshot_data(
263
112
  Create an RDS boto3 client and grab all the DBSnapshots.
264
113
  """
265
114
  client = boto3_session.client("rds", region_name=region)
266
- return aws_paginate(client, "describe_db_snapshots", "DBSnapshots")
115
+ snapshots = list(aws_paginate(client, "describe_db_snapshots", "DBSnapshots"))
116
+ return snapshots
267
117
 
268
118
 
269
119
  @timeit
270
120
  def load_rds_snapshots(
271
121
  neo4j_session: neo4j.Session,
272
- data: Dict,
122
+ data: List[Dict],
273
123
  region: str,
274
124
  current_aws_account_id: str,
275
125
  aws_update_tag: int,
@@ -277,266 +127,45 @@ def load_rds_snapshots(
277
127
  """
278
128
  Ingest the RDS snapshots to neo4j and link them to necessary nodes.
279
129
  """
280
- ingest_rds_snapshot = """
281
- UNWIND $Snapshots as rds_snapshot
282
- MERGE (snapshot:RDSSnapshot{id: rds_snapshot.DBSnapshotArn})
283
- ON CREATE SET snapshot.firstseen = timestamp(),
284
- snapshot.arn = rds_snapshot.DBSnapshotArn
285
- SET snapshot.db_snapshot_identifier = rds_snapshot.DBSnapshotIdentifier,
286
- snapshot.db_instance_identifier = rds_snapshot.DBInstanceIdentifier,
287
- snapshot.snapshot_create_time = rds_snapshot.SnapshotCreateTime,
288
- snapshot.engine = rds_snapshot.Engine,
289
- snapshot.allocated_storage = rds_snapshot.AllocatedStorage,
290
- snapshot.status = rds_snapshot.Status,
291
- snapshot.port = rds_snapshot.Port,
292
- snapshot.availability_zone = rds_snapshot.AvailabilityZone,
293
- snapshot.vpc_id = rds_snapshot.VpcId,
294
- snapshot.instance_create_time = rds_snapshot.InstanceCreateTime,
295
- snapshot.master_username = rds_snapshot.MasterUsername,
296
- snapshot.engine_version = rds_snapshot.EngineVersion,
297
- snapshot.license_model = rds_snapshot.LicenseModel,
298
- snapshot.snapshot_type = rds_snapshot.SnapshotType,
299
- snapshot.iops = rds_snapshot.Iops,
300
- snapshot.option_group_name = rds_snapshot.OptionGroupName,
301
- snapshot.percent_progress = rds_snapshot.PercentProgress,
302
- snapshot.source_region = rds_snapshot.SourceRegion,
303
- snapshot.source_db_snapshot_identifier = rds_snapshot.SourceDBSnapshotIdentifier,
304
- snapshot.storage_type = rds_snapshot.StorageType,
305
- snapshot.tde_credential_arn = rds_snapshot.TdeCredentialArn,
306
- snapshot.encrypted = rds_snapshot.Encrypted,
307
- snapshot.kms_key_id = rds_snapshot.KmsKeyId,
308
- snapshot.timezone = rds_snapshot.Timezone,
309
- snapshot.iam_database_authentication_enabled = rds_snapshot.IAMDatabaseAuthenticationEnabled,
310
- snapshot.processor_features = rds_snapshot.ProcessorFeatures,
311
- snapshot.dbi_resource_id = rds_snapshot.DbiResourceId,
312
- snapshot.original_snapshot_create_time = rds_snapshot.OriginalSnapshotCreateTime,
313
- snapshot.snapshot_database_time = rds_snapshot.SnapshotDatabaseTime,
314
- snapshot.snapshot_target = rds_snapshot.SnapshotTarget,
315
- snapshot.storage_throughput = rds_snapshot.StorageThroughput,
316
- snapshot.region = $Region,
317
- snapshot.lastupdated = $aws_update_tag
318
- WITH snapshot
319
- MATCH (aa:AWSAccount{id: $AWS_ACCOUNT_ID})
320
- MERGE (aa)-[r:RESOURCE]->(snapshot)
321
- ON CREATE SET r.firstseen = timestamp()
322
- SET r.lastupdated = $aws_update_tag
323
- """
324
-
325
- snapshots = transform_rds_snapshots(data)
326
-
327
- neo4j_session.run(
328
- ingest_rds_snapshot,
329
- Snapshots=snapshots,
130
+ load(
131
+ neo4j_session,
132
+ RDSSnapshotSchema(),
133
+ data,
134
+ lastupdated=aws_update_tag,
330
135
  Region=region,
331
- AWS_ACCOUNT_ID=current_aws_account_id,
332
- aws_update_tag=aws_update_tag,
333
- )
334
- _attach_snapshots(neo4j_session, snapshots, aws_update_tag)
335
-
336
-
337
- @timeit
338
- def _attach_snapshots(
339
- neo4j_session: neo4j.Session,
340
- snapshots: List[Dict],
341
- aws_update_tag: int,
342
- ) -> None:
343
- """
344
- Attach snapshots to their source instance
345
- """
346
- attach_member_to_source = """
347
- UNWIND $Snapshots as snapshot
348
- MATCH (rdsInstance:RDSInstance {db_instance_identifier: snapshot.DBInstanceIdentifier}),
349
- (rdsSnapshot:RDSSnapshot {arn: snapshot.DBSnapshotArn})
350
- MERGE (rdsInstance)-[r:IS_SNAPSHOT_SOURCE]->(rdsSnapshot)
351
- ON CREATE SET r.firstseen = timestamp()
352
- SET r.lastupdated = $aws_update_tag
353
- """
354
- neo4j_session.run(
355
- attach_member_to_source,
356
- Snapshots=snapshots,
357
- aws_update_tag=aws_update_tag,
136
+ AWS_ID=current_aws_account_id,
358
137
  )
359
138
 
360
139
 
361
140
  @timeit
362
- def _attach_ec2_subnet_groups(
363
- neo4j_session: neo4j.Session,
364
- instances: List[Dict],
141
+ @aws_handle_regions
142
+ def get_rds_event_subscription_data(
143
+ boto3_session: boto3.session.Session,
365
144
  region: str,
366
- current_aws_account_id: str,
367
- aws_update_tag: int,
368
- ) -> None:
369
- """
370
- Attach RDS instances to their EC2 subnet groups
371
- """
372
- attach_rds_to_subnet_group = """
373
- UNWIND $SubnetGroups as rds_sng
374
- MERGE (sng:DBSubnetGroup{id: rds_sng.arn})
375
- ON CREATE SET sng.firstseen = timestamp()
376
- SET sng.name = rds_sng.DBSubnetGroupName,
377
- sng.vpc_id = rds_sng.VpcId,
378
- sng.description = rds_sng.DBSubnetGroupDescription,
379
- sng.status = rds_sng.DBSubnetGroupStatus,
380
- sng.lastupdated = $aws_update_tag
381
- WITH sng, rds_sng.instance_arn AS instance_arn
382
- MATCH(rds:RDSInstance{id: instance_arn})
383
- MERGE(rds)-[r:MEMBER_OF_DB_SUBNET_GROUP]->(sng)
384
- ON CREATE SET r.firstseen = timestamp()
385
- SET r.lastupdated = $aws_update_tag
386
- """
387
- db_sngs = []
388
- for instance in instances:
389
- db_sng = instance["DBSubnetGroup"]
390
- db_sng["arn"] = _get_db_subnet_group_arn(
391
- region,
392
- current_aws_account_id,
393
- db_sng["DBSubnetGroupName"],
394
- )
395
- db_sng["instance_arn"] = instance["DBInstanceArn"]
396
- db_sngs.append(db_sng)
397
- neo4j_session.run(
398
- attach_rds_to_subnet_group,
399
- SubnetGroups=db_sngs,
400
- aws_update_tag=aws_update_tag,
401
- )
402
- _attach_ec2_subnets_to_subnetgroup(
403
- neo4j_session,
404
- db_sngs,
405
- region,
406
- current_aws_account_id,
407
- aws_update_tag,
408
- )
145
+ ) -> List[Dict[str, Any]]:
146
+ client = boto3_session.client("rds", region_name=region)
147
+ paginator = client.get_paginator("describe_event_subscriptions")
148
+ subscriptions = []
149
+ for page in paginator.paginate():
150
+ subscriptions.extend(page["EventSubscriptionsList"])
151
+ return subscriptions
409
152
 
410
153
 
411
154
  @timeit
412
- def _attach_ec2_subnets_to_subnetgroup(
155
+ def load_rds_event_subscriptions(
413
156
  neo4j_session: neo4j.Session,
414
- db_subnet_groups: List[Dict],
157
+ data: List[Dict],
415
158
  region: str,
416
159
  current_aws_account_id: str,
417
160
  aws_update_tag: int,
418
161
  ) -> None:
419
- """
420
- Attach EC2Subnets to their DB Subnet Group.
421
-
422
- From https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html:
423
- `Each DB subnet group should have subnets in at least two Availability Zones in a given region. When creating a DB
424
- instance in a VPC, you must select a DB subnet group. Amazon RDS uses that DB subnet group and your preferred
425
- Availability Zone to select a subnet and an IP address within that subnet to associate with your DB instance.`
426
- """
427
- attach_subnets_to_sng = """
428
- UNWIND $Subnets as rds_sn
429
- MATCH(sng:DBSubnetGroup{id: rds_sn.sng_arn})
430
- MERGE(subnet:EC2Subnet{subnetid: rds_sn.sn_id})
431
- ON CREATE SET subnet.firstseen = timestamp()
432
- MERGE(sng)-[r:RESOURCE]->(subnet)
433
- ON CREATE SET r.firstseen = timestamp()
434
- SET r.lastupdated = $aws_update_tag,
435
- subnet.availability_zone = rds_sn.az,
436
- subnet.lastupdated = $aws_update_tag
437
- """
438
- subnets = []
439
- for subnet_group in db_subnet_groups:
440
- for subnet in subnet_group.get("Subnets", []):
441
- sn_id = subnet.get("SubnetIdentifier")
442
- sng_arn = _get_db_subnet_group_arn(
443
- region,
444
- current_aws_account_id,
445
- subnet_group["DBSubnetGroupName"],
446
- )
447
- az = subnet.get("SubnetAvailabilityZone", {}).get("Name")
448
- subnets.append(
449
- {
450
- "sn_id": sn_id,
451
- "sng_arn": sng_arn,
452
- "az": az,
453
- },
454
- )
455
- neo4j_session.run(
456
- attach_subnets_to_sng,
457
- Subnets=subnets,
458
- aws_update_tag=aws_update_tag,
459
- )
460
-
461
-
462
- @timeit
463
- def _attach_ec2_security_groups(
464
- neo4j_session: neo4j.Session,
465
- instances: List[Dict],
466
- aws_update_tag: int,
467
- ) -> None:
468
- """
469
- Attach an RDS instance to its EC2SecurityGroups
470
- """
471
- attach_rds_to_group = """
472
- UNWIND $Groups as rds_sg
473
- MATCH (rds:RDSInstance{id: rds_sg.arn})
474
- MERGE (sg:EC2SecurityGroup{id: rds_sg.group_id})
475
- MERGE (rds)-[m:MEMBER_OF_EC2_SECURITY_GROUP]->(sg)
476
- ON CREATE SET m.firstseen = timestamp()
477
- SET m.lastupdated = $aws_update_tag
478
- """
479
- groups = []
480
- for instance in instances:
481
- for group in instance["VpcSecurityGroups"]:
482
- groups.append(
483
- {
484
- "arn": instance["DBInstanceArn"],
485
- "group_id": group["VpcSecurityGroupId"],
486
- },
487
- )
488
- neo4j_session.run(
489
- attach_rds_to_group,
490
- Groups=groups,
491
- aws_update_tag=aws_update_tag,
492
- )
493
-
494
-
495
- @timeit
496
- def _attach_read_replicas(
497
- neo4j_session: neo4j.Session,
498
- read_replicas: List[Dict],
499
- aws_update_tag: int,
500
- ) -> None:
501
- """
502
- Attach read replicas to their source instances
503
- """
504
- attach_replica_to_source = """
505
- UNWIND $Replicas as rds_replica
506
- MATCH (replica:RDSInstance{id: rds_replica.DBInstanceArn}),
507
- (source:RDSInstance{db_instance_identifier: rds_replica.ReadReplicaSourceDBInstanceIdentifier})
508
- MERGE (replica)-[r:IS_READ_REPLICA_OF]->(source)
509
- ON CREATE SET r.firstseen = timestamp()
510
- SET r.lastupdated = $aws_update_tag
511
- """
512
- neo4j_session.run(
513
- attach_replica_to_source,
514
- Replicas=read_replicas,
515
- aws_update_tag=aws_update_tag,
516
- )
517
-
518
-
519
- @timeit
520
- def _attach_clusters(
521
- neo4j_session: neo4j.Session,
522
- cluster_members: List[Dict],
523
- aws_update_tag: int,
524
- ) -> None:
525
- """
526
- Attach cluster members to their source clusters
527
- """
528
- attach_member_to_source = """
529
- UNWIND $Members as rds_cluster_member
530
- MATCH (member:RDSInstance{id: rds_cluster_member.DBInstanceArn}),
531
- (source:RDSCluster{db_cluster_identifier: rds_cluster_member.DBClusterIdentifier})
532
- MERGE (member)-[r:IS_CLUSTER_MEMBER_OF]->(source)
533
- ON CREATE SET r.firstseen = timestamp()
534
- SET r.lastupdated = $aws_update_tag
535
- """
536
- neo4j_session.run(
537
- attach_member_to_source,
538
- Members=cluster_members,
539
- aws_update_tag=aws_update_tag,
162
+ load(
163
+ neo4j_session,
164
+ RDSEventSubscriptionSchema(),
165
+ data,
166
+ lastupdated=aws_update_tag,
167
+ Region=region,
168
+ AWS_ID=current_aws_account_id,
540
169
  )
541
170
 
542
171
 
@@ -570,8 +199,48 @@ def _get_db_subnet_group_arn(
570
199
  )
571
200
 
572
201
 
573
- @timeit
574
- def transform_rds_snapshots(data: Dict) -> List[Dict]:
202
+ def transform_rds_clusters(data: List[Dict]) -> List[Dict]:
203
+ """
204
+ Transform RDS cluster data for Neo4j ingestion
205
+ """
206
+ clusters = []
207
+
208
+ for cluster in data:
209
+ # Copy the cluster data
210
+ transformed_cluster = cluster.copy()
211
+
212
+ # Convert datetime fields
213
+ transformed_cluster["EarliestRestorableTime"] = dict_value_to_str(
214
+ cluster, "EarliestRestorableTime"
215
+ )
216
+ transformed_cluster["LatestRestorableTime"] = dict_value_to_str(
217
+ cluster, "LatestRestorableTime"
218
+ )
219
+ transformed_cluster["ClusterCreateTime"] = dict_value_to_str(
220
+ cluster, "ClusterCreateTime"
221
+ )
222
+ transformed_cluster["EarliestBacktrackTime"] = dict_value_to_str(
223
+ cluster, "EarliestBacktrackTime"
224
+ )
225
+
226
+ # Extract scaling configuration info
227
+ scaling_config = cluster.get("ScalingConfigurationInfo", {})
228
+ transformed_cluster["ScalingConfigurationInfoMinCapacity"] = scaling_config.get(
229
+ "MinCapacity"
230
+ )
231
+ transformed_cluster["ScalingConfigurationInfoMaxCapacity"] = scaling_config.get(
232
+ "MaxCapacity"
233
+ )
234
+ transformed_cluster["ScalingConfigurationInfoAutoPause"] = scaling_config.get(
235
+ "AutoPause"
236
+ )
237
+
238
+ clusters.append(transformed_cluster)
239
+
240
+ return clusters
241
+
242
+
243
+ def transform_rds_snapshots(data: List[Dict]) -> List[Dict]:
575
244
  snapshots = []
576
245
 
577
246
  for snapshot in data:
@@ -598,18 +267,173 @@ def transform_rds_snapshots(data: Dict) -> List[Dict]:
598
267
  return snapshots
599
268
 
600
269
 
270
+ def transform_rds_instances(
271
+ data: List[Dict], region: str, current_aws_account_id: str
272
+ ) -> List[Dict]:
273
+ """
274
+ Transform RDS instance data for Neo4j ingestion
275
+ """
276
+ instances = []
277
+
278
+ for instance in data:
279
+ # Copy the instance data
280
+ transformed_instance = instance.copy()
281
+
282
+ # Extract security group IDs for the relationship
283
+ security_group_ids = []
284
+ if instance.get("VpcSecurityGroups"):
285
+ for group in instance["VpcSecurityGroups"]:
286
+ security_group_ids.append(group["VpcSecurityGroupId"])
287
+
288
+ transformed_instance["security_group_ids"] = security_group_ids
289
+
290
+ # Handle read replica source identifier for the relationship
291
+ if instance.get("ReadReplicaSourceDBInstanceIdentifier"):
292
+ transformed_instance["read_replica_source_identifier"] = instance[
293
+ "ReadReplicaSourceDBInstanceIdentifier"
294
+ ]
295
+
296
+ # Handle cluster identifier for the relationship
297
+ if instance.get("DBClusterIdentifier"):
298
+ transformed_instance["db_cluster_identifier"] = instance[
299
+ "DBClusterIdentifier"
300
+ ]
301
+
302
+ # Handle subnet group data for the relationship
303
+ if instance.get("DBSubnetGroup"):
304
+ db_subnet_group = instance["DBSubnetGroup"]
305
+ transformed_instance["db_subnet_group_arn"] = _get_db_subnet_group_arn(
306
+ region, current_aws_account_id, db_subnet_group["DBSubnetGroupName"]
307
+ )
308
+
309
+ # Handle endpoint data
310
+ ep = _validate_rds_endpoint(instance)
311
+ transformed_instance["EndpointAddress"] = ep.get("Address")
312
+ transformed_instance["EndpointHostedZoneId"] = ep.get("HostedZoneId")
313
+ transformed_instance["EndpointPort"] = ep.get("Port")
314
+
315
+ # Convert datetime fields
316
+ transformed_instance["InstanceCreateTime"] = dict_value_to_str(
317
+ instance, "InstanceCreateTime"
318
+ )
319
+ transformed_instance["LatestRestorableTime"] = dict_value_to_str(
320
+ instance, "LatestRestorableTime"
321
+ )
322
+
323
+ instances.append(transformed_instance)
324
+
325
+ return instances
326
+
327
+
328
+ def transform_rds_event_subscriptions(data: List[Dict]) -> List[Dict]:
329
+ subscriptions = []
330
+ for subscription in data:
331
+ transformed = {
332
+ "CustSubscriptionId": subscription.get("CustSubscriptionId"),
333
+ "EventSubscriptionArn": subscription.get("EventSubscriptionArn"),
334
+ "CustomerAwsId": subscription.get("CustomerAwsId"),
335
+ "SnsTopicArn": subscription.get("SnsTopicArn"),
336
+ "SourceType": subscription.get("SourceType"),
337
+ "Status": subscription.get("Status"),
338
+ "Enabled": subscription.get("Enabled"),
339
+ "SubscriptionCreationTime": dict_value_to_str(
340
+ subscription, "SubscriptionCreationTime"
341
+ ),
342
+ "event_categories": subscription.get("EventCategoriesList") or None,
343
+ "source_ids": subscription.get("SourceIdsList") or None,
344
+ "lastupdated": None, # This will be set by the loader
345
+ }
346
+ subscriptions.append(transformed)
347
+ return subscriptions
348
+
349
+
350
+ def transform_rds_subnet_groups(
351
+ data: List[Dict], region: str, current_aws_account_id: str
352
+ ) -> List[Dict]:
353
+ """
354
+ Transform RDS subnet group data for Neo4j ingestion
355
+ """
356
+ subnet_groups_dict = {}
357
+
358
+ for instance in data:
359
+ if instance.get("DBSubnetGroup"):
360
+ db_subnet_group = instance["DBSubnetGroup"]
361
+ db_subnet_group_arn = _get_db_subnet_group_arn(
362
+ region, current_aws_account_id, db_subnet_group["DBSubnetGroupName"]
363
+ )
364
+
365
+ # If this subnet group doesn't exist yet, create it
366
+ if db_subnet_group_arn not in subnet_groups_dict:
367
+ subnet_groups_dict[db_subnet_group_arn] = {
368
+ "id": db_subnet_group_arn,
369
+ "name": db_subnet_group["DBSubnetGroupName"],
370
+ "vpc_id": db_subnet_group["VpcId"],
371
+ "description": db_subnet_group["DBSubnetGroupDescription"],
372
+ "status": db_subnet_group["SubnetGroupStatus"],
373
+ "db_instance_identifier": [],
374
+ "subnet_ids": [],
375
+ }
376
+
377
+ # Add this RDS instance to the subnet group's list
378
+ if instance.get("DBInstanceIdentifier"):
379
+ subnet_groups_dict[db_subnet_group_arn][
380
+ "db_instance_identifier"
381
+ ].append(instance["DBInstanceIdentifier"])
382
+
383
+ # Add subnet IDs from the DB subnet group
384
+ for subnet in db_subnet_group.get("Subnets", []):
385
+ subnet_id = subnet.get("SubnetIdentifier")
386
+ if (
387
+ subnet_id
388
+ and subnet_id
389
+ not in subnet_groups_dict[db_subnet_group_arn]["subnet_ids"]
390
+ ):
391
+ subnet_groups_dict[db_subnet_group_arn]["subnet_ids"].append(
392
+ subnet_id
393
+ )
394
+
395
+ return list(subnet_groups_dict.values())
396
+
397
+
398
+ @timeit
399
+ def load_rds_subnet_groups(
400
+ neo4j_session: neo4j.Session,
401
+ data: List[Dict],
402
+ region: str,
403
+ current_aws_account_id: str,
404
+ aws_update_tag: int,
405
+ ) -> None:
406
+ """
407
+ Ingest the RDS subnet groups to Neo4j and link them to necessary nodes.
408
+ """
409
+ load(
410
+ neo4j_session,
411
+ DBSubnetGroupSchema(),
412
+ data,
413
+ lastupdated=aws_update_tag,
414
+ Region=region,
415
+ AWS_ID=current_aws_account_id,
416
+ )
417
+
418
+
601
419
  @timeit
602
420
  def cleanup_rds_instances_and_db_subnet_groups(
603
421
  neo4j_session: neo4j.Session,
604
422
  common_job_parameters: Dict,
605
423
  ) -> None:
606
424
  """
607
- Remove RDS graph nodes and DBSubnetGroups that were created from other ingestion runs
425
+ Remove RDS instances and DB subnet groups that weren't updated in this sync run
608
426
  """
609
- run_cleanup_job(
610
- "aws_import_rds_instances_cleanup.json",
611
- neo4j_session,
612
- common_job_parameters,
427
+ logger.debug("Running RDS instances and DB subnet groups cleanup job")
428
+
429
+ # Clean up RDS instances
430
+ GraphJob.from_node_schema(RDSInstanceSchema(), common_job_parameters).run(
431
+ neo4j_session
432
+ )
433
+
434
+ # Clean up DB subnet groups
435
+ GraphJob.from_node_schema(DBSubnetGroupSchema(), common_job_parameters).run(
436
+ neo4j_session
613
437
  )
614
438
 
615
439
 
@@ -619,12 +443,12 @@ def cleanup_rds_clusters(
619
443
  common_job_parameters: Dict,
620
444
  ) -> None:
621
445
  """
622
- Remove RDS cluster graph nodes
446
+ Remove RDS clusters that weren't updated in this sync run
623
447
  """
624
- run_cleanup_job(
625
- "aws_import_rds_clusters_cleanup.json",
626
- neo4j_session,
627
- common_job_parameters,
448
+ logger.debug("Running RDS clusters cleanup job")
449
+
450
+ GraphJob.from_node_schema(RDSClusterSchema(), common_job_parameters).run(
451
+ neo4j_session
628
452
  )
629
453
 
630
454
 
@@ -634,12 +458,26 @@ def cleanup_rds_snapshots(
634
458
  common_job_parameters: Dict,
635
459
  ) -> None:
636
460
  """
637
- Remove RDS snapshots graph nodes
461
+ Remove RDS snapshots that weren't updated in this sync run
638
462
  """
639
- run_cleanup_job(
640
- "aws_import_rds_snapshots_cleanup.json",
641
- neo4j_session,
642
- common_job_parameters,
463
+ logger.debug("Running RDS snapshots cleanup job")
464
+
465
+ GraphJob.from_node_schema(RDSSnapshotSchema(), common_job_parameters).run(
466
+ neo4j_session
467
+ )
468
+
469
+
470
+ @timeit
471
+ def cleanup_rds_event_subscriptions(
472
+ neo4j_session: neo4j.Session,
473
+ common_job_parameters: Dict,
474
+ ) -> None:
475
+ """
476
+ Remove RDS event subscriptions that weren't updated in this sync run
477
+ """
478
+ logger.debug("Running RDS event subscriptions cleanup job")
479
+ GraphJob.from_node_schema(RDSEventSubscriptionSchema(), common_job_parameters).run(
480
+ neo4j_session
643
481
  )
644
482
 
645
483
 
@@ -653,16 +491,19 @@ def sync_rds_clusters(
653
491
  common_job_parameters: Dict,
654
492
  ) -> None:
655
493
  """
656
- Grab RDS instance data from AWS, ingest to neo4j, and run the cleanup job.
494
+ Grab RDS cluster data from AWS, ingest to neo4j, and run the cleanup job.
657
495
  """
658
496
  for region in regions:
659
497
  logger.info(
660
- "Syncing RDS for region '%s' in account '%s'.",
498
+ "Syncing RDS clusters for region '%s' in account '%s'.",
661
499
  region,
662
500
  current_aws_account_id,
663
501
  )
664
502
  data = get_rds_cluster_data(boto3_session, region)
665
- load_rds_clusters(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
503
+ transformed_data = transform_rds_clusters(data)
504
+ load_rds_clusters(
505
+ neo4j_session, transformed_data, region, current_aws_account_id, update_tag
506
+ )
666
507
  cleanup_rds_clusters(neo4j_session, common_job_parameters)
667
508
 
668
509
 
@@ -680,12 +521,23 @@ def sync_rds_instances(
680
521
  """
681
522
  for region in regions:
682
523
  logger.info(
683
- "Syncing RDS for region '%s' in account '%s'.",
524
+ "Syncing RDS instances for region '%s' in account '%s'.",
684
525
  region,
685
526
  current_aws_account_id,
686
527
  )
687
528
  data = get_rds_instance_data(boto3_session, region)
688
- load_rds_instances(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
529
+ transformed_data = transform_rds_instances(data, region, current_aws_account_id)
530
+ load_rds_instances(
531
+ neo4j_session, transformed_data, region, current_aws_account_id, update_tag
532
+ )
533
+
534
+ # Load subnet groups from RDS instances
535
+ subnet_group_data = transform_rds_subnet_groups(
536
+ data, region, current_aws_account_id
537
+ )
538
+ load_rds_subnet_groups(
539
+ neo4j_session, subnet_group_data, region, current_aws_account_id, update_tag
540
+ )
689
541
  cleanup_rds_instances_and_db_subnet_groups(neo4j_session, common_job_parameters)
690
542
 
691
543
 
@@ -703,15 +555,44 @@ def sync_rds_snapshots(
703
555
  """
704
556
  for region in regions:
705
557
  logger.info(
706
- "Syncing RDS for region '%s' in account '%s'.",
558
+ "Syncing RDS snapshots for region '%s' in account '%s'.",
707
559
  region,
708
560
  current_aws_account_id,
709
561
  )
710
562
  data = get_rds_snapshot_data(boto3_session, region)
711
- load_rds_snapshots(neo4j_session, data, region, current_aws_account_id, update_tag) # type: ignore
563
+ transformed_data = transform_rds_snapshots(data)
564
+ load_rds_snapshots(
565
+ neo4j_session, transformed_data, region, current_aws_account_id, update_tag
566
+ )
712
567
  cleanup_rds_snapshots(neo4j_session, common_job_parameters)
713
568
 
714
569
 
570
+ @timeit
571
+ def sync_rds_event_subscriptions(
572
+ neo4j_session: neo4j.Session,
573
+ boto3_session: boto3.session.Session,
574
+ regions: List[str],
575
+ current_aws_account_id: str,
576
+ update_tag: int,
577
+ common_job_parameters: Dict,
578
+ ) -> None:
579
+ """
580
+ Grab RDS event subscription data from AWS, ingest to neo4j, and run the cleanup job.
581
+ """
582
+ for region in regions:
583
+ logger.info(
584
+ "Syncing RDS event subscriptions for region '%s' in account '%s'.",
585
+ region,
586
+ current_aws_account_id,
587
+ )
588
+ data = get_rds_event_subscription_data(boto3_session, region)
589
+ transformed = transform_rds_event_subscriptions(data)
590
+ load_rds_event_subscriptions(
591
+ neo4j_session, transformed, region, current_aws_account_id, update_tag
592
+ )
593
+ cleanup_rds_event_subscriptions(neo4j_session, common_job_parameters)
594
+
595
+
715
596
  @timeit
716
597
  def sync(
717
598
  neo4j_session: neo4j.Session,
@@ -745,6 +626,16 @@ def sync(
745
626
  update_tag,
746
627
  common_job_parameters,
747
628
  )
629
+
630
+ sync_rds_event_subscriptions(
631
+ neo4j_session,
632
+ boto3_session,
633
+ regions,
634
+ current_aws_account_id,
635
+ update_tag,
636
+ common_job_parameters,
637
+ )
638
+
748
639
  merge_module_sync_metadata(
749
640
  neo4j_session,
750
641
  group_type="AWSAccount",