Skip to content

feat: Support for Gateway-level Access Policies and Multi-level Enforcement#127

Open
chuangw6 wants to merge 3 commits intokubernetes-sigs:mainfrom
chuangw6:gw-ap
Open

feat: Support for Gateway-level Access Policies and Multi-level Enforcement#127
chuangw6 wants to merge 3 commits intokubernetes-sigs:mainfrom
chuangw6:gw-ap

Conversation

@chuangw6
Copy link
Contributor

@chuangw6 chuangw6 commented Mar 2, 2026

What type of PR is this?

/kind feature

What this PR does / why we need it:

This PR implements support for AccessPolicy resources targeting
Gateway objects, enabling global policy enforcement alongside specific Backend
policies. It introduces a hierarchical evaluation model where requests are
validated at both the Gateway (entry) and Backend (service) levels.

Key changes:

  • API: Allow 'Gateway' as a valid TargetRef in XAccessPolicy with cross-kind
    validation rules.
  • Controller:
    • Added logic to re-enqueue Gateways directly targeted by AccessPolicies,
      as well as all root Gateways of XBackends targeted by AccessPolicies.
    • Implement seniority-based policy acceptance (limit 5 policies per target).
    • Accepted policies are reflected in the resource status via PolicyAncestorStatus.
  • Translator:
    • Gateway-level policies are translated into top-level Envoy HTTP RBAC
      filters.
    • Backend-level policies use Envoy's 'TypedPerFilterConfig' to override
      placeholder filters at the cluster level.
    • Enforced correct filter ordering: MCP -> Gateway RBAC -> Backend RBAC
      -> Router.
  • E2E: Added a multi-level test case verifying that a request must satisfy
    both Gateway and Backend policies, and that policies fallback correctly
    when modified or deleted.
    • No policy (allow all)
    • Backend-only policy
    • Gateway-only policy
    • Multi-level denial (sequential AND logic)
    • Multi-level allow after patching

Which issue(s) this PR fixes:

Fixes #55

Does this PR introduce a user-facing change?:

Support for Gateway-level Access Policies and Multi-level Enforcement

Users can now apply `XAccessPolicy` resources directly to a `Gateway`. This allows for global authorization rules that apply to all traffic entering the Gateway.

**Key Features for Users:**
*   **Gateway Targeting:** `XAccessPolicy` now accepts `Gateway` (gateway.networking.k8s.io) as a valid `targetRef`.
*   **Hierarchical Enforcement:** When both Gateway and Backend policies exist, they are enforced sequentially. A request must be authorized by both levels to succeed.
*   **Improved Status Visibility:** Policy acceptance status and troubleshooting information (e.g., missing targets) are now correctly reflected in the `XAccessPolicy` status field using standard Gateway API conditions.
*   **Seniority-based Acceptance:** Up to 5 policies can be applied per target, prioritized by creation timestamp.

@k8s-ci-robot k8s-ci-robot added the kind/feature Categorizes issue or PR as related to a new feature. label Mar 2, 2026
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: chuangw6
Once this PR has been reviewed and has the lgtm label, please assign david-martin for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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 cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Mar 2, 2026
@k8s-ci-robot
Copy link
Contributor

Hi @chuangw6. 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.

Tip

We noticed you've done this a few times! Consider joining the org to skip this step and gain /lgtm and other bot rights. We recommend asking approvers on your previous PRs to sponsor you.

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 the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Mar 2, 2026
@netlify
Copy link

netlify bot commented Mar 2, 2026

Deploy Preview for kube-agentic-networking ready!

Name Link
🔨 Latest commit f9347c4
🔍 Latest deploy log https://app.netlify.com/projects/kube-agentic-networking/deploys/69b1db1521461e000810148a
😎 Deploy Preview https://deploy-preview-127--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.

@haiyanmeng
Copy link
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 Mar 2, 2026
@chuangw6 chuangw6 force-pushed the gw-ap branch 3 times, most recently from 3f84403 to e9161f2 Compare March 2, 2026 19:34
@chuangw6 chuangw6 changed the title Support for Gateway-level Access Policies and Multi-level Enforcement feat: Support for Gateway-level Access Policies and Multi-level Enforcement Mar 2, 2026
@haiyanmeng
Copy link
Contributor

/cc @guicassolato
/cc @david-martin

@guicassolato
Copy link
Contributor

Lots of conflicts with #83 😞

@haiyanmeng
Copy link
Contributor

