Allow AccessPolicy to Target Gateway Objects¶
Currently, the AccessPolicy resource is only allowed to target Backends.
This has scalability issues when a given Tool Authorization policy needs to be enforced for all the traffic managed by a Gateway object.
This proposal allows AccessPolicy to target Gateway objects, in addition to Backend objects with the following rules and restrictions:
Restrictions and Evaluation Order¶
Restrictions¶
- Mutually Exclusive Targets: A single
AccessPolicyobject targeting a Gateway and a Backend at the same time is NOT allowed.
Coexistence and Evaluation Flow¶
It is allowed to have AccessPolicy objects targeting a Gateway object and AccessPolicy objects targeting a Backend object behind the Gateway object. The evaluation follows a strict hierarchy:
1. Gateway-Level Evaluation (First)¶
The AccessPolicy objects targeting the Gateway object are evaluated first.
- ExternalAuth-type Rules:
- Evaluated first.
- If any ExternalAuth rule matching the request returns
deny, the request is denied immediately.
- InlineTools-type Rules:
- Evaluated only if all ExternalAuth rules (if any) allowed the request.
- If there are no InlineTools rules matching the request, proceed to Backend-level evaluation.
- If any InlineTools rule matching the request exists and allows it, proceed to Backend-level evaluation.
- Otherwise, the request is denied immediately.
If the request is denied at the gateway level, evaluation stops, and Backend-level policies are NOT evaluated.
2. Backend-Level Evaluation (Second)¶
If the request is allowed at the gateway level, the AccessPolicy objects targeting the Backend object are evaluated using the same logic:
- ExternalAuth-type Rules:
- Evaluated first.
- If any ExternalAuth rule matching the request returns
deny, the request is denied immediately.
- InlineTools-type Rules:
- Evaluated only if all ExternalAuth rules (if any) allowed the request.
- If there are no InlineTools rules matching the request, the request is allowed.
- If any InlineTools rule matching the request exists and allows it, the request is allowed.
- Otherwise, the request is denied.
Summary Table¶
The following table summarizes the evaluation results for different combinations of policy checks. Note that evaluation short-circuits as soon as a definitive Deny or Allow is reached.
| Gateway ExternalAuth | Gateway InlineTools | Backend ExternalAuth | Backend InlineTools | Final Result |
|---|---|---|---|---|
| Deny (Any denies) | - | - | - | Deny |
| Allow (All allow) | Deny (none allows) | - | - | Deny |
| Allow (All allow) | Allow (At least one allows) | Deny (Any denies) | - | Deny |
| Allow (All allow) | Allow (At least one allows) | Allow (All allow) | Deny (none allows) | Deny |
| Allow (All allow) | Allow (At least one allows) | Allow (All allow) | Allow (At least one allows) | Allow |
Example¶
Consider the following setup:
We have a Gateway, an HTTPRoute and a Backend:
- Gateway:
prod-gateway - HTTPRoute:
payment-route(attached toprod-gateway, routes topayment-service) - Backend:
payment-service
We also have the following AccessPolicies applied:
gateway-policy-external-auth-1(Targetsprod-gateway).gateway-policy-external-auth-2(Targetsprod-gateway).gateway-policy-inline-tools-1(Targetsprod-gateway).gateway-policy-inline-tools-2(Targetsprod-gateway).backend-policy-external-auth-1(Targetspayment-service).backend-policy-external-auth-2(Targetspayment-service).backend-policy-inline-tools-1(Targetspayment-service).backend-policy-inline-tools-2(Targetspayment-service).
The graph shows the relationships between these resources:
graph TD
%% 1. Policies at the Top
subgraph PolicyLayer [Gateway-Level Policy Attachments]
direction LR
GPA1(AccessPolicy: gateway-policy-external-auth-1)
GPA2(AccessPolicy: gateway-policy-external-auth-2)
GPR1(AccessPolicy: gateway-policy-inline-tools-1)
GPR2(AccessPolicy: gateway-policy-inline-tools-2)
end
%% 2. Infrastructure & Routing on the same line
%% We define the order here: Gateway <-> Route <-> Backend
GW(Gateway: prod-gateway)
Route(HTTPRoute: payment-route)
BE(Backend: payment-service)
%% Invisible links to force horizontal alignment
GW ~~~ Route ~~~ BE
%% 3. Vertical Arrows (Policies pointing DOWN)
GPA1 -. "TargetRefs" .-> GW
GPA2 -. "TargetRefs" .-> GW
GPR1 -. "TargetRefs" .-> GW
GPR2 -. "TargetRefs" .-> GW
%% 4. Horizontal Arrows (Routing logic)
Route -- "ParentRefs" --> GW
Route -- "BackendRefs" --> BE
%% 5. Backend Policy at the Bottom
subgraph BackendPolicyLayer [Backend-Level Policy Attachments]
direction LR
BPA1(AccessPolicy: backend-policy-external-auth-1)
BPA2(AccessPolicy: backend-policy-external-auth-2)
BPI1(AccessPolicy: backend-policy-inline-tools-1)
BPI2(AccessPolicy: backend-policy-inline-tools-2)
end
%% Target arrows
BPA1 -. "TargetRefs" .-> BE
BPA2 -. "TargetRefs" .-> BE
BPI1 -. "TargetRefs" .-> BE
BPI2 -. "TargetRefs" .-> BE
%% Force BackendPolicyLayer below BE
BE ~~~ BPA1
BE ~~~ BPA2
BE ~~~ BPI1
BE ~~~ BPI2
%% --- STYLING ---
classDef infra fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
classDef routing fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
classDef policy fill:#fff3e0,stroke:#ef6c00,stroke-width:2px,stroke-dasharray: 5 5;
class GW,BE infra;
class Route routing;
class GPA1,GPR1,GPA2,GPR2,BPA1,BPA2,BPI1,BPI2 policy;
style PolicyLayer fill:none,stroke:#ccc,stroke-dasharray: 5 5;
style BackendPolicyLayer fill:none,stroke:#ccc,stroke-dasharray: 5 5;
Evaluation Flow¶
When a request comes to payment-service through prod-gateway:
1. Gateway Level Checks¶
- ExternalAuth Policies:
gateway-policy-external-auth-1andgateway-policy-external-auth-2are evaluated.- If any denies, the request is rejected immediately.
- If all allow, proceed.
- Note: Evaluation order among these policies does not matter.
- InlineTools Policies:
gateway-policy-inline-tools-1andgateway-policy-inline-tools-2are evaluated.- If any allows, proceed to Backend level.
- If none allows, the request is rejected immediately.
- Note: Evaluation order among these policies does not matter.
2. Backend Level Checks¶
- ExternalAuth Policies:
backend-policy-external-auth-1andbackend-policy-external-auth-2are evaluated.- If any denies, the request is rejected immediately.
- If all allow, proceed.
- Note: Evaluation order among these policies does not matter.
- InlineTools Policies:
backend-policy-inline-tools-1andbackend-policy-inline-tools-2are evaluated.- If any allows, the request is allowed.
- If none allows, the request is denied.
- Note: Evaluation order among these policies does not matter.
API Changes¶
We will use +kubebuilder:validation:XValidation:rule markers to make sure that:
- A
targetRefmust be eitherGatewayorBackend. - All targetRefs must have the same kind.
// AccessPolicySpec defines the desired state of AccessPolicy.
type AccessPolicySpec struct {
// TargetRefs specifies the targets of the AccessPolicy.
// An AccessPolicy must target at least one resource.
// +required
// +kubebuilder:validation:MinItems=1
// +listType=atomic
// +kubebuilder:validation:XValidation:rule="self.all(x, (x.group == 'agentic.prototype.x-k8s.io' && x.kind == 'XBackend') || (x.group == 'gateway.networking.k8s.io' && x.kind == 'Gateway'))",message="TargetRef must have group agentic.prototype.x-k8s.io and kind XBackend, or group gateway.networking.k8s.io and kind Gateway"
// +kubebuilder:validation:XValidation:rule="self.all(ref, ref.kind == self[0].kind)",message="All targetRefs must have the same Kind"
TargetRefs []gwapiv1.LocalPolicyTargetReference `json:"targetRefs"`
}
In addition, to make it easy for users to understand why a tool access is allowed or denied, we will disallow the combination of InlineTools and ExternalAuth in the same AccessPolicy.
Currently, the InlineTools type of AuthorizationRule supports a list of tool names, which works well for AccessPolicy targeting Backend objects. However, it does not work well for AccessPolicy targeting Gateway objects, because there could be tool name conflicts between different backends behind the same Gateway. We will address this in a separate proposal.
Support requirements in implementation¶
-
An implementation MUST support at least one of the following:
AccessPolicyobjects targetingGatewayobjectsAccessPolicyobjects targetingBackendobjects
-
If an implementation supports allowing
AccessPolicyto target bothGatewayandBackendobjects, it MUST support the evaluation flow described above.
Future Considerations: Support for DENY Policies¶
In the future, if AccessPolicy is extended to support explicit DENY policies (in addition to the current ExternalAuth and InlineTools mechanisms), the evaluation order should follow the following pattern to ensure safe defaults:
- ExternalAuth Policies: Evaluated first. If any
ExternalAuthpolicy matching the request exists and denies it, the request is denied immediately. - DENY Policies: Evaluated second. If any
DENYpolicy matching the request exists, the request is denied immediately. - InlineTools Policies: Evaluated last. If any
InlineToolspolicy matching the request exists and allows it, the request is allowed. Otherwise, the request is denied by default.
This ensures that explicit denials take precedence over allows, and external authorization has the first say.
Summary Table¶
The following table summarizes the evaluation results for different combinations of policy checks including future DENY policies. Note that evaluation short-circuits as soon as a definitive Deny or Allow is reached.
| Gateway ExternalAuth | Gateway DENY | Gateway InlineTools | Backend ExternalAuth | Backend DENY | Backend InlineTools | Final Result |
|---|---|---|---|---|---|---|
| Deny (Any denies) | - | - | - | - | - | Deny |
| Allow (All allow) | Deny (Any matches) | - | - | - | - | Deny |
| Allow (All allow) | Allow (No matches) | Deny (All deny) | - | - | - | Deny |
| Allow (All allow) | Allow (No matches) | Allow (At least one allows) | Deny (Any denies) | - | - | Deny |
| Allow (All allow) | Allow (No matches) | Allow (At least one allows) | Allow (All allow) | Deny (Any matches) | - | Deny |
| Allow (All allow) | Allow (No matches) | Allow (At least one allows) | Allow (All allow) | Allow (No matches) | Deny (All deny) | Deny |
| Allow (All allow) | Allow (No matches) | Allow (At least one allows) | Allow (All allow) | Allow (No matches) | Allow (At least one allows) | Allow |
Prior Art¶
Istio Authorization Policy¶
Istio Authorization Policy supports CUSTOM, DENY and ALLOW actions for access control. When CUSTOM, DENY and ALLOW actions are used for a workload at the same time, the CUSTOM action is evaluated first, then the DENY action, and finally the ALLOW action. The evaluation is determined by the following rules:
- If there are any CUSTOM policies that match the request, evaluate and deny the request if the evaluation result is deny.
- If there are any DENY policies that match the request, deny the request.
- If there are no ALLOW policies for the workload, allow the request.
- If any of the ALLOW policies match the request, allow the request.
- Deny the request.
Envoy Gateway Security Policy¶
Envoy Gateway Security Policy supports external authorization and internal authorization. When both are configured, the evaluation is determined by the following rules:
- If the external authorization rule denies the request, deny the request. If the external authorization rule allows the request, proceed to the next evaluation phase.
- The internal authorization rules are checked from top to bottom as they appear in the
SecurityPolicyresource. The first rule that matches the request is applied, and all subsequent rules are ignored. - If no intenral authorization rules match, the gateway applies the
defaultAction(which isDenyby default).
The Precedence Hierarchy¶
When multiple SecurityPolicy resources apply to the same request, Envoy Gateway determines which one takes effect based on where they are attached:
| Level | Target Resource | Precedence |
|---|---|---|
| Highest | Route Rule (via sectionName) |
1 (Wins all) |
| High | HTTPRoute / GRPCRoute |
2 |
| Medium | Gateway Listener (via sectionName) |
3 |
| Lowest | Gateway (Entire resource) |
4 |
Handling Conflicts (Same Level)¶
If two different SecurityPolicy objects target the exact same resource (e.g., two policies both targeting HTTPRoute: my-service), Envoy Gateway uses "Tie-breaking" rules:
-
Oldest Wins: The policy with the earliest
creationTimestampis applied. -
Alphabetical Sorting: If the timestamps are identical, the policy whose name comes first alphabetically wins.
-
Status Reporting: The "losing" policies will show a status of Overridden=True or Conflicted=True in their Kubernetes status field.
Linkerd Authorization Policy¶
Linkerd Authorization Policy evaluation follows a "Specific-to-General" hierarchy that centers around the concept of a Server resource.
Linkerd's proxy makes an authorization decision for every incoming request using these checks in order:
-
Check for a
Serverresource:-
NO
Serverexists: The proxy uses the Default Policy (see below). -
YES
Serverexists: Proceed to step 2.
-
-
Check for an
HTTPRoute:-
If the request matches a defined
HTTPRoute(e.g., a specific path like/admin), onlyAuthorizationPolicytargeting that specific route are checked. -
If no
HTTPRoutematches (or none are defined), Linkerd checks policies targeting theServeritself.
-
-
Final Verdict:
-
If any matching policy allows the request: ALLOW.
-
If no policies match or the client fails authentication: DENY (HTTP 403 for HTTP traffic, or TCP connection refusal).
-
When no Server resource is defined for a port, Linkerd looks at the config.linkerd.io/default-inbound-policy annotation (checked from Pod → Namespace → Cluster level).
Multi-Policy Interaction (AND vs. OR)¶
One of the most important rules is how Linkerd handles multiple authentication requirements:
-
OR (Between Policies): If you have two different AuthorizationPolicy objects targeting the same Server, the request is allowed if either one is satisfied.
-
AND (Within a Policy): If a single AuthorizationPolicy has multiple entries in its requiredAuthenticationRefs list, the client must satisfy all of them (e.g., must have a specific Identity AND come from a specific IP range).