Skip to content

feat: add dynamic authorization using CEL in AccessPolicy#241

Merged
k8s-ci-robot merged 9 commits into
kubernetes-sigs:mainfrom
abhipatnala:add_dynamic_auth_feature
May 8, 2026
Merged

feat: add dynamic authorization using CEL in AccessPolicy#241
k8s-ci-robot merged 9 commits into
kubernetes-sigs:mainfrom
abhipatnala:add_dynamic_auth_feature

Conversation

@abhipatnala
Copy link
Copy Markdown
Contributor

@abhipatnala abhipatnala commented Apr 17, 2026

What type of PR is this?
/kind feature
What this PR does / why we need it:
This PR introduces CEL-based dynamic authorization for XAccessPolicy. To ensure security and compatibility with Envoy, the controller enforces a strict allowlist of supported CEL variables.

Currently supported variables:

Custom MCP Variables:
request.mcp.tool_name (e.g., request.mcp.tool_name == 'get_weather' or request.mcp.tool_name.startsWith('read_'))
Standard Envoy HTTP Attributes:
request.path
request.url_path
request.method
request.host
request.headers
request.time

How it Works (Validation & Translation)
To provide a seamless developer experience while maintaining strict security, this implementation uses a highly optimized, single-pass compilation architecture:

Validation (Fail-Fast): During reconciliation, the controller parses the user's raw CEL string and extracts all request.* identifier chains. It strictly checks these against the allowlist above. If a user attempts to use an unsupported variable (e.g., request.unrecognized), the controller immediately rejects the policy with a clear error in the XAccessPolicy status.

Translation: Valid custom variables (specifically request.mcp.tool_name) undergo a macro replacement. The controller translates them into the underlying Envoy-native metadata path (metadata.filter_metadata['mcp_proxy'].params.name) populated by our upstream WASM filter. Standard attributes (like request.path) are passed through untouched.

Native Envoy Enforcement: The translated expression is compiled into a CEL Abstract Syntax Tree (AST) using a loosely-typed map environment. This perfectly matches the SelectExpr structure Envoy expects. The AST is injected into the proxy via xDS, allowing Envoy's native RBAC engine to evaluate the complex conditions at runtime.

Which issue(s) this PR fixes:
Fixes #52
Does this PR introduce a user-facing change?:
Yes

Added support for dynamic authorization in `AccessPolicy` using CEL (Common Expression Language) expressions. Users can now define fine-grained rules to restrict tool access based on request attributes (e.g., `request.mcp.tool_name.startsWith('verify_')`).

@k8s-ci-robot k8s-ci-robot added the kind/feature Categorizes issue or PR as related to a new feature. label Apr 17, 2026
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Apr 17, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 17, 2026

Deploy Preview for kube-agentic-networking ready!

Name Link
🔨 Latest commit beb5b4f
🔍 Latest deploy log https://app.netlify.com/projects/kube-agentic-networking/deploys/69fe52497658600008bd7cb1
😎 Deploy Preview https://deploy-preview-241--kube-agentic-networking.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@k8s-ci-robot
Copy link
Copy Markdown
Contributor

Welcome @abhipatnala!

It looks like this is your first PR to kubernetes-sigs/kube-agentic-networking 🎉. Please refer to our pull request process documentation to help your PR have a smooth ride to approval.

You will be prompted by a bot to use commands during the review process. Do not be afraid to follow the prompts! It is okay to experiment. Here is the bot commands documentation.

You can also check if kubernetes-sigs/kube-agentic-networking has its own contribution guidelines.

You may want to refer to our testing guide if you run into trouble with your tests not passing.

If you are having difficulty getting your pull request seen, please follow the recommended escalation practices. Also, for tips and tricks in the contribution process you may want to read the Kubernetes contributor cheat sheet. We want to make sure your contribution gets all the attention it needs!

Thank you, and welcome to Kubernetes. 😃

@k8s-ci-robot k8s-ci-robot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Apr 17, 2026
@k8s-ci-robot
Copy link
Copy Markdown
Contributor

Hi @abhipatnala. Thanks for your PR.

I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work.

Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Apr 17, 2026
@haiyanmeng
Copy link
Copy Markdown
Contributor

CLA Missing ID CLA Not Signed

@abhipatnala , Can you fix this?

@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch from 4d167a1 to 972a554 Compare April 17, 2026 02:42
@k8s-ci-robot k8s-ci-robot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Apr 17, 2026
@guicassolato
Copy link
Copy Markdown
Contributor

@abhipatnala

This is a great and promising start.

Do you have specific instructions for one who wants to try this PR?