Lots of conflicts with #83 😞

@guicassolato , can you elaborate more regarding the conflicts? Are the conflicts reconcilable?

@guicassolato
Copy link
Contributor

Lots of conflicts with #83 😞

@guicassolato , can you elaborate more regarding the conflicts? Are the conflicts reconcilable?

They sure can be reconciled. It's just a lot of rework due to both PRs touching the same sections in parallel, somewhat heavily. We could probably have coordinated these two changes better IMO.

@haiyanmeng
Copy link
Contributor

Lots of conflicts with #83 😞

@guicassolato , can you elaborate more regarding the conflicts? Are the conflicts reconcilable?

They sure can be reconciled. It's just a lot of rework due to both PRs touching the same sections in parallel, somewhat heavily. We could probably have coordinated these two changes better IMO.

Thanks for the explanation. If the conflicts can be reconciled, we should merge #83 first. Then we can work with @chuangw6 to make sure this PR still works.

@haiyanmeng
Copy link
Contributor

/hold Let us merge #83 first.

@k8s-ci-robot k8s-ci-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Mar 3, 2026
@chuangw6 chuangw6 force-pushed the gw-ap branch 3 times, most recently from b0cd4e2 to 1cf4699 Compare March 5, 2026 04:14
@chuangw6 chuangw6 force-pushed the gw-ap branch 3 times, most recently from 7288765 to 7f9c627 Compare March 10, 2026 17:32
@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2026
@chuangw6 chuangw6 requested a review from haiyanmeng March 10, 2026 17:36
@haiyanmeng
Copy link
Contributor

Thanks for the great work and multiple rounds of labor-intensive rebase effort, @chuangw6 .

/lgtm

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

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 10, 2026
@chuangw6 chuangw6 requested a review from guicassolato March 10, 2026 19:55
@chuangw6
Copy link
Contributor Author

Thanks for the great work and multiple rounds of labor-intensive rebase effort, @chuangw6 .

/lgtm

Thanks @haiyanmeng.

Regarding the ext auth discussion above, this feels out of scope for the current PR, and seems like a great candidate for a follow-up issue. I'd like to move forward with this PR to avoid further merge conflicts. @guicassolato , does that sound reasonable to you?

Copy link
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 @chuangw6 !

PolicyConditionAccepted gwapiv1.PolicyConditionType = "Accepted"

// PolicyReasonExceededLimit indicates that the policy was rejected because the maximum number of policies per target was exceeded.
PolicyReasonExceededLimit gwapiv1.PolicyConditionReason = "ExceededLimit"
Copy link
Member

Choose a reason for hiding this comment

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

nit: Would something more verbal be better here? I.e PolicyLimitExceeded or PolicyLimitPerTargetExceeded?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to PolicyLimitPerTargetExceeded


