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
@@ -0,0 +1,291 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ import neo4j
5
+ from googleapiclient.discovery import Resource
6
+ from googleapiclient.errors import HttpError
7
+
8
+ from cartography.client.core.tx import load
9
+ from cartography.client.core.tx import load_matchlinks
10
+ from cartography.graph.job import GraphJob
11
+ from cartography.models.gsuite.group import GSuiteGroupSchema
12
+ from cartography.models.gsuite.group import GSuiteGroupToGroupMemberRel
13
+ from cartography.models.gsuite.group import GSuiteGroupToGroupOwnerRel
14
+ from cartography.models.gsuite.tenant import GSuiteTenantSchema
15
+ from cartography.util import timeit
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ GOOGLE_API_NUM_RETRIES = 5
20
+
21
+
22
+ @timeit
23
+ def get_all_groups(
24
+ admin: Resource, customer_id: str = "my_customer"
25
+ ) -> list[dict[str, Any]]:
26
+ """
27
+ Return list of Google Groups in your organization
28
+ Returns empty list if we are unable to enumerate the groups for any reasons
29
+
30
+ googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials, cache_discovery=False)
31
+
32
+ :param admin: google's apiclient discovery resource object. From googleapiclient.discovery.build
33
+ See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
34
+ :return: list of Google groups in domain
35
+ """
36
+ request = admin.groups().list(
37
+ customer=customer_id,
38
+ maxResults=20,
39
+ orderBy="email",
40
+ )
41
+ response_objects = []
42
+ while request is not None:
43
+ try:
44
+ resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
45
+ response_objects.extend(resp.get("groups", []))
46
+ request = admin.groups().list_next(request, resp)
47
+ except HttpError as e:
48
+ if (
49
+ e.resp.status == 403
50
+ and "Request had insufficient authentication scopes" in str(e)
51
+ ):
52
+ logger.error(
53
+ "Missing required GSuite scopes. If using the gcloud CLI, "
54
+ "run: gcloud auth application-default login --scopes="
55
+ '"https://www.googleapis.com/auth/admin.directory.user.readonly,'
56
+ "https://www.googleapis.com/auth/admin.directory.group.readonly,"
57
+ "https://www.googleapis.com/auth/admin.directory.group.member.readonly,"
58
+ 'https://www.googleapis.com/auth/cloud-platform"'
59
+ )
60
+ raise
61
+ return response_objects
62
+
63
+
64
+ @timeit
65
+ def get_members_for_groups(
66
+ admin: Resource, groups_email: list[str]
67
+ ) -> dict[str, list[dict[str, Any]]]:
68
+ """Get all members for given groups emails
69
+
70
+ Args:
71
+ admin (Resource): google's apiclient discovery resource object. From googleapiclient.discovery.build
72
+ See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
73
+ groups_email (list[str]): List of group email addresses to get members for
74
+
75
+
76
+ :return: list of dictionaries representing Users or Groups grouped by group email
77
+ """
78
+ results: dict[str, list[dict]] = {}
79
+ for group_email in groups_email:
80
+ request = admin.members().list(
81
+ groupKey=group_email,
82
+ maxResults=500,
83
+ )
84
+ members: list[dict] = []
85
+ while request is not None:
86
+ resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
87
+ members = members + resp.get("members", [])
88
+ request = admin.members().list_next(request, resp)
89
+ results[group_email] = members
90
+
91
+ return results
92
+
93
+
94
+ @timeit
95
+ def transform_groups(
96
+ groups: list[dict], group_memberships: dict[str, list[dict[str, Any]]]
97
+ ) -> tuple[list[dict], list[dict], list[dict]]:
98
+ """Strips list of API response objects to return list of group objects only and lists of subgroup relationships
99
+
100
+ :param groups: Raw groups from Google API
101
+ :param group_memberships: Group memberships data
102
+ :return: tuple of (groups, group_member_relationships, group_owner_relationships)
103
+ """
104
+ transformed_groups: list[dict] = []
105
+ group_member_relationships: list[dict] = []
106
+ group_owner_relationships: list[dict] = []
107
+
108
+ for group in groups:
109
+ group_id = group["id"]
110
+ group_email = group["email"]
111
+ group["member_ids"] = []
112
+ group["owner_ids"] = []
113
+
114
+ for member in group_memberships.get(group_email, []):
115
+ if member["type"] == "GROUP":
116
+ # Create group-to-group relationships
117
+ relationship_data = {
118
+ "parent_group_id": group_id,
119
+ "subgroup_id": member.get("id"),
120
+ "role": member.get("role"),
121
+ }
122
+
123
+ if member.get("role") == "OWNER":
124
+ group_owner_relationships.append(relationship_data)
125
+ else:
126
+ group_member_relationships.append(relationship_data)
127
+ continue
128
+
129
+ # Handle user memberships
130
+ if member.get("role") == "OWNER":
131
+ group["owner_ids"].append(member.get("id"))
132
+ group["member_ids"].append(member.get("id"))
133
+
134
+ transformed_groups.append(group)
135
+
136
+ return transformed_groups, group_member_relationships, group_owner_relationships
137
+
138
+
139
+ @timeit
140
+ def load_gsuite_groups(
141
+ neo4j_session: neo4j.Session,
142
+ groups: list[dict],
143
+ customer_id: str,
144
+ gsuite_update_tag: int,
145
+ ) -> None:
146
+ """
147
+ Load GSuite groups using the modern data model
148
+ """
149
+ logger.info("Ingesting %d gsuite groups", len(groups))
150
+
151
+ # Load tenant first if it doesn't exist
152
+ tenant_data = [{"id": customer_id}]
153
+ load(
154
+ neo4j_session,
155
+ GSuiteTenantSchema(),
156
+ tenant_data,
157
+ lastupdated=gsuite_update_tag,
158
+ )
159
+
160
+ # Load groups with relationship to tenant
161
+ load(
162
+ neo4j_session,
163
+ GSuiteGroupSchema(),
164
+ groups,
165
+ lastupdated=gsuite_update_tag,
166
+ CUSTOMER_ID=customer_id,
167
+ )
168
+
169
+
170
+ @timeit
171
+ def load_gsuite_group_to_group_relationships(
172
+ neo4j_session: neo4j.Session,
173
+ group_member_relationships: list[dict],
174
+ group_owner_relationships: list[dict],
175
+ customer_id: str,
176
+ gsuite_update_tag: int,
177
+ ) -> None:
178
+ """
179
+ Load GSuite group-to-group relationships using MatchLinks
180
+ """
181
+ logger.info(
182
+ "Ingesting %d group member relationships", len(group_member_relationships)
183
+ )
184
+ logger.info(
185
+ "Ingesting %d group owner relationships", len(group_owner_relationships)
186
+ )
187
+
188
+ # Load group member relationships (Group -> Group MEMBER)
189
+ if group_member_relationships:
190
+ load_matchlinks(
191
+ neo4j_session,
192
+ GSuiteGroupToGroupMemberRel(),
193
+ group_member_relationships,
194
+ lastupdated=gsuite_update_tag,
195
+ _sub_resource_label="GSuiteTenant",
196
+ _sub_resource_id=customer_id,
197
+ )
198
+
199
+ # Load group owner relationships (Group -> Group OWNER)
200
+ if group_owner_relationships:
201
+ load_matchlinks(
202
+ neo4j_session,
203
+ GSuiteGroupToGroupOwnerRel(),
204
+ group_owner_relationships,
205
+ lastupdated=gsuite_update_tag,
206
+ _sub_resource_label="GSuiteTenant",
207
+ _sub_resource_id=customer_id,
208
+ )
209
+
210
+
211
+ @timeit
212
+ def cleanup_gsuite_groups(
213
+ neo4j_session: neo4j.Session,
214
+ common_job_parameters: dict[str, Any],
215
+ customer_id: str,
216
+ gsuite_update_tag: int,
217
+ ) -> None:
218
+ """
219
+ Clean up GSuite groups and group-to-group relationships using the modern data model
220
+ """
221
+ logger.debug("Running GSuite groups cleanup job")
222
+
223
+ # Cleanup group nodes
224
+ GraphJob.from_node_schema(GSuiteGroupSchema(), common_job_parameters).run(
225
+ neo4j_session
226
+ )
227
+
228
+ # Cleanup group-to-group member relationships
229
+ GraphJob.from_matchlink(
230
+ GSuiteGroupToGroupMemberRel(),
231
+ "GSuiteTenant",
232
+ customer_id,
233
+ gsuite_update_tag,
234
+ ).run(neo4j_session)
235
+
236
+ # Cleanup group-to-group owner relationships
237
+ GraphJob.from_matchlink(
238
+ GSuiteGroupToGroupOwnerRel(),
239
+ "GSuiteTenant",
240
+ customer_id,
241
+ gsuite_update_tag,
242
+ ).run(neo4j_session)
243
+
244
+
245
+ @timeit
246
+ def sync_gsuite_groups(
247
+ neo4j_session: neo4j.Session,
248
+ admin: Resource,
249
+ gsuite_update_tag: int,
250
+ common_job_parameters: dict[str, Any],
251
+ ) -> None:
252
+ """
253
+ GET GSuite group objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
254
+
255
+ :param neo4j_session: The Neo4j session
256
+ :param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
257
+ See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
258
+ :param gsuite_update_tag: The timestamp value to set our new Neo4j nodes with
259
+ :param common_job_parameters: Parameters to carry to the Neo4j jobs
260
+ :return: Nothing
261
+ """
262
+ logger.debug("Syncing GSuite Groups")
263
+
264
+ customer_id = common_job_parameters.get(
265
+ "CUSTOMER_ID", "my_customer"
266
+ ) # Default to "my_customer" for backward compatibility
267
+
268
+ # 1. GET - Fetch data from API
269
+ resp_objs = get_all_groups(admin, customer_id)
270
+ group_members = get_members_for_groups(admin, [resp["email"] for resp in resp_objs])
271
+
272
+ # 2. TRANSFORM - Shape data for ingestion
273
+ groups, group_member_relationships, group_owner_relationships = transform_groups(
274
+ resp_objs, group_members
275
+ )
276
+
277
+ # 3. LOAD - Ingest to Neo4j using data model
278
+ load_gsuite_groups(neo4j_session, groups, customer_id, gsuite_update_tag)
279
+
280
+ # Load group-to-group relationships after groups are loaded
281
+ load_gsuite_group_to_group_relationships(
282
+ neo4j_session,
283
+ group_member_relationships,
284
+ group_owner_relationships,
285
+ customer_id,
286
+ gsuite_update_tag,
287
+ )
288
+
289
+ # 4. CLEANUP - Remove stale data
290
+ cleanup_params = {**common_job_parameters, "CUSTOMER_ID": customer_id}
291
+ cleanup_gsuite_groups(neo4j_session, cleanup_params, customer_id, gsuite_update_tag)
@@ -0,0 +1,142 @@
1
+ import logging
2
+ from collections import defaultdict
3
+ from typing import Any
4
+
5
+ import neo4j
6
+ from googleapiclient.discovery import Resource
7
+
8
+ from cartography.client.core.tx import load
9
+ from cartography.graph.job import GraphJob
10
+ from cartography.models.gsuite.tenant import GSuiteTenantSchema
11
+ from cartography.models.gsuite.user import GSuiteUserSchema
12
+ from cartography.util import timeit
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ GOOGLE_API_NUM_RETRIES = 5
17
+
18
+
19
+ @timeit
20
+ def get_all_users(admin: Resource) -> list[dict]:
21
+ """
22
+ Return list of Google Users in your organization
23
+ Returns empty list if we are unable to enumerate the users for any reasons
24
+ https://developers.google.com/admin-sdk/directory/v1/guides/manage-users
25
+
26
+ :param admin: apiclient discovery resource object
27
+ :return: list of Google users in domain
28
+ see https://developers.google.com/admin-sdk/directory/v1/guides/manage-users#get_all_domain_users
29
+ """
30
+ request = admin.users().list(
31
+ customer="my_customer",
32
+ maxResults=500,
33
+ orderBy="email",
34
+ )
35
+ response_objects = []
36
+ while request is not None:
37
+ resp = request.execute(num_retries=GOOGLE_API_NUM_RETRIES)
38
+ response_objects.append(resp)
39
+ request = admin.users().list_next(request, resp)
40
+ return response_objects
41
+
42
+
43
+ @timeit
44
+ def transform_users(response_objects: list[dict]) -> dict[str, list[dict[str, Any]]]:
45
+ """Transform list of API response objects to return list of user objects with flattened structure grouped by customerId
46
+ :param response_objects: Raw API response objects
47
+ :return: list of dictionary objects for data model consumption
48
+ """
49
+ results = defaultdict(list)
50
+ for response_object in response_objects:
51
+ for user in response_object["users"]:
52
+ # Flatten the nested name structure
53
+ transformed_user = user.copy()
54
+ if "name" in user and isinstance(user["name"], dict):
55
+ transformed_user["name"] = user["name"].get("fullName")
56
+ transformed_user["family_name"] = user["name"].get("familyName")
57
+ transformed_user["given_name"] = user["name"].get("givenName")
58
+ results[transformed_user["customerId"]].append(transformed_user)
59
+ return results
60
+
61
+
62
+ @timeit
63
+ def load_gsuite_users(
64
+ neo4j_session: neo4j.Session,
65
+ users_by_customer: dict[str, list[dict]],
66
+ gsuite_update_tag: int,
67
+ ) -> None:
68
+ """
69
+ Load GSuite users using the modern data model
70
+ """
71
+ logger.info("Ingesting %s gsuite tenants", len(users_by_customer))
72
+ tenant_data = [{"id": customer_id} for customer_id in users_by_customer.keys()]
73
+ load(
74
+ neo4j_session,
75
+ GSuiteTenantSchema(),
76
+ tenant_data,
77
+ lastupdated=gsuite_update_tag,
78
+ )
79
+
80
+ for customer_id, users in users_by_customer.items():
81
+ logger.info(
82
+ "Ingesting %s gsuite users for customer %s", len(users), customer_id
83
+ )
84
+ # Load users with relationship to tenant
85
+ load(
86
+ neo4j_session,
87
+ GSuiteUserSchema(),
88
+ users,
89
+ lastupdated=gsuite_update_tag,
90
+ CUSTOMER_ID=customer_id,
91
+ )
92
+
93
+
94
+ @timeit
95
+ def cleanup_gsuite_users(
96
+ neo4j_session: neo4j.Session,
97
+ common_job_parameters: dict[str, Any],
98
+ ) -> None:
99
+ """
100
+ Clean up GSuite users using the modern data model
101
+ """
102
+ logger.debug("Running GSuite users cleanup job")
103
+ GraphJob.from_node_schema(GSuiteUserSchema(), common_job_parameters).run(
104
+ neo4j_session
105
+ )
106
+
107
+
108
+ @timeit
109
+ def sync_gsuite_users(
110
+ neo4j_session: neo4j.Session,
111
+ admin: Resource,
112
+ gsuite_update_tag: int,
113
+ common_job_parameters: dict[str, Any],
114
+ ) -> list[str]:
115
+ """
116
+ GET GSuite user objects using the google admin api resource, load the data into Neo4j and clean up stale nodes.
117
+
118
+ :param neo4j_session: The Neo4j session
119
+ :param admin: Google admin resource object created by `googleapiclient.discovery.build()`.
120
+ See https://googleapis.github.io/google-api-python-client/docs/epy/googleapiclient.discovery-module.html#build.
121
+ :param gsuite_update_tag: The timestamp value to set our new Neo4j nodes with
122
+ :param common_job_parameters: Parameters to carry to the Neo4j jobs
123
+ :return: list of customer IDs
124
+ """
125
+ logger.debug("Syncing GSuite Users")
126
+
127
+ # 1. GET - Fetch data from API
128
+ resp_objs = get_all_users(admin)
129
+
130
+ # 2. TRANSFORM - Shape data for ingestion
131
+ users_by_customers = transform_users(resp_objs)
132
+
133
+ # 3. LOAD - Ingest to Neo4j using data model
134
+ load_gsuite_users(neo4j_session, users_by_customers, gsuite_update_tag)
135
+
136
+ # 4. CLEANUP - Remove stale data
137
+ for customer_id in users_by_customers.keys():
138
+ cleanup_params = {**common_job_parameters, "CUSTOMER_ID": customer_id}
139
+ cleanup_gsuite_users(neo4j_session, cleanup_params)
140
+
141
+ # Return the list of customer IDs
142
+ return list(users_by_customers.keys())
@@ -4,6 +4,7 @@ from typing import List
4
4
 
