feat(authz): introduce conditional access control via CEL#4040
feat(authz): introduce conditional access control via CEL#4040matheuscscp wants to merge 1 commit intoproject-zot:mainfrom
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #4040 +/- ##
==========================================
+ Coverage 91.66% 91.68% +0.02%
==========================================
Files 199 199
Lines 28602 28828 +226
==========================================
+ Hits 26217 26432 +215
- Misses 1535 1540 +5
- Partials 850 856 +6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
98d31e3 to
8e79bdb
Compare
andaaron
left a comment
There was a problem hiding this comment.
This is a very interesting proposal.
There was a problem hiding this comment.
Pull request overview
This PR adds conditional access control to Zot’s accessControl policies by introducing CEL-based conditions that must evaluate to true for a policy entry to grant access, with request/user/TLS/network/claims context exposed via a req input object.
Changes:
- Extend access-control policy model to include
conditions(CEL expressions + operator message) and compile them at config-load/startup/hot-reload time. - Evaluate policy conditions during authorization and surface an operator-provided deny reason in 403 responses when a condition explicitly evaluates to false.
- Expose authn-time attributes (OIDC token claims) to authz-time conditions via
req.claims, and document the new feature with examples.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/requestcontext/user_access_control.go | Adds claim storage on request context and makes glob-pattern storage more robust to setter ordering. |
| pkg/common/http_server.go | Adds AuthzFailWithReason to include a deny reason in DENIED error details. |
| pkg/cli/server/root.go | Validates config by compiling access-control policy conditions at load time. |
| pkg/cli/server/root_test.go | Adds config-load tests ensuring policy conditions decode and invalid CEL fails load. |
| pkg/cel/expression.go | Adds option to declare map<string, dyn> CEL variables for richer runtime typing. |
| pkg/cel/claim_processor.go | Carries raw OIDC claim set through claim processing for later authz use. |
| pkg/api/controller.go | Stores compiled condition programs in the controller and refreshes them on hot reload. |
| pkg/api/config/config.go | Extends access-control policy schema with Conditions and documents the req.* inputs. |
| pkg/api/authz.go | Implements condition compilation, lookup, evaluation, and deny-reason propagation; wires middleware to use it. |
| pkg/api/authz_internal_test.go | Adds focused unit tests covering condition semantics, request-field exposure, and reload recompilation. |
| pkg/api/authn.go | Plumbs OIDC bearer auth results (including claims) into request context and updates AccessController construction. |
| examples/README.md | Documents conditional policy configuration, available req.* fields, and deny-message behavior. |
| examples/config-policy.json | Adds an example conditions configuration under a repository policy. |
| errors/errors.go | Adds ErrPolicyConditionNotCompiled for fail-closed lookups. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1a92bbe to
92ecdc0
Compare
|
#4045 |
92ecdc0 to
5ee9f1f
Compare
|
Done 🙏 |
|
Just pushed a commit to attempt fixing the binary size increase 🙏 |
7984dbd to
cc4d996
Compare
|
Looks like the binary size increase issue is now fixed, only the bats flake failed this time, can you pls retrigger it? 🙏 https://github.com/project-zot/zot/actions/runs/25569525149/job/75061677582?pr=4040 |
|
Just a note that we are really betting that CEL is safe and not subject to CEL-injection attacks etc. "expression": "req.time < timestamp("2099-12-31T23:59:59Z")", |
|
@matheuscscp pls also take a look at copilot reviews. |
Yeah it's pretty hermetic, we use it in Flux in at least 3 different features and controllers, they run on very privileged Flux controller pods in Kubernetes. The Kubernetes API Server also runs CEL for several built-in features, including CRD custom validation and the ValidatingAdmissionPolicy API. These were probably influenced from Google Cloud IAM security features. CEL is often used for security features, you can see by the influence chain.
👍 Looking right now |
A few outstanding and they look relevant. Will wait for those to be addressed. Otherwise lgtm. |
👍 I'm fixing one and replying to the other. I also replied to the first one earlier. |
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
cc4d996 to
bd53acb
Compare
|
Hey @andaaron sorry, I think I may have mislclicked something here:
@rchincha @andaaron All copilot comments addressed. Among the last two, one was repeated from the first three (the one I implemented). For the other two comments from the first batch and the other one from the second batch I just replied, they are not applicable. Pls approve CI 🙏 |
|
|
|
| /v2/_catalog may over-list repositories This is worrisome. Also, does this happen if there is no CEL in the config? |
|
Note on /v2/_catalog with conditional policies:
Result: _catalog may over-list repositories that will later be denied by conditions (i.e., potential repo-name disclosure depending on how conditions are used). WRT Authz depending on runtime CEL evaluation - this is true, but it is a decision of the server admin, if he wants to use this feature, he needs to properly test the expressions he configures. |
I had long discussions about this with Opus 4.7, and Copilot posted two comments about it. I think the option I chose is the best trade off considering UX, performance, implementation complexity and security. See the summary from Opus 4.7 below. Essentially, users will only see repos but will not have access to them. This is much better than not seeing repos they do have access to. (Exactly what Andrei posted above!)
Not at all. This is only a thing when using conditions. The current behavior is 100% unchanged and conditions are 100% optional! Again, no need to worry about CEL, they are safe and designed for security features like this by Google! Google, Kubernetes and Flux deeply trust CEL for features like this. Summary from Opus 4.7 about the discussion.
|

Closes: #4039
Supersedes: #4036