// Initial check for policy limit per target.
if !c.isPolicyUnderTargetLimit(context.Background(), policy) {
return
Copy link
Member

Choose a reason for hiding this comment

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

add log?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isPolicyUnderTargetLimit already logs the details

Comment on lines +65 to +69
specChanged := newPolicy.Generation != oldPolicy.Generation || !reflect.DeepEqual(newPolicy.Annotations, oldPolicy.Annotations)
deletionTimestampChanged := newPolicy.DeletionTimestamp != oldPolicy.DeletionTimestamp
acceptanceChanged := newPolicy.IsAccepted() != oldPolicy.IsAccepted()

if specChanged || deletionTimestampChanged || acceptanceChanged {
Copy link
Member

Choose a reason for hiding this comment

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

would highly benefit from a helper function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

acceptanceChanged := newPolicy.IsAccepted() != oldPolicy.IsAccepted()

if specChanged || deletionTimestampChanged || acceptanceChanged {
klog.V(4).InfoS("Updating AccessPolicy", "accesspolicy", klog.KObj(oldPolicy), "specChanged", specChanged, "acceptanceChanged", acceptanceChanged)
Copy link
Member

Choose a reason for hiding this comment

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

this just prints true/false for spec Changed and acceptance Change etc, is this useful?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated, but logging Updating AccessPolicy is still helpful imo to show it's reconciled and align with other onAccessPolicyxxx. lmk otherwise

// If targets changed, we must re-evaluate the limit as it's equivalent to an 'Add' for the new target.
if !reflect.DeepEqual(oldPolicy.Spec.TargetRefs, newPolicy.Spec.TargetRefs) {
if !c.isPolicyUnderTargetLimit(context.Background(), newPolicy) {
return
Copy link
Member

Choose a reason for hiding this comment

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

add log?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isPolicyUnderTargetLimit already logs the details

Comment on lines -77 to -78
// It's deny-by-default (a.k.a ALLOW action), we explicitly allow necessary
// MCP operations for all backends. These policies are essential for MCP
Copy link
Member

Choose a reason for hiding this comment

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

are we allowing or denying traffic by default? (assuming no policy exist)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  • If no policy exists for the target, it's allow-by-default.
  • If a policy exists for the target but tool list is empty, it denies all tool access.

See unit tests.

allAccessPolicies, err := accessPolicyLister.XAccessPolicies(backend.Namespace).List(labels.Everything())
// findAccessPoliciesForTarget finds all AccessPolicies that target the given resource.
// It returns only accepted policies.
func (t *Translator) findAccessPoliciesForTarget(group, kind, namespace, name string) ([]*agenticv0alpha0.XAccessPolicy, error) {
Copy link
Member

Choose a reason for hiding this comment

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

can we change this to work from an index? related to my previous comment about

can be a followup but lets add TODO() for both locations in the code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, added todo and linked to #168

Makefile Outdated
.PHONY: fmt
fmt: ;$(info $(M)...Begin to run go fmt against code.) @ ## Run go fmt against code.
gofmt -w ./pkg
gofmt -w ./api ./cmd ./pkg
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
gofmt -w ./api ./cmd ./pkg
go fmt ./...

Copy link
Member

Choose a reason for hiding this comment

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

go formatting should be done with .golangci.yml -- see https://github.com/kubernetes-sigs/gateway-api/blob/main/.golangci.yml#L99-L109

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to go fmt ./...

our https://github.com/kubernetes-sigs/kube-agentic-networking/blob/main/.golangci.yaml seems to have minimum checks only. It can be a follow up to update it, but it's out of scope for this PR.

Makefile Outdated
.PHONY: vet
vet: ;$(info $(M)...Begin to run go vet against code.) @ ## Run go vet against code.
go vet ./pkg/...
go vet ./api/... ./cmd/... ./pkg/...
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
go vet ./api/... ./cmd/... ./pkg/...
go vet ./...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

# Run go test against code
.PHONY: test
test: vet test-pkg test-cel test-crd ## Run all tests.
test: vet test-unit test-cel test-crd ## Run all tests.
Copy link
Member

Choose a reason for hiding this comment

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

question: why do we need separate tests targets?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd defer the question to @haiyanmeng . They were added in #58

@k8s-ci-robot
Copy link
Contributor

@LiorLieberman: GitHub didn't allow me to request PR reviews from the following users: thing, before, HarshithaMS005, as, she, did, a, similar.

Note that only kubernetes-sigs members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

can we have a todo to have an index of Target --> policies?

/cc @HarshithaMS005 as she did a similar thing before

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 the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2026
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Mar 11, 2026
@k8s-ci-robot
Copy link
Contributor

New changes are detected. LGTM label has been removed.

@k8s-ci-robot k8s-ci-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 11, 2026
Allow 'Gateway' as a valid TargetRef in XAccessPolicy
with cross-kind validation rules.

Signed-off-by: Chuang Wang <chuangw@google.com>
This change implements support for AccessPolicy resources targeting Gateway
objects, enabling global authorization policies across all routes in a
Gateway. It also introduces a multi-level policy evaluation model where
both Gateway-level and Backend-level policies are enforced sequentially.

Key changes:
- Controller: Implement seniority-based policy acceptance (limit 5 policies
  per target by default). Accepted policies are reflected in the resource
  status via PolicyAncestorStatus.
- Translator:
    - Gateway-level policies are translated into top-level Envoy HTTP RBAC
      filters.
    - Backend-level policies use Envoy's 'TypedPerFilterConfig' to override
      placeholder filters at the cluster level.
    - Enforced correct filter ordering: MCP -> Gateway RBAC -> Backend RBAC
      -> Router.

Signed-off-by: Chuang Wang <chuangw@google.com>
@haiyanmeng
Copy link
Contributor

/hold @chuangw6 , Let us work with @guicassolato to close the externalAuth gap in this PR.

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Mar 11, 2026
Signed-off-by: Chuang Wang <chuangw@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. kind/feature Categorizes issue or PR as related to a new feature. 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.

Allow AccessPolicy to target Gateway objects

6 participants