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,60 +1,110 @@
1
+ import json
1
2
  import logging
2
- from typing import Dict
3
- from typing import List
3
+ from typing import Any
4
4
 
5
- from neo4j import Session
5
+ import neo4j
6
+ from kubernetes.client.models import V1OwnerReference
7
+ from kubernetes.client.models import V1Secret
6
8
 
9
+ from cartography.client.core.tx import load
10
+ from cartography.graph.job import GraphJob
7
11
  from cartography.intel.kubernetes.util import get_epoch
12
+ from cartography.intel.kubernetes.util import k8s_paginate
8
13
  from cartography.intel.kubernetes.util import K8sClient
14
+ from cartography.models.kubernetes.secrets import KubernetesSecretSchema
9
15
  from cartography.util import timeit
10
16
 
11
17
  logger = logging.getLogger(__name__)
12
18
 
13
19
 
14
20
  @timeit
15
- def sync_secrets(
16
- session: Session,
17
- client: K8sClient,
21
+ def get_secrets(client: K8sClient) -> list[V1Secret]:
22
+ items = k8s_paginate(client.core.list_secret_for_all_namespaces)
23
+ return items
24
+
25
+
26
+ def _get_owner_references(
27
+ owner_references: list[V1OwnerReference] | None,
28
+ ) -> str | None:
29
+ if owner_references:
30
+ owner_references_list = []
31
+ for owner_reference in owner_references:
32
+ owner_references_list.append(
33
+ {
34
+ "kind": owner_reference.kind,
35
+ "name": owner_reference.name,
36
+ "uid": owner_reference.uid,
37
+ "apiVersion": owner_reference.api_version,
38
+ "controller": owner_reference.controller,
39
+ }
40
+ )
41
+ return json.dumps(owner_references_list)
42
+ return None
43
+
44
+
45
+ def transform_secrets(secrets: list[V1Secret]) -> list[dict[str, Any]]:
46
+ secrets_list = []
47
+ for secret in secrets:
48
+ secrets_list.append(
49
+ {
50
+ "uid": secret.metadata.uid,
51
+ "name": secret.metadata.name,
52
+ "creation_timestamp": get_epoch(secret.metadata.creation_timestamp),
53
+ "deletion_timestamp": get_epoch(secret.metadata.deletion_timestamp),
54
+ "owner_references": _get_owner_references(
55
+ secret.metadata.owner_references
56
+ ),
57
+ "namespace": secret.metadata.namespace,
58
+ "type": secret.type,
59
+ }
60
+ )
61
+
62
+ return secrets_list
63
+
64
+
65
+ @timeit
66
+ def load_secrets(
67
+ session: neo4j.Session,
68
+ secrets: list[dict[str, Any]],
18
69
  update_tag: int,
19
- cluster: Dict,
20
- ) -> List[Dict]:
21
- secrets = get_secrets(client, cluster)
22
- load_secrets(session, secrets, update_tag)
23
- return secrets
70
+ cluster_id: str,
71
+ cluster_name: str,
72
+ ) -> None:
73
+ logger.info(f"Loading {len(secrets)} KubernetesSecrets")
74
+ load(
75
+ session,
76
+ KubernetesSecretSchema(),
77
+ secrets,
78
+ lastupdated=update_tag,
79
+ CLUSTER_ID=cluster_id,
80
+ CLUSTER_NAME=cluster_name,
81
+ )
82
+
83
+
84
+ @timeit
85
+ def cleanup(session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
86
+ logger.debug("Running cleanup for KubernetesSecrets")
87
+ cleanup_job = GraphJob.from_node_schema(
88
+ KubernetesSecretSchema(),
89
+ common_job_parameters,
90
+ )
91
+ cleanup_job.run(session)
24
92
 
25
93
 
26
94
  @timeit
27
- def get_secrets(client: K8sClient, cluster: Dict) -> List[Dict]:
28
- return [
29
- {
30
- "uid": secret.metadata.uid,
31
- "name": secret.metadata.name,
32
- "creation_timestamp": get_epoch(secret.metadata.creation_timestamp),
33
- "deletion_timestamp": get_epoch(secret.metadata.deletion_timestamp),
34
- "namespace": secret.metadata.namespace,
35
- "cluster_uid": cluster["uid"],
36
- "labels": secret.metadata.labels,
37
- "type": secret.type,
38
- }
39
- for secret in client.core.list_secret_for_all_namespaces().items
40
- ]
41
-
42
-
43
- def load_secrets(session: Session, data: List[Dict], update_tag: int) -> None:
44
- ingestion_cypher_query = """
45
- UNWIND $secrets as k8secret
46
- MERGE (secret:KubernetesSecret {id: k8secret.uid})
47
- ON CREATE SET secret.firstseen = timestamp()
48
- SET secret.lastupdated = $update_tag,
49
- secret.name = k8secret.name,
50
- secret.created_at = k8secret.creation_timestamp,
51
- secret.deleted_at = k8secret.deletion_timestamp,
52
- secret.type = k8secret.type
53
- WITH secret, k8secret.namespace as ns, k8secret.cluster_uid as cuid
54
- MATCH (cluster:KubernetesCluster {id: cuid})-[:HAS_NAMESPACE]->(space:KubernetesNamespace {name: ns})
55
- MERGE (space)-[rel1:HAS_SECRET]->(secret)
56
- ON CREATE SET rel1.firstseen = timestamp()
57
- SET rel1.lastupdated = $update_tag
58
- """
59
- logger.info(f"Loading {len(data)} kubernetes secrets.")
60
- session.run(ingestion_cypher_query, secrets=data, update_tag=update_tag)
95
+ def sync_secrets(
96
+ session: neo4j.Session,
97
+ client: K8sClient,
98
+ update_tag: int,
99
+ common_job_parameters: dict[str, Any],
100
+ ) -> None:
101
+ secrets = get_secrets(client)
102
+ transformed_secrets = transform_secrets(secrets)
103
+ load_secrets(
104
+ session=session,
105
+ secrets=transformed_secrets,
106
+ update_tag=update_tag,
107
+ cluster_id=common_job_parameters["CLUSTER_ID"],
108
+ cluster_name=client.name,
109
+ )
110
+ cleanup(session, common_job_parameters)
@@ -1,90 +1,154 @@
1
+ import json
1
2
  import logging
2
- from typing import Dict
3
- from typing import List
3
+ from typing import Any
4
4
 
5
- from neo4j import Session
5
+ import neo4j
6
+ from kubernetes.client.models import V1LoadBalancerIngress
7
+ from kubernetes.client.models import V1PortStatus
8
+ from kubernetes.client.models import V1Service
6
9
 
10
+ from cartography.client.core.tx import load
11
+ from cartography.graph.job import GraphJob
7
12
  from cartography.intel.kubernetes.util import get_epoch
13
+ from cartography.intel.kubernetes.util import k8s_paginate
8
14
  from cartography.intel.kubernetes.util import K8sClient
15
+ from cartography.models.kubernetes.services import KubernetesServiceSchema
9
16
  from cartography.util import timeit
10
17
 
11
18
  logger = logging.getLogger(__name__)
12
19
 
13
20
 
14
21
  @timeit
15
- def sync_services(
16
- session: Session,
17
- client: K8sClient,
18
- update_tag: int,
19
- cluster: Dict,
20
- pods: List[Dict],
21
- ) -> None:
22
- services = get_services(client, cluster, pods)
23
- load_services(session, services, update_tag)
22
+ def get_services(client: K8sClient) -> list[V1Service]:
23
+ items = k8s_paginate(client.core.list_service_for_all_namespaces)
24
+ return items
24
25
 
25
26
 
26
- @timeit
27
- def get_services(client: K8sClient, cluster: Dict, pods: List[Dict]) -> List[Dict]:
28
- services = list()
29
- for service in client.core.list_service_for_all_namespaces().items:
27
+ def _format_service_selector(selector: dict[str, str]) -> str:
28
+ return json.dumps(selector)
29
+
30
+
31
+ def _format_load_balancer_ingress(ingress: list[V1LoadBalancerIngress] | None) -> str:
32
+
33
+ def _format_ingress_ports(
34
+ ports: list[V1PortStatus] | None,
35
+ ) -> list[dict[str, Any]] | None:
36
+ if ports is None:
37
+ return None
38
+
39
+ ingress_ports = []
40
+ for port in ports:
41
+ ingress_ports.append(
42
+ {
43
+ "error": port.port,
44
+ "port": port.protocol,
45
+ "protocol": port.ip,
46
+ }
47
+ )
48
+ return ingress_ports
49
+
50
+ if ingress is None:
51
+ return json.dumps(None)
52
+
53
+ loadbalancer_ingress = []
54
+ for item in ingress:
55
+ loadbalancer_ingress.append(
56
+ {
57
+ "hostname": item.hostname,
58
+ "ip": item.ip,
59
+ "ip_mode": item.ip_mode,
60
+ "ports": _format_ingress_ports(item.ports),
61
+ }
62
+ )
63
+ return json.dumps(loadbalancer_ingress)
64
+
65
+
66
+ def transform_services(
67
+ services: list[V1Service], all_pods: list[dict[str, Any]]
68
+ ) -> list[dict[str, Any]]:
69
+ services_list = []
70
+ for service in services:
30
71
  item = {
31
72
  "uid": service.metadata.uid,
32
73
  "name": service.metadata.name,
33
74
  "creation_timestamp": get_epoch(service.metadata.creation_timestamp),
34
75
  "deletion_timestamp": get_epoch(service.metadata.deletion_timestamp),
35
76
  "namespace": service.metadata.namespace,
36
- "cluster_uid": cluster["uid"],
37
77
  "type": service.spec.type,
38
- "selector": service.spec.selector,
78
+ "selector": _format_service_selector(service.spec.selector),
79
+ "cluster_ip": service.spec.cluster_ip,
39
80
  "load_balancer_ip": service.spec.load_balancer_ip,
40
81
  }
41
82
 
42
- ingresses = service.status.load_balancer.ingress
43
- for ingress in ingresses or list():
44
- item.update({"ingress_host": ingress.hostname, "ingress_ip": ingress.ip})
45
-
46
- service_pods = list()
47
- for pod in pods:
48
- is_service_pod = True if service.spec.selector else False
49
- for selector in service.spec.selector or dict():
50
- if (
51
- not pod.get("labels")
52
- or selector not in pod["labels"]
53
- or service.spec.selector[selector] != pod["labels"][selector]
54
- ):
55
- is_service_pod = False
56
- break
57
- if is_service_pod:
58
- service_pods.append(pod)
59
- item["pods"] = service_pods
60
- services.append(item)
61
- return services
62
-
63
-
64
- def load_services(session: Session, data: List[Dict], update_tag: int) -> None:
65
- ingestion_cypher_query = """
66
- UNWIND $services as k8service
67
- MERGE (service:KubernetesService {id: k8service.uid})
68
- ON CREATE SET service.firstseen = timestamp()
69
- SET service.lastupdated = $update_tag,
70
- service.name = k8service.name,
71
- service.created_at = k8service.creation_timestamp,
72
- service.deleted_at = k8service.deletion_timestamp,
73
- service.type = k8service.type,
74
- service.load_balancer_ip = k8service.load_balancer_ip,
75
- service.ingress_host = k8service.ingress_host,
76
- service.ingress_ip = k8service.ingress_ip
77
- WITH service, k8service.namespace as ns, k8service.cluster_uid as cuid, k8service.pods as k8pods
78
- MATCH (cluster:KubernetesCluster {id: cuid})-[:HAS_NAMESPACE]->(space:KubernetesNamespace {name: ns})
79
- MERGE (space)-[rel1:HAS_SERVICE]->(service)
80
- ON CREATE SET rel1.firstseen = timestamp()
81
- SET rel1.lastupdated = $update_tag
82
- WITH service, k8pods
83
- UNWIND k8pods as k8pod
84
- MATCH (pod:KubernetesPod {id: k8pod.uid})
85
- MERGE (service)-[rel2:SERVES_POD]->(pod)
86
- ON CREATE SET rel2.firstseen = timestamp()
87
- SET rel2.lastupdated = $update_tag
88
- """
89
- logger.info(f"Loading {len(data)} kubernetes services.")
90
- session.run(ingestion_cypher_query, services=data, update_tag=update_tag)
83
+ # TODO: instead of storing a json string, we should probably create seperate nodes for each ingress
84
+ if service.spec.type == "LoadBalancer":
85
+ if service.status.load_balancer:
86
+ item["load_balancer_ingress"] = _format_load_balancer_ingress(
87
+ service.status.load_balancer.ingress
88
+ )
89
+
90
+ # check if pod labels match service selector and add pod_ids to item
91
+ pod_ids = []
92
+ for pod in all_pods:
93
+ if pod["namespace"] == service.metadata.namespace:
94
+ service_selector: dict[str, str] | None = service.spec.selector
95
+ pod_labels: dict[str, str] | None = json.loads(pod["labels"])
96
+
97
+ # check if pod labels match service selector
98
+ if pod_labels and service_selector:
99
+ if all(
100
+ service_selector[key] == pod_labels.get(key)
101
+ for key in service_selector
102
+ ):
103
+ pod_ids.append(pod["uid"])
104
+
105
+ item["pod_ids"] = pod_ids
106
+
107
+ services_list.append(item)
108
+ return services_list
109
+
110
+
111
+ def load_services(
112
+ session: neo4j.Session,
113
+ services: list[dict[str, Any]],
114
+ update_tag: int,
115
+ cluster_id: str,
116
+ cluster_name: str,
117
+ ) -> None:
118
+ logger.info(f"Loading {len(services)} KubernetesServices")
119
+ load(
120
+ session,
121
+ KubernetesServiceSchema(),
122
+ services,
123
+ lastupdated=update_tag,
124
+ CLUSTER_ID=cluster_id,
125
+ CLUSTER_NAME=cluster_name,
126
+ )
127
+
128
+
129
+ def cleanup(session: neo4j.Session, common_job_parameters: dict[str, Any]) -> None:
130
+ logger.debug("Running cleanup job for KubernetesService")
131
+ cleanup_job = GraphJob.from_node_schema(
132
+ KubernetesServiceSchema(), common_job_parameters
133
+ )
134
+ cleanup_job.run(session)
135
+
136
+
137
+ @timeit
138
+ def sync_services(
139
+ session: neo4j.Session,
140
+ client: K8sClient,
141
+ all_pods: list[dict[str, Any]],
142
+ update_tag: int,
143
+ common_job_parameters: dict[str, Any],
144
+ ) -> None:
145
+ services = get_services(client)
146
+ transformed_services = transform_services(services, all_pods)
147
+ load_services(
148
+ session=session,
149
+ services=transformed_services,
150
+ update_tag=update_tag,
151
+ cluster_id=common_job_parameters["CLUSTER_ID"],
152
+ cluster_name=client.name,
153
+ )
154
+ cleanup(session, common_job_parameters)
@@ -1,11 +1,17 @@
1
+ import logging
1
2
  from datetime import datetime
2
- from typing import List
3
- from typing import Union
3
+ from typing import Any
4
+ from typing import Callable
4
5
 
5
6
  from kubernetes import config
6
7
  from kubernetes.client import ApiClient
7
8
  from kubernetes.client import CoreV1Api
8
9
  from kubernetes.client import NetworkingV1Api
10
+ from kubernetes.client import RbacAuthorizationV1Api
11
+ from kubernetes.client import VersionApi
12
+ from kubernetes.client.exceptions import ApiException
13
+
14
+ logger = logging.getLogger(__name__)
9
15
 
10
16
 
11
17
  class KubernetesContextNotFound(Exception):
@@ -13,39 +19,161 @@ class KubernetesContextNotFound(Exception):
13
19
 
14
20
 
15
21
  class K8CoreApiClient(CoreV1Api):
16
- def __init__(self, name: str, api_client: ApiClient = None) -> None:
22
+ def __init__(
23
+ self,
24
+ name: str,
25
+ config_file: str,
26
+ api_client: ApiClient | None = None,
27
+ ) -> None:
17
28
  self.name = name
18
29
  if not api_client:
19
- api_client = config.new_client_from_config(context=name)
30
+ api_client = config.new_client_from_config(
31
+ context=name, config_file=config_file
32
+ )
20
33
  super().__init__(api_client=api_client)
21
34
 
22
35
 
23
36
  class K8NetworkingApiClient(NetworkingV1Api):
24
- def __init__(self, name: str, api_client: ApiClient = None) -> None:
37
+ def __init__(
38
+ self,
39
+ name: str,
40
+ config_file: str,
41
+ api_client: ApiClient | None = None,
42
+ ) -> None:
43
+ self.name = name
44
+ if not api_client:
45
+ api_client = config.new_client_from_config(
46
+ context=name, config_file=config_file
47
+ )
48
+ super().__init__(api_client=api_client)
49
+
50
+
51
+ class K8VersionApiClient(VersionApi):
52
+ def __init__(
53
+ self,
54
+ name: str,
55
+ config_file: str,
56
+ api_client: ApiClient | None = None,
57
+ ) -> None:
25
58
  self.name = name
26
59
  if not api_client:
27
- api_client = config.new_client_from_config(context=name)
60
+ api_client = config.new_client_from_config(
61
+ context=name, config_file=config_file
62
+ )
63
+ super().__init__(api_client=api_client)
64
+
65
+
66
+ class K8RbacApiClient(RbacAuthorizationV1Api):
67
+ def __init__(
68
+ self,
69
+ name: str,
70
+ config_file: str,
71
+ api_client: ApiClient | None = None,
72
+ ) -> None:
73
+ self.name = name
74
+ if not api_client:
75
+ api_client = config.new_client_from_config(
76
+ context=name, config_file=config_file
77
+ )
28
78
  super().__init__(api_client=api_client)
29
79
 
30
80
 
31
81
  class K8sClient:
32
- def __init__(self, name: str) -> None:
82
+ def __init__(
83
+ self,
84
+ name: str,
85
+ config_file: str,
86
+ external_id: str | None = None,
87
+ ) -> None:
33
88
  self.name = name
34
- self.core = K8CoreApiClient(self.name)
35
- self.networking = K8NetworkingApiClient(self.name)
89
+ self.config_file = config_file
90
+ self.external_id = external_id
91
+ self.core = K8CoreApiClient(self.name, self.config_file)
92
+ self.networking = K8NetworkingApiClient(self.name, self.config_file)
93
+ self.version = K8VersionApiClient(self.name, self.config_file)
94
+ self.rbac = K8RbacApiClient(self.name, self.config_file)
36
95
 
37
96
 
38
- def get_k8s_clients(kubeconfig: str) -> List[K8sClient]:
97
+ def get_k8s_clients(kubeconfig: str) -> list[K8sClient]:
98
+ # returns a tuple of (all contexts, current context)
39
99
  contexts, _ = config.list_kube_config_contexts(kubeconfig)
40
100
  if not contexts:
41
101
  raise KubernetesContextNotFound("No context found in kubeconfig.")
42
- clients = list()
102
+
103
+ clients = []
43
104
  for context in contexts:
44
- clients.append(K8sClient(context["name"]))
105
+ clients.append(
106
+ K8sClient(
107
+ context["name"],
108
+ kubeconfig,
109
+ external_id=context["context"].get("cluster"),
110
+ ),
111
+ )
45
112
  return clients
46
113
 
47
114
 
48
- def get_epoch(date: datetime) -> Union[int, None]:
115
+ def get_epoch(date: datetime | None) -> int | None:
49
116
  if date:
50
- return int(date.strftime("%s"))
117
+ return int(date.timestamp())
51
118
  return None
119
+
120
+
121
+ def k8s_paginate(
122
+ list_func: Callable,
123
+ **kwargs: Any,
124
+ ) -> list[dict[str, Any]]:
125
+ """
126
+ Handles pagination for a Kubernetes API call.
127
+
128
+ :param list_func: The list function to call (e.g. client.core.list_pod_for_all_namespaces)
129
+ :param kwargs: Keyword arguments to pass to the list function (e.g. limit=100)
130
+ :return: A list of all resources returned by the list function
131
+ """
132
+ all_resources = []
133
+ continue_token = None
134
+ limit = kwargs.pop("limit", 100)
135
+ function_name = list_func.__name__
136
+
137
+ logger.debug(f"Starting pagination for {function_name} with limit {limit}.")
138
+
139
+ while True:
140
+ try:
141
+ if continue_token:
142
+ response = list_func(limit=limit, _continue=continue_token, **kwargs)
143
+ else:
144
+ response = list_func(limit=limit, **kwargs)
145
+
146
+ # Check if items exists on the response
147
+ if not hasattr(response, "items"):
148
+ logger.warning(
149
+ f"Response from {function_name} does not contain 'items' attribute."
150
+ )
151
+ break
152
+
153
+ items_count = len(response.items)
154
+ all_resources.extend(response.items)
155
+
156
+ logger.debug(f"Retrieved {items_count} {function_name} resources")
157
+
158
+ # Check if metadata exists on the response
159
+ if not hasattr(response, "metadata"):
160
+ logger.warning(
161
+ f"Response from {function_name} does not contain 'metadata' attribute."
162
+ )
163
+ break
164
+
165
+ continue_token = response.metadata._continue
166
+ if not continue_token:
167
+ logger.debug(f"No more {function_name} resources to retrieve.")
168
+ break
169
+
170
+ except ApiException as e:
171
+ logger.error(
172
+ f"Kubernetes API error retrieving {function_name} resources. {e}: {e.status} - {e.reason}"
173
+ )
174
+ break
175
+
176
+ logger.debug(
177
+ f"Completed pagination for {function_name}: retrieved {len(all_resources)} resources"
178
+ )
179
+ return all_resources
@@ -10,6 +10,8 @@ from typing import List
10
10
  import neo4j
11
11
  import oci
12
12
 
13
+ from cartography.client.core.tx import read_list_of_dicts_tx
14
+ from cartography.client.core.tx import run_write_query
13
15
  from cartography.util import run_cleanup_job
14
16
 
15
17
  from . import utils
@@ -89,7 +91,8 @@ def load_compartments(
89
91
  """
90
92
 
91
93
  for compartment in compartments:
92
- neo4j_session.run(
94
+ run_write_query(
95
+ neo4j_session,
93
96
  ingest_compartment,
94
97
  OCID=compartment["id"],
95
98
  COMPARTMENT_ID=compartment["compartment-id"],
@@ -126,7 +129,8 @@ def load_users(
126
129
  """
127
130
 
128
131
  for user in users:
129
- neo4j_session.run(
132
+ run_write_query(
133
+ neo4j_session,
130
134
  ingest_user,
131
135
  OCID=user["id"],
132
136
  CREATE_DATE=str(user["time-created"]),
@@ -206,7 +210,8 @@ def load_groups(
206
210
  """
207
211
 
208
212
  for group in groups:
209
- neo4j_session.run(
213
+ run_write_query(
214
+ neo4j_session,
210
215
  ingest_group,
211
216
  OCID=group["id"],
212
217
  CREATE_DATE=str(group["time-created"]),
@@ -260,7 +265,11 @@ def sync_group_memberships(
260
265
  "MATCH (group:OCIGroup)<-[:RESOURCE]-(OCITenancy{ocid: $OCI_TENANCY_ID}) "
261
266
  "return group.name as name, group.ocid as ocid;"
262
267
  )
263
- groups = neo4j_session.run(query, OCI_TENANCY_ID=current_tenancy_id)
268
+ groups = neo4j_session.execute_read(
269
+ read_list_of_dicts_tx,
270
+ query,
271
+ OCI_TENANCY_ID=current_tenancy_id,
272
+ )
264
273
  groups_membership = {
265
274
  group["ocid"]: get_group_membership_data(iam, group["ocid"], current_tenancy_id)
266
275
  for group in groups
@@ -288,7 +297,8 @@ def load_group_memberships(
288
297
  """
289
298
  for group_ocid, membership_data in group_memberships.items():
290
299
  for info in membership_data["GroupMemberships"]:
291
- neo4j_session.run(
300
+ run_write_query(
301
+ neo4j_session,
292
302
  ingest_membership,
293
303
  COMPARTMENT_ID=info["compartment-id"],
294
304
  GROUP_OCID=info["group-id"],
@@ -317,7 +327,8 @@ def load_policies(
317
327
  """
318
328
 
319
329
  for policy in policies:
320
- neo4j_session.run(
330
+ run_write_query(
331
+ neo4j_session,
321
332
  ingest_policy,
322
333
  OCID=policy["id"],
323
334
  POLICY_NAME=policy["name"],
@@ -386,7 +397,8 @@ def load_oci_policy_group_reference(
386
397
  ON CREATE SET r.firstseen = timestamp()
387
398
  SET r.lastupdated = $oci_update_tag
388
399
  """
389
- neo4j_session.run(
400
+ run_write_query(
401
+ neo4j_session,
390
402
  ingest_policy_group_reference,
391
403
  POLICY_ID=policy_id,
392
404
  GROUP_ID=group_id,
@@ -408,7 +420,8 @@ def load_oci_policy_compartment_reference(
408
420
  ON CREATE SET r.firstseen = timestamp()
409
421
  SET r.lastupdated = $oci_update_tag
410
422
  """
411
- neo4j_session.run(
423
+ run_write_query(
424
+ neo4j_session,
412
425
  ingest_policy_compartment_reference,
413
426
  POLICY_ID=policy_id,
414
427
  COMPARTMENT_ID=compartment_id,
@@ -487,7 +500,8 @@ def load_region_subscriptions(
487
500
  SET r.lastupdated = $oci_update_tag
488
501
  """
489
502
  for region in regions:
490
- neo4j_session.run(
503
+ run_write_query(
504
+ neo4j_session,
491
505
  query,
492
506
  REGION_KEY=region["region-key"],
493
507
  REGION_NAME=region["region-name"],