5
5
  import neo4j
6
6
 
7
+ from cartography.client.core.tx import run_write_query
7
8
  from cartography.intel.jamf.util import call_jamf_api
8
9
  from cartography.util import run_cleanup_job
9
10
  from cartography.util import timeit
@@ -35,7 +36,12 @@ def load_computer_groups(
35
36
  g.lastupdated = $UpdateTag
36
37
  """
37
38
  groups = data.get("computer_groups")
38
- neo4j_session.run(ingest_groups, JsonData=groups, UpdateTag=update_tag)
39
+ run_write_query(
40
+ neo4j_session,
41
+ ingest_groups,
42
+ JsonData=groups,
43
+ UpdateTag=update_tag,
44
+ )
39
45
 
40
46
 
41
47
  @timeit
@@ -0,0 +1,153 @@
1
+ import logging
2
+
3
+ import neo4j
4
+ import requests
5
+
6
+ import cartography.intel.keycloak.authenticationexecutions
7
+ import cartography.intel.keycloak.authenticationflows
8
+ import cartography.intel.keycloak.clients
9
+ import cartography.intel.keycloak.groups
10
+ import cartography.intel.keycloak.identityproviders
11
+ import cartography.intel.keycloak.organizations
12
+ import cartography.intel.keycloak.realms
13
+ import cartography.intel.keycloak.roles
14
+ import cartography.intel.keycloak.scopes
15
+ import cartography.intel.keycloak.users
16
+ from cartography.config import Config
17
+ from cartography.util import timeit
18
+
19
+ logger = logging.getLogger(__name__)
20
+ _TIMEOUT = (60, 60)
21
+
22
+
23
+ @timeit
24
+ def start_keycloak_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
25
+ """
26
+ If this module is configured, perform ingestion of Keycloak data. Otherwise warn and exit
27
+ :param neo4j_session: Neo4J session for database interface
28
+ :param config: A cartography.config object
29
+ :return: None
30
+ """
31
+ if (
32
+ not config.keycloak_client_id
33
+ or not config.keycloak_client_secret
34
+ or not config.keycloak_url
35
+ or not config.keycloak_realm
36
+ ):
37
+ logger.info(
38
+ "Keycloak import is not configured - skipping this module. "
39
+ "See docs to configure.",
40
+ )
41
+ return
42
+
43
+ # Create requests sessions
44
+ with requests.session() as api_session:
45
+ payload = {
46
+ "grant_type": "client_credentials",
47
+ "client_id": config.keycloak_client_id,
48
+ "client_secret": config.keycloak_client_secret,
49
+ }
50
+ req = api_session.post(
51
+ f"{config.keycloak_url}/realms/{config.keycloak_realm}/protocol/openid-connect/token",
52
+ data=payload,
53
+ timeout=_TIMEOUT,
54
+ )
55
+ req.raise_for_status()
56
+ api_session.headers.update(
57
+ {"Authorization": f'Bearer {req.json()["access_token"]}'}
58
+ )
59
+
60
+ common_job_parameters = {
61
+ "UPDATE_TAG": config.update_tag,
62
+ }
63
+
64
+ for realm in cartography.intel.keycloak.realms.sync(
65
+ neo4j_session, api_session, config.keycloak_url, common_job_parameters
66
+ ):
67
+ realm_scopped_job_parameters = {
68
+ "UPDATE_TAG": config.update_tag,
69
+ "REALM": realm["realm"],
70
+ "REALM_ID": realm["id"],
71
+ }
72
+ cartography.intel.keycloak.users.sync(
73
+ neo4j_session,
74
+ api_session,
75
+ config.keycloak_url,
76
+ realm_scopped_job_parameters,
77
+ )
78
+ cartography.intel.keycloak.identityproviders.sync(
79
+ neo4j_session,
80
+ api_session,
81
+ config.keycloak_url,
82
+ realm_scopped_job_parameters,
83
+ )
84
+ scopes = cartography.intel.keycloak.scopes.sync(
85
+ neo4j_session,
86
+ api_session,
87
+ config.keycloak_url,
88
+ realm_scopped_job_parameters,
89
+ )
90
+ scope_ids = [s["id"] for s in scopes]
91
+ flows = cartography.intel.keycloak.authenticationflows.sync(
92
+ neo4j_session,
93
+ api_session,
94
+ config.keycloak_url,
95
+ realm_scopped_job_parameters,
96
+ )
97
+ flow_aliases_to_id = {f["alias"]: f["id"] for f in flows}
98
+ cartography.intel.keycloak.authenticationexecutions.sync(
99
+ neo4j_session,
100
+ api_session,
101
+ config.keycloak_url,
102
+ realm_scopped_job_parameters,
103
+ list(flow_aliases_to_id.keys()),
104
+ )
105
+ realm_default_flows = {
106
+ "browser": flow_aliases_to_id.get(realm.get("browserFlow")),
107
+ "registration": flow_aliases_to_id.get(realm.get("registrationFlow")),
108
+ "direct_grant": flow_aliases_to_id.get(realm.get("directGrantFlow")),
109
+ "reset_credentials": flow_aliases_to_id.get(
110
+ realm.get("resetCredentialsFlow")
111
+ ),
112
+ "client_authentication": flow_aliases_to_id.get(
113
+ realm.get("clientAuthenticationFlow")
114
+ ),
115
+ "docker_authentication": flow_aliases_to_id.get(
116
+ realm.get("dockerAuthenticationFlow")
117
+ ),
118
+ "first_broker_login": flow_aliases_to_id.get(
119
+ realm.get("firstBrokerLoginFlow")
120
+ ),
121
+ }
122
+
123
+ clients = cartography.intel.keycloak.clients.sync(
124
+ neo4j_session,
125
+ api_session,
126
+ config.keycloak_url,
127
+ realm_scopped_job_parameters,
128
+ realm_default_flows,
129
+ )
130
+ client_ids = [c["id"] for c in clients]
131
+ cartography.intel.keycloak.roles.sync(
132
+ neo4j_session,
133
+ api_session,
134
+ config.keycloak_url,
135
+ realm_scopped_job_parameters,
136
+ client_ids,
137
+ scope_ids,
138
+ )
139
+ cartography.intel.keycloak.groups.sync(
140
+ neo4j_session,
141
+ api_session,
142
+ config.keycloak_url,
143
+ realm_scopped_job_parameters,
144
+ )
145
+
146
+ # Organizations if they are enabled
147
+ if realm.get("organizationsEnabled", False):
148
+ cartography.intel.keycloak.organizations.sync(
149
+ neo4j_session,
150
+ api_session,
151
+ config.keycloak_url,
152
+ realm_scopped_job_parameters,
153
+ )