Skip to content

Commit 814d1e6

Browse files
authored
Feat: ResourcePool Authorization via Authzed/SpiceDB (#1266)
* Feat: move resource pools check to authz (#1248) * feat: update schema for authzed * feat(authz): add ResourcePool as a supported authorization resource * feat(authz): add member and prohibited relationship types * feat(db): add ResourcePool authz schema migration, copy membership * chore(authz): update schema tests for resource pools * feat(authz): add the USE Scope * chore(tests): update the authorization tests for resource pools * squashme: copy-paste artifact * squashme: format * refactor: use vars instead of magic strings * fix: move migration head * feat: add test for migration * refactor: harmonize nomenclature * Feat: authz resource pools feature parity (#1256) * feat: add ResourcePool and membership types * feat: add ResourcePool as a supported authorization resource * feat: add member and prohibited relationships * refactor: authz_change decorator for multiple APIUser args * fix: session commit responsibility to session creator * refactor: move authorization logic to authz schema * feat: wire Authz into dependency graphs * feat: update blueprint func for single rp * fix: use proper non admin user in visibility tests * feat: visibility toggle test for rp * feat: update test utils setup for rp_repo with authz * refactor: update functions for authz usage * feat: new authorization tests * fix: use NonCachingAuthz in nb_config for tests * squashme: remove debug print * squashme: fix comments * fix: edge case for noop visibility change * refactor: authz consistency * fix: call spicedb only on authz updates * chore: fix error message * refactor: DRY some stuff * squashme: remove commented out code * fix: await resource pool creation with authz * feat: support PROHIBITED role with bidirectional Relation mapping * refactor: allow Member to represent non-group resources * refactor: unify resource pool membership under single ResourceType * refactor: rename default resource pool create function * refactor: use TypeVar for resource_id
1 parent ad7bb15 commit 814d1e6

18 files changed

Lines changed: 1475 additions & 160 deletions

File tree

bases/renku_data_services/data_api/config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ def from_env(cls, db: DBConfig | None = None) -> Self:
5151
if db is None:
5252
db = DBConfig.from_env()
5353

54+
authz_config = AuthzConfig.from_env()
55+
5456
if dummy_stores:
5557
keycloak = None
5658
gitlab_url = None
@@ -63,7 +65,7 @@ def from_env(cls, db: DBConfig | None = None) -> Self:
6365
else:
6466
gitlab_url = None
6567

66-
nb_config = NotebooksConfig.from_env(db, enable_internal_gitlab=enable_internal_gitlab)
68+
nb_config = NotebooksConfig.from_env(db, authz_config, enable_internal_gitlab=enable_internal_gitlab)
6769
return cls(
6870
enable_internal_gitlab=enable_internal_gitlab,
6971
version=os.environ.get("VERSION", "0.0.1"),
@@ -76,7 +78,7 @@ def from_env(cls, db: DBConfig | None = None) -> Self:
7678
secrets=PublicSecretsConfig.from_env(),
7779
sentry=SentryConfig.from_env(),
7880
posthog=PosthogConfig.from_env(),
79-
authz_config=AuthzConfig.from_env(),
81+
authz_config=authz_config,
8082
solr=SolrClientConfig.from_env(),
8183
trusted_proxies=TrustedProxiesConfig.from_env(),
8284
keycloak=keycloak,

bases/renku_data_services/data_api/dependencies.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,11 @@ def from_env(cls) -> DependencyManager:
326326
session_maker=config.db.async_session_maker,
327327
quotas_repo=quota_repo,
328328
user_repo=kc_user_repo,
329+
authz=authz,
330+
)
331+
rp_repo = ResourcePoolRepository(
332+
session_maker=config.db.async_session_maker, quotas_repo=quota_repo, authz=authz
329333
)
330-
rp_repo = ResourcePoolRepository(session_maker=config.db.async_session_maker, quotas_repo=quota_repo)
331334
storage_repo = StorageRepository(
332335
session_maker=config.db.async_session_maker,
333336
gitlab_client=gitlab_client,

bases/renku_data_services/k8s_cache/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Self
88

99
from renku_data_services.app_config.config import SentryConfig
10+
from renku_data_services.authz.config import AuthzConfig
1011
from renku_data_services.db_config.config import DBConfig
1112

1213

@@ -74,6 +75,7 @@ class Config:
7475
metrics: _MetricsConfig
7576
image_builders: _ImageBuilderConfig
7677
v1_services: _V1ServicesConfig
78+
authz: AuthzConfig
7779
sentry: SentryConfig
7880

7981
@classmethod
@@ -84,12 +86,14 @@ def from_env(cls) -> Config:
8486
metrics = _MetricsConfig.from_env()
8587
image_builders = _ImageBuilderConfig.from_env()
8688
v1_services = _V1ServicesConfig.from_env()
89+
authz = AuthzConfig.from_env()
8790
sentry = SentryConfig.from_env()
8891
return cls(
8992
db=db,
9093
k8s=k8s,
9194
metrics=metrics,
9295
image_builders=image_builders,
9396
v1_services=v1_services,
97+
authz=authz,
9498
sentry=sentry,
9599
)

bases/renku_data_services/k8s_cache/dependencies.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from dataclasses import dataclass, field
44

5+
from renku_data_services.authz.authz import Authz
56
from renku_data_services.crc.db import ClusterRepository, QuotaRepository, ResourcePoolRepository
67
from renku_data_services.k8s.clients import DummyPriorityClassClient, DummyResourceQuotaClient
78
from renku_data_services.k8s.db import K8sDbCache
@@ -20,6 +21,7 @@ class DependencyManager:
2021
_k8s_cache: K8sDbCache | None = field(default=None, repr=False, init=False)
2122
_metrics_repo: MetricsRepository | None = field(default=None, repr=False, init=False)
2223
_metrics: StagingMetricsService | None = field(default=None, repr=False, init=False)
24+
_authz: Authz | None = field(default=None, repr=False, init=False)
2325
_rp_repo: ResourcePoolRepository | None = field(default=None, repr=False, init=False)
2426
_cluster_repo: ClusterRepository | None = field(default=None, repr=False, init=False)
2527

@@ -35,11 +37,17 @@ def metrics(self) -> StagingMetricsService:
3537
self._metrics = StagingMetricsService(enabled=self.config.metrics.enabled, metrics_repo=self.metrics_repo())
3638
return self._metrics
3739

40+
def authz(self) -> Authz:
41+
"""The authorization service."""
42+
if not self._authz:
43+
self._authz = Authz(authz_config=self.config.authz)
44+
return self._authz
45+
3846
def rp_repo(self) -> ResourcePoolRepository:
3947
"""The resource pool repository."""
4048
if not self._rp_repo:
4149
self._rp_repo = ResourcePoolRepository(
42-
session_maker=self.config.db.async_session_maker, quotas_repo=self.quota_repo()
50+
session_maker=self.config.db.async_session_maker, quotas_repo=self.quota_repo(), authz=self.authz()
4351
)
4452
return self._rp_repo
4553

0 commit comments

Comments
 (0)