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,12 +1,13 @@
1
1
  import logging
2
2
  from typing import Any
3
- from typing import Dict
4
- from typing import List
5
3
 
6
4
  import boto3
5
+ import botocore.exceptions
7
6
  import neo4j
8
7
 
9
8
  from cartography.client.core.tx import load
9
+ from cartography.client.core.tx import load_matchlinks
10
+ from cartography.client.core.tx import read_list_of_dicts_tx
10
11
  from cartography.graph.job import GraphJob
11
12
  from cartography.models.aws.identitycenter.awsidentitycenter import (
12
13
  AWSIdentityCenterInstanceSchema,
@@ -14,20 +15,38 @@ from cartography.models.aws.identitycenter.awsidentitycenter import (
14
15
  from cartography.models.aws.identitycenter.awspermissionset import (
15
16
  AWSPermissionSetSchema,
16
17
  )
18
+ from cartography.models.aws.identitycenter.awspermissionset import (
19
+ AWSRoleToSSOGroupMatchLink,
20
+ )
21
+ from cartography.models.aws.identitycenter.awspermissionset import (
22
+ AWSRoleToSSOUserMatchLink,
23
+ )
24
+ from cartography.models.aws.identitycenter.awssogroup import AWSSSOGroupSchema
17
25
  from cartography.models.aws.identitycenter.awsssouser import AWSSSOUserSchema
18
26
  from cartography.util import aws_handle_regions
19
- from cartography.util import run_cleanup_job
20
27
  from cartography.util import timeit
21
28
 
22
29
  logger = logging.getLogger(__name__)
23
30
 
24
31
 
32
+ def _is_permission_set_sync_unsupported_error(
33
+ error: botocore.exceptions.ClientError,
34
+ ) -> bool:
35
+ """Return True when the Identity Center instance does not support permission sets."""
36
+ error_info = error.response.get("Error", {})
37
+ if error_info.get("Code") != "ValidationException":
38
+ return False
39
+
40
+ message = error_info.get("Message", "").lower()
41
+ return "not supported for this identity center instance" in message
42
+
43
+
25
44
  @timeit
26
45
  @aws_handle_regions
27
46
  def get_identity_center_instances(
28
47
  boto3_session: boto3.session.Session,
29
48
  region: str,
30
- ) -> List[Dict]:
49
+ ) -> list[dict[str, Any]]:
31
50
  """
32
51
  Get all AWS IAM Identity Center instances in the current region
33
52
  """
@@ -44,7 +63,7 @@ def get_identity_center_instances(
44
63
  @timeit
45
64
  def load_identity_center_instances(
46
65
  neo4j_session: neo4j.Session,
47
- instance_data: List[Dict],
66
+ instance_data: list[dict[str, Any]],
48
67
  region: str,
49
68
  current_aws_account_id: str,
50
69
  aws_update_tag: int,
@@ -71,7 +90,7 @@ def get_permission_sets(
71
90
  boto3_session: boto3.session.Session,
72
91
  instance_arn: str,
73
92
  region: str,
74
- ) -> List[Dict]:
93
+ ) -> list[dict[str, Any]]:
75
94
  """
76
95
  Get all permission sets for a given Identity Center instance
77
96
  """
@@ -88,18 +107,37 @@ def get_permission_sets(
88
107
  )
89
108
  permission_set = details.get("PermissionSet", {})
90
109
  if permission_set:
91
- permission_set["RoleHint"] = (
92
- f":role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_{permission_set.get('Name')}"
93
- )
94
110
  permission_sets.append(permission_set)
95
111
 
96
112
  return permission_sets
97
113
 
98
114
 
115
+ def transform_permission_sets(
116
+ permission_sets: list[dict[str, Any]],
117
+ region: str,
118
+ ) -> list[dict[str, Any]]:
119
+ """
120
+ Transform permission sets by adding the RoleHint based on region.
121
+
122
+ AWS SSO roles in us-east-1 don't include region in the ARN path,
123
+ but roles in other regions do: /aws-reserved/sso.amazonaws.com/{region}/AWSReservedSSO_*
124
+ """
125
+ for permission_set in permission_sets:
126
+ if region == "us-east-1":
127
+ permission_set["RoleHint"] = (
128
+ f":role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_{permission_set.get('Name')}"
129
+ )
130
+ else:
131
+ permission_set["RoleHint"] = (
132
+ f":role/aws-reserved/sso.amazonaws.com/{region}/AWSReservedSSO_{permission_set.get('Name')}"
133
+ )
134
+ return permission_sets
135
+
136
+
99
137
  @timeit
100
138
  def load_permission_sets(
101
139
  neo4j_session: neo4j.Session,
102
- permission_sets: List[Dict],
140
+ permission_sets: list[dict[str, Any]],
103
141
  instance_arn: str,
104
142
  region: str,
105
143
  aws_account_id: str,
@@ -120,6 +158,8 @@ def load_permission_sets(
120
158
  InstanceArn=instance_arn,
121
159
  Region=region,
122
160
  AWS_ID=aws_account_id,
161
+ _sub_resource_label="AWSAccount",
162
+ _sub_resource_id=aws_account_id,
123
163
  )
124
164
 
125
165
 
@@ -129,7 +169,7 @@ def get_sso_users(
129
169
  boto3_session: boto3.session.Session,
130
170
  identity_store_id: str,
131
171
  region: str,
132
- ) -> List[Dict]:
172
+ ) -> list[dict[str, Any]]:
133
173
  """
134
174
  Get all SSO users for a given Identity Store
135
175
  """
@@ -140,17 +180,117 @@ def get_sso_users(
140
180
  for page in paginator.paginate(IdentityStoreId=identity_store_id):
141
181
  user_page = page.get("Users", [])
142
182
  for user in user_page:
143
- if user.get("ExternalIds", None):
144
- user["ExternalId"] = user.get("ExternalIds")[0].get("Id")
145
183
  users.append(user)
146
184
 
147
185
  return users
148
186
 
149
187
 
188
+ @timeit
189
+ @aws_handle_regions
190
+ def get_sso_groups(
191
+ boto3_session: boto3.session.Session,
192
+ identity_store_id: str,
193
+ region: str,
194
+ ) -> list[dict[str, Any]]:
195
+ """
196
+ Get all SSO groups for a given Identity Store
197
+ """
198
+ client = boto3_session.client("identitystore", region_name=region)
199
+ groups: list[dict[str, Any]] = []
200
+
201
+ paginator = client.get_paginator("list_groups")
202
+ for page in paginator.paginate(IdentityStoreId=identity_store_id):
203
+ group_page = page.get("Groups", [])
204
+ for group in group_page:
205
+ groups.append(group)
206
+
207
+ return groups
208
+
209
+
210
+ def transform_sso_users(
211
+ users: list[dict[str, Any]],
212
+ user_group_memberships: dict[str, list[str]] | None = None,
213
+ user_permissionsets: list[dict[str, Any]] | None = None,
214
+ ) -> list[dict[str, Any]]:
215
+ """
216
+ Transform SSO users to match the expected schema, optionally including group memberships
217
+ and permission set assignments.
218
+
219
+ Args:
220
+ users: List of SSO users from AWS API
221
+ user_group_memberships: Optional mapping of UserId -> [GroupIds]
222
+ user_permissionsets: Optional list of permission set assignments with shape:
223
+ [{UserId: str, PermissionSetArn: str, AccountId: str}, ...]
224
+
225
+ Returns:
226
+ Transformed users with MemberOfGroups and AssignedPermissionSets fields added
227
+ """
228
+ # Build mapping from UserId to list of PermissionSetArns
229
+ user_permission_sets: dict[str, list[str]] = {}
230
+ if user_permissionsets:
231
+ for assignment in user_permissionsets:
232
+ user_id = assignment["UserId"]
233
+ perm_set = assignment["PermissionSetArn"]
234
+ user_permission_sets.setdefault(user_id, []).append(perm_set)
235
+
236
+ # Transform users
237
+ transformed_users = []
238
+ for user in users:
239
+ if user.get("ExternalIds"):
240
+ user["ExternalId"] = user["ExternalIds"][0].get("Id")
241
+ # Add group memberships if provided
242
+ if user_group_memberships:
243
+ user["MemberOfGroups"] = user_group_memberships.get(user["UserId"], [])
244
+ # Add direct permission set assignments if available
245
+ if user_permission_sets:
246
+ user["AssignedPermissionSets"] = user_permission_sets.get(
247
+ user["UserId"], []
248
+ )
249
+ transformed_users.append(user)
250
+ return transformed_users
251
+
252
+
253
+ def transform_sso_groups(
254
+ groups: list[dict[str, Any]],
255
+ group_role_assignments: list[dict[str, Any]] | None = None,
256
+ ) -> list[dict[str, Any]]:
257
+ """
258
+ Transform SSO groups to match the expected schema, optionally including permission set assignments.
259
+
260
+ Args:
261
+ groups: List of SSO groups from AWS API
262
+ group_role_assignments: Optional list of role assignments with shape:
263
+ [{GroupId: str, PermissionSetArn: str, AccountId: str}, ...]
264
+
265
+ Returns:
266
+ Transformed groups with AssignedPermissionSets field added
267
+ """
268
+ # Build mapping from GroupId to list of PermissionSetArns
269
+ group_permission_sets: dict[str, list[str]] = {}
270
+ if group_role_assignments:
271
+ for assignment in group_role_assignments:
272
+ group_id = assignment["GroupId"]
273
+ perm_set = assignment["PermissionSetArn"]
274
+ group_permission_sets.setdefault(group_id, []).append(perm_set)
275
+
276
+ # Transform groups
277
+ transformed_groups: list[dict[str, Any]] = []
278
+ for group in groups:
279
+ if group.get("ExternalIds"):
280
+ group["ExternalId"] = group["ExternalIds"][0].get("Id")
281
+ # Add permission set assignments if available
282
+ if group_permission_sets:
283
+ group["AssignedPermissionSets"] = group_permission_sets.get(
284
+ group["GroupId"], []
285
+ )
286
+ transformed_groups.append(group)
287
+ return transformed_groups
288
+
289
+
150
290
  @timeit
151
291
  def load_sso_users(
152
292
  neo4j_session: neo4j.Session,
153
- users: List[Dict],
293
+ users: list[dict[str, Any]],
154
294
  identity_store_id: str,
155
295
  region: str,
156
296
  aws_account_id: str,
@@ -174,21 +314,49 @@ def load_sso_users(
174
314
  )
175
315
 
176
316
 
317
+ @timeit
318
+ def load_sso_groups(
319
+ neo4j_session: neo4j.Session,
320
+ groups: list[dict[str, Any]],
321
+ identity_store_id: str,
322
+ region: str,
323
+ aws_account_id: str,
324
+ aws_update_tag: int,
325
+ ) -> None:
326
+ """
327
+ Load SSO groups into the graph
328
+ """
329
+ logger.info(
330
+ f"Loading {len(groups)} SSO groups for identity store {identity_store_id} in region {region}",
331
+ )
332
+
333
+ load(
334
+ neo4j_session,
335
+ AWSSSOGroupSchema(),
336
+ groups,
337
+ lastupdated=aws_update_tag,
338
+ IdentityStoreId=identity_store_id,
339
+ AWS_ID=aws_account_id,
340
+ Region=region,
341
+ )
342
+
343
+
177
344
  @timeit
178
345
  @aws_handle_regions
179
- def get_role_assignments(
346
+ def get_user_permissionsets(
180
347
  boto3_session: boto3.session.Session,
181
- users: List[Dict],
348
+ users: list[dict[str, Any]],
182
349
  instance_arn: str,
183
350
  region: str,
184
- ) -> List[Dict]:
351
+ ) -> list[dict[str, Any]]:
185
352
  """
186
- Get role assignments for SSO users
353
+ Get permissionsets for SSO users, taking into account which accounts the user is assigned to.
354
+ Although a permissionset can be assigned to multiple accounts, it is possible for the user
355
+ to be assigned to just a subset of those!
187
356
  """
188
-
189
- logger.info(f"Getting role assignments for {len(users)} users")
357
+ logger.info(f"Getting permissionsets for {len(users)} users")
190
358
  client = boto3_session.client("sso-admin", region_name=region)
191
- role_assignments = []
359
+ user_permissionsets = []
192
360
 
193
361
  for user in users:
194
362
  user_id = user["UserId"]
@@ -199,7 +367,7 @@ def get_role_assignments(
199
367
  PrincipalType="USER",
200
368
  ):
201
369
  for assignment in page.get("AccountAssignments", []):
202
- role_assignments.append(
370
+ user_permissionsets.append(
203
371
  {
204
372
  "UserId": user_id,
205
373
  "PermissionSetArn": assignment.get("PermissionSetArn"),
@@ -207,40 +375,198 @@ def get_role_assignments(
207
375
  },
208
376
  )
209
377
 
210
- return role_assignments
378
+ return user_permissionsets
379
+
380
+
381
+ @timeit
382
+ @aws_handle_regions
383
+ def get_group_permissionsets(
384
+ boto3_session: boto3.session.Session,
385
+ groups: list[dict[str, Any]],
386
+ instance_arn: str,
387
+ region: str,
388
+ ) -> list[dict[str, Any]]:
389
+ """
390
+ Get permissionsets for SSO groups, taking into account which accounts the group is assigned to.
391
+ """
392
+ logger.info(f"Getting permissionsets for {len(groups)} groups")
393
+ client = boto3_session.client("sso-admin", region_name=region)
394
+ group_permissionsets: list[dict[str, Any]] = []
395
+
396
+ for group in groups:
397
+ group_id = group["GroupId"]
398
+ paginator = client.get_paginator("list_account_assignments_for_principal")
399
+ for page in paginator.paginate(
400
+ InstanceArn=instance_arn,
401
+ PrincipalId=group_id,
402
+ PrincipalType="GROUP",
403
+ ):
404
+ for assignment in page.get("AccountAssignments", []):
405
+ group_permissionsets.append(
406
+ {
407
+ "GroupId": group_id,
408
+ "PermissionSetArn": assignment.get("PermissionSetArn"),
409
+ "AccountId": assignment.get("AccountId"),
410
+ }
411
+ )
412
+
413
+ return group_permissionsets
414
+
415
+
416
+ @timeit
417
+ @aws_handle_regions
418
+ def get_user_group_memberships(
419
+ boto3_session: boto3.session.Session,
420
+ identity_store_id: str,
421
+ groups: list[dict[str, Any]],
422
+ region: str,
423
+ ) -> dict[str, list[str]]:
424
+ """
425
+ Return a mapping of UserId -> [GroupIds] for all group memberships in the identity store.
426
+ """
427
+ client = boto3_session.client("identitystore", region_name=region)
428
+ user_groups: dict[str, list[str]] = {}
429
+
430
+ for group in groups:
431
+ group_id = group["GroupId"]
432
+ paginator = client.get_paginator("list_group_memberships")
433
+ for page in paginator.paginate(
434
+ IdentityStoreId=identity_store_id, GroupId=group_id
435
+ ):
436
+ for membership in page.get("GroupMemberships", []):
437
+ member = membership.get("MemberId", {})
438
+ user_id = member.get("UserId")
439
+ if user_id:
440
+ user_groups.setdefault(user_id, []).append(group_id)
441
+
442
+ return user_groups
211
443
 
212
444
 
213
445
  @timeit
214
- def load_role_assignments(
446
+ def _get_permset_roles(
215
447
  neo4j_session: neo4j.Session,
216
- role_assignments: List[Dict],
217
- aws_update_tag: int,
218
- ) -> None:
448
+ permset_ids: list[str],
449
+ ) -> dict[tuple[str, str], str]:
450
+ """
451
+ Given a list of permission set ARNs, return a mapping of (permission set ARN, account ID) to role ARN
452
+ based on the ASSIGNED_TO_ROLE relationship in the graph.
219
453
  """
220
- Load role assignments into the graph
221
- """
222
- logger.info(f"Loading {len(role_assignments)} role assignments")
223
- if role_assignments:
224
- neo4j_session.run(
225
- """
226
- UNWIND $role_assignments AS ra
227
- MATCH (acc:AWSAccount{id:ra.AccountId}) -[:RESOURCE]->
228
- (role:AWSRole)<-[:ASSIGNED_TO_ROLE]-
229
- (permset:AWSPermissionSet {id: ra.PermissionSetArn})
230
- MATCH (sso:AWSSSOUser {id: ra.UserId})
231
- MERGE (role)-[r:ALLOWED_BY]->(sso)
232
- SET r.lastupdated = $aws_update_tag,
233
- r.permission_set_arn = ra.PermissionSetArn
234
- """,
235
- role_assignments=role_assignments,
236
- aws_update_tag=aws_update_tag,
454
+ query = """
455
+ MATCH (role:AWSRole)<-[:ASSIGNED_TO_ROLE]-(permset:AWSPermissionSet)
456
+ MATCH (account:AWSAccount)-[:RESOURCE]->(role)
457
+ WHERE permset.arn IN $PermSetIds
458
+ RETURN permset.arn AS PermissionSetArn, role.arn AS RoleArn, account.id AS AccountId
459
+ """
460
+ permset_to_role = neo4j_session.execute_read(
461
+ read_list_of_dicts_tx,
462
+ query,
463
+ PermSetIds=permset_ids,
464
+ )
465
+ return {
466
+ (entry["PermissionSetArn"], entry["AccountId"]): entry["RoleArn"]
467
+ for entry in permset_to_role
468
+ }
469
+
470
+
471
+ @timeit
472
+ def get_principal_roles(
473
+ neo4j_session: neo4j.Session,
474
+ principal_assignments: list[dict[str, Any]],
475
+ ) -> list[dict[str, Any]]:
476
+ """
477
+ At this point we've established that the principal has access to a given account
478
+ via a given permission set, and now we need to find the exact role in the account
479
+ it has access to.
480
+ :param neo4j_session: neo4j.Session
481
+ :param principal_assignments: either a list of {
482
+ "UserId": str
483
+ "AccountId": str,
484
+ "PermissionSetArn": str,
485
+ }, or a list of {
486
+ "GroupId": str,
487
+ "AccountId": str,
488
+ "PermissionSetArn": str,
489
+ }
490
+ :return: either a list of {
491
+ "UserId": str,
492
+ "AccountId": str,
493
+ "PermissionSetArn": str,
494
+ "RoleArn": str
495
+ } or,
496
+ a list of {
497
+ "GroupId": str,
498
+ "AccountId": str,
499
+ "PermissionSetArn": str,
500
+ "RoleArn": str
501
+ }
502
+ """
503
+ # Get unique permission set ARNs from role assignments
504
+ permset_ids = list({pa["PermissionSetArn"] for pa in principal_assignments})
505
+ permset_to_role = _get_permset_roles(neo4j_session, permset_ids)
506
+
507
+ unmatched = 0
508
+ # Use the lookup table to enrich assignments with exact role ARNs
509
+ principal_roles = []
510
+ for assignment in principal_assignments:
511
+ lookup_key = (assignment["PermissionSetArn"], assignment["AccountId"])
512
+ role_arn = permset_to_role.get(lookup_key)
513
+ if not role_arn:
514
+ unmatched += 1
515
+ principal_roles.append(
516
+ {
517
+ **assignment,
518
+ "RoleArn": role_arn,
519
+ }
237
520
  )
521
+ if unmatched > 0:
522
+ logger.info(
523
+ f"Identity Center: {unmatched} of {len(principal_assignments)} principal assignments "
524
+ "did not match a role. This usually means IAM roles for some permission sets/accounts "
525
+ "have not been ingested yet. Re-run the IAM sync, and then the Identity Center sync to fix."
526
+ )
527
+ return principal_roles
528
+
529
+
530
+ @timeit
531
+ def load_user_roles(
532
+ neo4j_session: neo4j.Session,
533
+ user_roles: list[dict[str, Any]],
534
+ aws_account_id: str,
535
+ aws_update_tag: int,
536
+ ) -> None:
537
+ logger.info(f"Loading {len(user_roles)} user roles")
538
+ load_matchlinks(
539
+ neo4j_session,
540
+ AWSRoleToSSOUserMatchLink(),
541
+ user_roles,
542
+ lastupdated=aws_update_tag,
543
+ _sub_resource_label="AWSAccount",
544
+ _sub_resource_id=aws_account_id,
545
+ )
546
+
547
+
548
+ @timeit
549
+ def load_group_roles(
550
+ neo4j_session: neo4j.Session,
551
+ group_roles: list[dict[str, Any]],
552
+ aws_account_id: str,
553
+ aws_update_tag: int,
554
+ ) -> None:
555
+ logger.info(f"Loading {len(group_roles)} group roles")
556
+ load_matchlinks(
557
+ neo4j_session,
558
+ AWSRoleToSSOGroupMatchLink(),
559
+ group_roles,
560
+ lastupdated=aws_update_tag,
561
+ _sub_resource_label="AWSAccount",
562
+ _sub_resource_id=aws_account_id,
563
+ )
238
564
 
239
565
 
240
566
  @timeit
241
567
  def cleanup(
242
568
  neo4j_session: neo4j.Session,
243
- common_job_parameters: Dict[str, Any],
569
+ common_job_parameters: dict[str, Any],
244
570
  ) -> None:
245
571
  GraphJob.from_node_schema(
246
572
  AWSIdentityCenterInstanceSchema(),
@@ -252,24 +578,249 @@ def cleanup(
252
578
  GraphJob.from_node_schema(AWSSSOUserSchema(), common_job_parameters).run(
253
579
  neo4j_session,
254
580
  )
255
- run_cleanup_job(
256
- "aws_import_identity_center_cleanup.json",
581
+ GraphJob.from_node_schema(AWSSSOGroupSchema(), common_job_parameters).run(
257
582
  neo4j_session,
258
- common_job_parameters,
259
583
  )
260
584
 
585
+ # Clean up role assignment MatchLinks
586
+ GraphJob.from_matchlink(
587
+ AWSRoleToSSOUserMatchLink(),
588
+ "AWSAccount",
589
+ common_job_parameters["AWS_ID"],
590
+ common_job_parameters["UPDATE_TAG"],
591
+ ).run(neo4j_session)
592
+ GraphJob.from_matchlink(
593
+ AWSRoleToSSOGroupMatchLink(),
594
+ "AWSAccount",
595
+ common_job_parameters["AWS_ID"],
596
+ common_job_parameters["UPDATE_TAG"],
597
+ ).run(neo4j_session)
598
+
599
+
600
+ def _sync_permission_sets(
601
+ neo4j_session: neo4j.Session,
602
+ boto3_session: boto3.session.Session,
603
+ instance_arn: str,
604
+ region: str,
605
+ current_aws_account_id: str,
606
+ update_tag: int,
607
+ ) -> bool:
608
+ """
609
+ Sync permission sets for an Identity Center instance.
610
+
611
+ Returns:
612
+ True if permission set sync is supported, False for account-scoped instances
613
+ that don't support permission sets.
614
+ """
615
+ try:
616
+ permission_sets = get_permission_sets(boto3_session, instance_arn, region)
617
+ # Transform permission sets to add RoleHint for fuzzy matching to IAM roles
618
+ permission_sets = transform_permission_sets(permission_sets, region)
619
+ load_permission_sets(
620
+ neo4j_session,
621
+ permission_sets,
622
+ instance_arn,
623
+ region,
624
+ current_aws_account_id,
625
+ update_tag,
626
+ )
627
+ return True
628
+ except botocore.exceptions.ClientError as error:
629
+ if _is_permission_set_sync_unsupported_error(error):
630
+ logger.warning(
631
+ "Skipping permission set sync for Identity Center instance %s in region %s "
632
+ "because the instance does not support permission sets. "
633
+ "Will attempt to sync users and groups only.",
634
+ instance_arn,
635
+ region,
636
+ )
637
+ return False
638
+ raise
639
+
640
+
641
+ def _sync_groups_and_users(
642
+ neo4j_session: neo4j.Session,
643
+ boto3_session: boto3.session.Session,
644
+ instance_arn: str,
645
+ identity_store_id: str,
646
+ region: str,
647
+ permission_set_sync_supported: bool,
648
+ current_aws_account_id: str,
649
+ update_tag: int,
650
+ ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
651
+ """
652
+ Sync groups and users for an Identity Center instance.
653
+
654
+ Groups are synced first so that user->group membership edges can be created.
655
+ Permission set assignments are fetched (if supported) and used to enrich
656
+ the user/group nodes with HAS_PERMISSION_SET relationships, then returned
657
+ for later role assignment creation.
658
+
659
+ Args:
660
+ permission_set_sync_supported: If True, fetches and enriches permission set assignments
661
+
662
+ Returns:
663
+ (user_permission_set_assignments, group_permission_set_assignments)
664
+ These are the raw assignment data needed for creating ALLOWED_BY relationships.
665
+ Will be empty lists if permission_set_sync_supported is False.
666
+ """
667
+ # Fetch groups first to avoid interleaving between groups and users
668
+ groups = get_sso_groups(boto3_session, identity_store_id, region)
669
+
670
+ # Get permission set assignments for groups (if permission sets are supported)
671
+ group_permissionsets_raw: list[dict[str, Any]] = []
672
+ if permission_set_sync_supported:
673
+ group_permissionsets_raw = get_group_permissionsets(
674
+ boto3_session,
675
+ groups,
676
+ instance_arn,
677
+ region,
678
+ )
679
+
680
+ # Transform and load groups with their permission set assignments FIRST
681
+ # so that user->group membership edges can attach in the same run.
682
+ transformed_groups = transform_sso_groups(groups, group_permissionsets_raw)
683
+ load_sso_groups(
684
+ neo4j_session,
685
+ transformed_groups,
686
+ identity_store_id,
687
+ region,
688
+ current_aws_account_id,
689
+ update_tag,
690
+ )
691
+
692
+ # Handle users AFTER groups exist
693
+ users = get_sso_users(boto3_session, identity_store_id, region)
694
+ user_group_memberships = get_user_group_memberships(
695
+ boto3_session,
696
+ identity_store_id,
697
+ groups,
698
+ region,
699
+ )
700
+
701
+ # Get direct permission set assignments for users (if permission sets are supported)
702
+ user_permissionsets_raw: list[dict[str, Any]] = []
703
+ if permission_set_sync_supported:
704
+ user_permissionsets_raw = get_user_permissionsets(
705
+ boto3_session,
706
+ users,
707
+ instance_arn,
708
+ region,
709
+ )
710
+
711
+ # Transform and load users with their group memberships AFTER groups exist
712
+ transformed_users = transform_sso_users(
713
+ users,
714
+ user_group_memberships,
715
+ user_permissionsets_raw,
716
+ )
717
+ load_sso_users(
718
+ neo4j_session,
719
+ transformed_users,
720
+ identity_store_id,
721
+ region,
722
+ current_aws_account_id,
723
+ update_tag,
724
+ )
725
+
726
+ # Return the raw assignment data for role assignment creation
727
+ return user_permissionsets_raw, group_permissionsets_raw
728
+
729
+
730
+ def _sync_role_assignments(
731
+ neo4j_session: neo4j.Session,
732
+ user_permissionsets_raw: list[dict[str, Any]],
733
+ group_permissionsets_raw: list[dict[str, Any]],
734
+ current_aws_account_id: str,
735
+ update_tag: int,
736
+ ) -> None:
737
+ """
738
+ Create ALLOWED_BY relationships between IAM roles and SSO principals.
739
+
740
+ This enriches the raw permission set assignment data with exact role ARNs
741
+ from the graph (using the composite key lookup), then creates the MatchLink
742
+ relationships.
743
+
744
+ Note: This must be called AFTER groups and users are loaded so that the
745
+ MatchLinks can find the existing AWSSSOUser/AWSSSOGroup nodes when creating
746
+ the ALLOWED_BY edges.
747
+ """
748
+ user_roles = get_principal_roles(neo4j_session, user_permissionsets_raw)
749
+ load_user_roles(neo4j_session, user_roles, current_aws_account_id, update_tag)
750
+
751
+ group_roles = get_principal_roles(neo4j_session, group_permissionsets_raw)
752
+ load_group_roles(neo4j_session, group_roles, current_aws_account_id, update_tag)
753
+
754
+
755
+ def _sync_instance(
756
+ neo4j_session: neo4j.Session,
757
+ boto3_session: boto3.session.Session,
758
+ instance: dict[str, Any],
759
+ region: str,
760
+ current_aws_account_id: str,
761
+ update_tag: int,
762
+ ) -> None:
763
+ """
764
+ Sync a single Identity Center instance.
765
+
766
+ This syncs permission sets (if supported), groups, users, and role assignments
767
+ in the correct order to ensure all relationships can be created.
768
+ """
769
+ instance_arn = instance["InstanceArn"]
770
+ identity_store_id = instance["IdentityStoreId"]
771
+
772
+ # Sync permission sets (may not be supported for account-scoped instances)
773
+ permission_set_sync_supported = _sync_permission_sets(
774
+ neo4j_session,
775
+ boto3_session,
776
+ instance_arn,
777
+ region,
778
+ current_aws_account_id,
779
+ update_tag,
780
+ )
781
+
782
+ # Sync groups and users (always happens, but enriched with permission sets if available)
783
+ user_assignments, group_assignments = _sync_groups_and_users(
784
+ neo4j_session,
785
+ boto3_session,
786
+ instance_arn,
787
+ identity_store_id,
788
+ region,
789
+ permission_set_sync_supported,
790
+ current_aws_account_id,
791
+ update_tag,
792
+ )
793
+
794
+ # Create role assignment relationships (only if permission sets are supported)
795
+ if permission_set_sync_supported:
796
+ _sync_role_assignments(
797
+ neo4j_session,
798
+ user_assignments,
799
+ group_assignments,
800
+ current_aws_account_id,
801
+ update_tag,
802
+ )
803
+
261
804
 
262
805
  @timeit
263
806
  def sync_identity_center_instances(
264
807
  neo4j_session: neo4j.Session,
265
808
  boto3_session: boto3.session.Session,
266
- regions: List[str],
809
+ regions: list[str],
267
810
  current_aws_account_id: str,
268
811
  update_tag: int,
269
- common_job_parameters: Dict,
812
+ common_job_parameters: dict[str, Any],
270
813
  ) -> None:
271
814
  """
272
- Sync Identity Center instances, their permission sets, and SSO users
815
+ Sync Identity Center instances across all specified regions.
816
+
817
+ For each instance, syncs:
818
+ 1. Permission sets (if supported by the instance type)
819
+ 2. Groups and users (with permission set assignments if available)
820
+ 3. Role assignment relationships (ALLOWED_BY edges from roles to principals)
821
+
822
+ Account-scoped Identity Center instances don't support permission sets and will
823
+ skip step 1 and 3, but still sync users and groups.
273
824
  """
274
825
  logger.info(f"Syncing Identity Center instances for regions {regions}")
275
826
  for region in regions:
@@ -283,42 +834,13 @@ def sync_identity_center_instances(
283
834
  update_tag,
284
835
  )
285
836
 
286
- # For each instance, get and load its permission sets and SSO users
287
837
  for instance in instances:
288
- instance_arn = instance["InstanceArn"]
289
- identity_store_id = instance["IdentityStoreId"]
290
-
291
- permission_sets = get_permission_sets(boto3_session, instance_arn, region)
292
-
293
- load_permission_sets(
294
- neo4j_session,
295
- permission_sets,
296
- instance_arn,
297
- region,
298
- current_aws_account_id,
299
- update_tag,
300
- )
301
-
302
- users = get_sso_users(boto3_session, identity_store_id, region)
303
- load_sso_users(
838
+ _sync_instance(
304
839
  neo4j_session,
305
- users,
306
- identity_store_id,
307
- region,
308
- current_aws_account_id,
309
- update_tag,
310
- )
311
-
312
- # Get and load role assignments
313
- role_assignments = get_role_assignments(
314
840
  boto3_session,
315
- users,
316
- instance_arn,
841
+ instance,
317
842
  region,
318
- )
319
- load_role_assignments(
320
- neo4j_session,
321
- role_assignments,
843
+ current_aws_account_id,
322
844
  update_tag,
323
845
  )
324
846