Overview
Access management in the ODJ is implemented with a central authorization service that uses SpiceDB underneath. SpiceDB is an open-source implementation of Google's Zanzibar paper. The main idea behind Zanzibar is to model permissions based on the resources and relations of the application. Relations that are relevant for authorization are replicated to the authorization database (SpiceDB) and kept up-to-date whenever they change in the application.
Request flow
Users have to obtain a token from MyAPI either via the Authorization Code Flow or the Client Credentials Flow (see Authentication Overview).
The ODJ API and the UI are protected with an Envoy sidecar container which validates the token. The token is passed to the
corresponding service either via cookie or Authorization
header. Each service can then parse the JWT and extract the user identity with the sub
claim.
That user identity is then used for authorization checks with the Access Management.
Architecture
The Access Management consists of three components:
- a service called
access-management
(AM) - a SpiceDB cluster managed by the SpiceDB operator (Helm chart, Cluster definition)
- Redis
The Access Management service (AM) guards all access to SpiceDB itself. All other components of the ODJ only talk to the AM, not to SpiceDB directly. This allows us to closely mirror the Architecture Runtime Model (ARM) in the API for the AM and encapsulate the whole permission model in one central place.
Propagating updates
The AM mirrors all the resources and their relationships that are relevant for authorization. If any of these relationships changes, that change needs to be propagated to the AM. In our architecture, this happens via synchronous REST endpoints exposed by the AM. Currently, the following operations need to be synced between the ODJ and the AM:
- User creation/removal (adding them to the global
all
role) - Team creation
- Adding/Updating/Removing team members
- Application creation/deletion
- Registering deployment workers with applications and the global
all
role
These syncs should happen synchronously and in a transactional way. If writing to the access management fails, the transaction in the source service should also be rolled back.
Consistency with ZedTokens
By default, SpiceDB caches subproblems for about 5 seconds. This means that access checks can be up to 5 seconds out of date.
This leads to some problems in read-after-write scenarios such as team or application creation. SpiceDB returns a so-called
ZedToken when relationships are written. ZedTokens are opaque but encode a database revision. By providing a ZedToken
in a CHECK request, we can force SpiceDB to only use the cache if it already contains the latest changes. The AM stores
the latest ZedToken for a resource in Redis. During CHECKs the latest ZedToken is read from Redis and then provided
to SpiceDB with the at_least_as_fresh
consistency level. If no ZedToken is stored for a resource, we fall back
to minimize_latency
, since we are more concerned with latency than with the New Enemy Problem.