Comment thread pkg/translator/accesspolicy.go Outdated
case agenticv0alpha0.AuthorizationRuleTypeCEL:
if rule.Authorization.CEL != nil {
env, err := cel.NewEnv(
cel.Variable("request", cel.MapType(cel.StringType, cel.AnyType)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess without defining an identity (or principal) variable as well, users can use rules.source to condition a particular CEL expression based on exact matching properties of the identity – to the extent of what source supports today (a SPIFFE ID, a Service Account name/namespace). Was that the thinking?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guicassolato I thought we use source field in yaml for identity matching and CEL for dynamic payload matching. Exposing identity directly in CEL is a great idea for a follow-up.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a follow up issue @abhipatnala ?

Comment thread pkg/translator/accesspolicy.go Outdated
Comment thread pkg/translator/accesspolicy.go Outdated
}
ast, issues := env.Compile(rule.Authorization.CEL.Expression)
if issues != nil && issues.Err() != nil {
klog.Errorf("Failed to compile CEL expression %q: %v", rule.Authorization.CEL.Expression, issues.Err())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update the status of the XAccessPolicy resource to reflect this failure.

cc @guicassolato We should merge #236 before this PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abhipatnala ended up validating the CEL expression in pkg/controller. So we no longer need to merge #236 before this PR.

Comment thread pkg/translator/accesspolicy.go Outdated
@haiyanmeng
Copy link
Copy Markdown
Contributor

Please extend https://github.com/kubernetes-sigs/kube-agentic-networking/tree/main/tests/crd for this PR

@haiyanmeng
Copy link
Copy Markdown
Contributor

Please extend https://github.com/kubernetes-sigs/kube-agentic-networking/tree/main/tests/cel for this PR

@haiyanmeng
Copy link
Copy Markdown
Contributor

/ok-to-test

@k8s-ci-robot k8s-ci-robot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Apr 20, 2026
@haiyanmeng
Copy link
Copy Markdown
Contributor

Please add e2e test coverage into https://github.com/kubernetes-sigs/kube-agentic-networking/tree/main/tests/e2e

@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Apr 26, 2026
@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch 5 times, most recently from 9537973 to bc87664 Compare April 26, 2026 06:09
…ching

- Move `celEnv`, `GetCelEnv` and `CompileCelExpression` from `accesspolicy.go` to a new file `cel.go` within the `translator` package to clean up code organization.
- Implement a thread-safe `sync.RWMutex` cache for compiled `cel.Ast` expressions to avoid duplicate compilation overhead between the controller validation and Envoy filter rendering.
- Add comprehensive unit test coverage in `cel_test.go` verifying singleton initialization, macro expansion (`request.mcp.tool_name`), syntax errors, and concurrent safety.
@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch 3 times, most recently from 4a47649 to dfe0d54 Compare May 8, 2026 18:08
Copy link
Copy Markdown
Member

@LiorLieberman LiorLieberman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating the description. one last request.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get another e2e test(s) that demostrate startsWith and/or other CEL expressions?

@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch from dfe0d54 to 7241db9 Compare May 8, 2026 20:40
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels May 8, 2026
@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch from 7241db9 to dbb9107 Compare May 8, 2026 21:01
@LiorLieberman
Copy link
Copy Markdown
Member

Thanks @abhipatnala !
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 8, 2026
@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: abhipatnala, LiorLieberman

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 8, 2026
- Update k8s/crds/agentic.networking.x-k8s.io_xaccesspolicies.yaml manifest via make generate.
- Fix gofumpt trailing blank newlines at EOF in accesspolicy.go and cel_test.go.
- Synchronize API group version and target refs to 'agentic.networking.x-k8s.io' in five new YAML test data manifests to fix E2E and CRD validation pre-submits.
- Extend E2E tests to verify native Envoy CEL variables (method, path, headers) are correctly enforced alongside custom macros.
@abhipatnala abhipatnala force-pushed the add_dynamic_auth_feature branch from dbb9107 to beb5b4f Compare May 8, 2026 21:14
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 8, 2026
@LiorLieberman
Copy link
Copy Markdown
Member

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label May 8, 2026
@k8s-ci-robot k8s-ci-robot merged commit b48e458 into kubernetes-sigs:main May 8, 2026
10 checks passed
@LiorLieberman LiorLieberman mentioned this pull request May 12, 2026
Comment thread pkg/translator/cel.go
)

const (
celVarRequestMCPToolName = "request.mcp.tool_name"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this conflict with existing CEL dictionaries that have different meaning. I suggest the following naming to help disambiguate.

mcp.request.method
mcp.request.tool_name (valid if mcp.request.method == tools/call)

http.request.authority
http.request.method
http.request.path (without query)
http.request.query
http.request.headers (we will need to disambiguate how multivalue headers are handled, since this is a security sensitive issue).

Comment thread pkg/translator/cel.go
Comment on lines +95 to +101
// 1. Validate variables in the original expression to ensure they are on the allowlist
matches := variableRegex.FindAllString(expression, -1)
for _, match := range matches {
if !isValidVariable(match) {
return nil, fmt.Errorf("unsupported CEL variable: %s", match)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about enforcing this validation in the control plane.

Because request was defined as a cel.Map, the validation would block perfectly valid expressions such as request["path"], to favour only the syntactically sugary version request.path. This will obviously limit more advanced use cases such as request[request.headers["x-dyn-property"]].

The validation also blocks macros on the request map such as request.all(…), request.exists(…), etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CEL authz type

7 participants