From a3d3ad41b9944438401c87bbae5cc69bb3aec311 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Fri, 27 Jun 2025 23:21:37 +0000 Subject: [PATCH 01/15] add api details gep-3779 --- geps/gep-3779/index.md | 253 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 252 insertions(+), 1 deletion(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 49464b16d6..6d69c6e906 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -246,10 +246,261 @@ Cilium has the concept of CiliumIdentity. Pods are assigned identities derived f More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ - ## API +This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (`ALLOW` or `DENY`), and a set of rules that include sources (the “who”) and an optional port attribute. + +### **Policy Rules** + +Each `AuthorizationPolicy` resource contains a list of rules. A request matches the policy if it matches **any** rule in the list (logical OR). Each rule defines multiple matching criteria; a request matches a rule only if it matches **all** criteria within that rule (logical AND). + +A rule may specify: + +* **Sources:** The source identities to which the rule applies. A request’s identity must match one of the listed sources. Supported source kinds are: + * **SPIFFE ID** + * **Kubernetes ServiceAccount** + * **Kubernetes Namespace** +* **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. + +### **ALLOW Policies** + +* An **ALLOW** policy is permissive. +* A request is allowed if: + * It matches at least one rule in any ALLOW policy targeting the workload **and** + * It is not explicitly denied by any DENY policy. +* If no ALLOW policy exists for a workload, traffic is permitted by default, unless any DENY policy applies. + +### **DENY Policies** + +* A **DENY** policy is restrictive and takes precedence over ALLOW. +* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. +* DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). + +### **ALLOW vs. DENY Semantics** + +* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. +* The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. +* Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. + +### **Target of Authorization** + +The `targetRef` of the policy specifies the workload(s) to which the policy applies. Two options are available for `targetRef`: + +#### **Option 1: Targeting a Service** + +The `targetRef` can point to a Kubernetes `Service`. + +**Benefits:** + +* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. +* **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. + +**Downsides and Open Questions:** + +However, targeting a `Service` introduces several challenges: + +1. Authorization cannot be enforced on workloads not exposed via a `Service` - excluding use cases of pods/jobs without a Service. +2. If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. +3. UX and implementation challenges - are implementations expected to enforce the policy only if the traffic arrived through the specific Service? Or just to take the service selectors and enforce the policy regardless of how the traffic got to the destination? + +#### **Option 2: Targeting Pods via Label Selectors** + +Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. + +**Benefits:** + +* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. +* Directly applies policy to pods, avoiding ambiguity present when targeting services. Ensures policies are enforced exactly where intended, regardless of how many services a pod might belong to. +* Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. + +**Downsides and Open Questions:** + +The main downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See below for more info. + +**Requirement: Enhancing Policy Attachment:** + +This option depends on enhancements to Gateway API’s policy attachment model to support `LabelSelector` as a valid `targetRef`. This capability was discussed and received consensus at KubeCon North America 2024 and was originally in scope for GEP-713 but deferred for a future PR to keep GEP-713 focused on stabilizing what we already have (See [https://github.com/kubernetes-sigs/gateway-api/pull/3609#discussion_r2053376938](https://github.com/kubernetes-sigs/gateway-api/pull/3609#discussion_r2053376938)). + +##### **Experimental Pattern** + +To mitigate some of the concerns, `LabelSelector` support in policy attachment is designated as an **experimental pattern**. + +* **Gateway API Community First:** Allows experimentation within Gateway API policies (like the one in this GEP). +* Implementations **should not** adopt `LabelSelector` targeting in their own custom policies attached to Gateway API resources until the pattern is sufficiently battle-tested and promoted to a standard feature. This staged approach mitigates risks of ecosystem fragmentation. + +Here is how it is going to look like: + +```go + +// PolicyTargetReferenceWithLabelSelectors specifies a reference to a set of Kubernetes +// objects by Group and Kind, with an optional label selector to narrow down the matching +// objects. +// +// Currently, we only support label selectors when targeting Pods. +// This restriction is intentional to limit the complexity and potential +// ambiguity of supporting label selectors for arbitrary Kubernetes kinds. +// Unless there is a very strong justification in the future, we plan to keep this +// functionality limited to selecting Pods only. +// +// This is currently experimental in the Gateway API and should only be used +// for policies implemented within Gateway API. It is currently not intended for general-purpose +// use outside of Gateway API resources. +// +kubebuilder:validation:XValidation:rule="!(has(self.selector)) || (self.kind == 'Pod' && (self.group == '' || self.group == 'core'))",message="Selector may only be set when targeting Pods." +type PolicyTargetReferenceWithLabelSelectors struct { + // Group is the group of the target object. + Group Group `json:"group"` + + // Kind is the kind of the target object. + Kind Kind `json:"kind"` + + // Selector is the label selector of target objects of the specified kind. + Selector *metav1.LabelSelector `json:"selector"` +} + +``` + +##### **Enhanced Discoverability with `gwctl`** + +A key challenge with `LabelSelector` is the loss of discoverability. It’s easier to see which policies target a `Service` but difficult to determine which policies might affect a specific pod. + +To address this, **investment in tooling is required.** Specifically, the `gwctl` CLI tool should be enhanced to provide insights such as: + +```sh +TODO: complete gwctl commands +``` + +Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. + +### API Design + +```go + +type AuthorizationPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of AuthorizationPolicy. + Spec AuthorizationPolicySpec `json:"spec,omitempty"` + + // Status defines the current state of AuthorizationPolicy. + Status PolicyStatus `json:"status,omitempty"` +} + +// AuthorizationPolicyAction specifies the action to take. +// +kubebuilder:validation:Enum=ALLOW;DENY +type AuthorizationPolicyAction string + +const ( + // ActionAllow allows requests that match the policy rules. + ActionAllow AuthorizationPolicyAction = "ALLOW" + // ActionDeny denies requests that match the policy rules. + ActionDeny AuthorizationPolicyAction = "DENY" +) + +// AuthorizationPolicySpec defines the desired state of AuthorizationPolicy. +type AuthorizationPolicySpec struct { + // TargetRef identifies the resource this policy is attached to. + // +kubebuilder:validation:Required + TargetRefs gatewayv1.PolicyTargetReferenceWithLabelSelectors `json:"targetRefs"` + + // Action specifies the action to take when a request matches the rules. + // +kubebuilder:validation:Required + Action AuthorizationPolicyAction `json:"action"` + + // TCPRules defines the list of matching criteria. A request is considered to + // match the policy if it matches any of the rules. + // +optional + TCPRules []AuthorizationTCPRule `json:"tcpRules,omitempty"` +} + +// AuthorizationTCPRule defines a set of criteria for matching a TCP request. +// A request must match all specified criteria. +type AuthorizationTCPRule struct { + // Sources specifies a list of identities that are matched by this rule. + // If this field is empty, this rule matches all sources. + // A request matches if its identity is present in this list. + // +optional + Sources []AuthorizationSource `json:"sources,omitempty"` + + // Attributes specifies a list of properties that are matched by this rule. + // If this field is empty, this rule matches all attributes. + // A request matches if its attributes are present in this list. + // + // +optional + Attributes []AuthorizationTCPAttributes `json:"attributes,omitempty"` +} + + +// AuthorizationSource specifies the source of a request. +// Only one of its fields may be set. +// +kubebuilder:validation:XValidation:rule="(size(self.identities) > 0 ? 1 : 0) + (size(self.serviceAccounts) > 0 ? 1 : 0) + (size(self.namespaces) > 0 ? 1 : 0) == 1",message="Exactly one of identities, serviceAccounts, or namespaces must be specified." +type AuthorizationSource struct { + + // Identities specifies a list of identities that are matched by this rule. + // A request's identity must be present in this list to match the rule. + // + // Identities must be specified as SPIFFE-formatted URIs following the pattern: + // spiffe:/// + // + // While the exact workload identifier structure is implementation-specific, + // implementations are encouraged to follow the convention of + // `spiffe:///ns//sa/` + // when representing Kubernetes workload identities. + // + // Identities for authorization can be derived in various ways by the underlying + // implementation. Common methods include: + // - From peer mTLS certificates: The identity is extracted from the client's + // mTLS certificate presented during connection establishment. + // - From IP-to-identity mappings: The implementation might maintain a dynamic + // mapping between source IP addresses (pod IPs) and their associated + // identities (e.g., Service Account, SPIFFE IDs). + // - From JWTs or other request-level authentication tokens. + // + // Note for reviewers: While this GEP primarily focuses on identity-based + // authorization where identity is often established at the transport layer, + // some implementations might derive identity from authenticated tokens or sources + // within the request itself. + // + // +optional + Identities []string `json:"identities,omitempty"` + + // ServiceAccounts specifies a list of Kubernetes Service Accounts that are + // matched by this rule. Each service account must be specified in the format + // "/". A request originating from a pod + // associated with one of these service accounts will match the rule. + // + // The ServiceAccounts listed here are expected to exist within the same + // trust domain as the targeted workload, which in many environments means + // the same Kubernetes cluster. Cross-cluster or cross-trust-domain should + // be expressed with Identities field. + // +optional + ServiceAccounts []string `json:"serviceAccounts,omitempty"` + + // Namespaces specifies a list of Kubernetes Namespaces that are matched + // by this rule. A request originating from any pod within one of these + // namespaces will match the rule, regardless of its specific Service Account. + // This provides a broader scope for authorization. + + // The Namespaces listed here are expected to exist within the same + // trust domain as the targeted workload, which in many environments means + // the same Kubernetes cluster. Cross-cluster or cross-trust-domain should + // be expressed with Identities field. + // +optional + Namespaces []string `json:"namespaces,omitempty"` +} + +// AuthorizationAttribute defines L4 properties of a request destination. +type AuthorizationTCPAttributes struct { + // Ports specifies a list of destination ports to match on. + // Traffic is matched if it is going to any of these ports. + // If not specified, the rule applies to all ports. + // +optional + Ports []gatewayv1.PortNumber `json:"ports,omitempty"` +} + +``` +Note: Existing AuthorizationAPIs recognized the need to support negation fields like `not{field}`. To avoid duplicating fields with negation, we plan to support richer match expressions for fields in `AuthorizationSource` such as `matchExpressions: { operator: In|NotIn, values: []}`. ## Conformance Details From 3b3f6882df01082c8643c54ece93affe43775160 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 2 Jul 2025 20:58:41 +0000 Subject: [PATCH 02/15] fmting --- geps/gep-3779/index.md | 48 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 6d69c6e906..04e1232f04 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -241,7 +241,7 @@ spec: ##### CiliumIdentity -Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. +Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ @@ -256,29 +256,31 @@ Each `AuthorizationPolicy` resource contains a list of rules. A request matches A rule may specify: -* **Sources:** The source identities to which the rule applies. A request’s identity must match one of the listed sources. Supported source kinds are: - * **SPIFFE ID** - * **Kubernetes ServiceAccount** - * **Kubernetes Namespace** -* **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. + * **Sources:** The source identities to which the rule applies. A request’s identity must match one of the listed sources. Supported source kinds are: + * **SPIFFE ID** + * **Kubernetes ServiceAccount** + * **Kubernetes Namespace** + + * **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. ### **ALLOW Policies** -* An **ALLOW** policy is permissive. -* A request is allowed if: - * It matches at least one rule in any ALLOW policy targeting the workload **and** - * It is not explicitly denied by any DENY policy. -* If no ALLOW policy exists for a workload, traffic is permitted by default, unless any DENY policy applies. + * An **ALLOW** policy is permissive. + * A request is allowed if: + * It matches at least one rule in any ALLOW policy targeting the workload **and** + * It is not explicitly denied by any DENY policy. + + * If no ALLOW policy exists for a workload, traffic is permitted by default, unless any DENY policy applies. ### **DENY Policies** -* A **DENY** policy is restrictive and takes precedence over ALLOW. -* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. +* A **DENY** policy is restrictive and takes precedence over ALLOW. +* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. * DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). ### **ALLOW vs. DENY Semantics** -* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. +* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. * The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. * Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. @@ -292,14 +294,14 @@ The `targetRef` can point to a Kubernetes `Service`. **Benefits:** -* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. +* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. * **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. **Downsides and Open Questions:** However, targeting a `Service` introduces several challenges: -1. Authorization cannot be enforced on workloads not exposed via a `Service` - excluding use cases of pods/jobs without a Service. +1. Authorization cannot be enforced on workloads not exposed via a `Service` - excluding use cases of pods/jobs without a Service. 2. If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. 3. UX and implementation challenges - are implementations expected to enforce the policy only if the traffic arrived through the specific Service? Or just to take the service selectors and enforce the policy regardless of how the traffic got to the destination? @@ -309,8 +311,8 @@ Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` **Benefits:** -* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. -* Directly applies policy to pods, avoiding ambiguity present when targeting services. Ensures policies are enforced exactly where intended, regardless of how many services a pod might belong to. +* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. +* Directly applies policy to pods, avoiding ambiguity present when targeting services. Ensures policies are enforced exactly where intended, regardless of how many services a pod might belong to. * Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. **Downsides and Open Questions:** @@ -325,7 +327,7 @@ This option depends on enhancements to Gateway API’s policy attachment model t To mitigate some of the concerns, `LabelSelector` support in policy attachment is designated as an **experimental pattern**. -* **Gateway API Community First:** Allows experimentation within Gateway API policies (like the one in this GEP). +* **Gateway API Community First:** Allows experimentation within Gateway API policies (like the one in this GEP). * Implementations **should not** adopt `LabelSelector` targeting in their own custom policies attached to Gateway API resources until the pattern is sufficiently battle-tested and promoted to a standard feature. This staged approach mitigates risks of ecosystem fragmentation. Here is how it is going to look like: @@ -454,9 +456,9 @@ type AuthorizationSource struct { // - From IP-to-identity mappings: The implementation might maintain a dynamic // mapping between source IP addresses (pod IPs) and their associated // identities (e.g., Service Account, SPIFFE IDs). - // - From JWTs or other request-level authentication tokens. - // - // Note for reviewers: While this GEP primarily focuses on identity-based + // - From JWTs or other request-level authentication tokens. + // + // Note for reviewers: While this GEP primarily focuses on identity-based // authorization where identity is often established at the transport layer, // some implementations might derive identity from authenticated tokens or sources // within the request itself. @@ -508,7 +510,7 @@ Note: Existing AuthorizationAPIs recognized the need to support negation fields #### Feature Names -### Conformance tests +### Conformance tests ## Alternatives From e373fa062ca2f59e2a4c5c8cec6d3b76383f12db Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 8 Jul 2025 22:59:36 +0000 Subject: [PATCH 03/15] some-fixes --- geps/gep-3779/index.md | 64 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 04e1232f04..bc44010eb3 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -292,20 +292,72 @@ The `targetRef` of the policy specifies the workload(s) to which the policy appl The `targetRef` can point to a Kubernetes `Service`. +Two implementation options when targeting a service: + +1. Apply authorization policy to all traffic addressed to this Service. + +1. Apply authorization policy to all workloads (pods) selected by the Service. + **Benefits:** * **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. * **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. **Downsides and Open Questions:** +However, targeting a `Service` introduces several challenges; + +##### Loss Of Service Context + +I we go with option 1, apply authorization policy to all traffic addressed to a service; + This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. + Here is the very high-level tarffic flow for sidecar-based meshes: + + ```sh + Client → Request to backend-service:8080 + → Source sidecar resolves service → backend-pod-1 (>:8080) + → Destination sidecar receives traffic on pod IP + → Destination sidecar has NO context that this came via "backend-service" + ``` + +Solving this problem either introduces security concern (e.g adding request metadata to indicate which service was dialed), or unnecessarily complex or in-efficient to solve. + +#### A Workload is Part of Multiple Services + +Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. + +If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. For example we _could_ apply the following algorithm: + +```sh +## Algorithm +For traffic to workload W: +1. Collect all Service-targeted AuthorizationPolicies where Service.selector matches W.labels +2. If no policies collected → Allow (default behavior) +3. If policies collected → Evaluate using union semantics + + +## Union semantics: +1. For each DENY policy: if request matches → DENY immediately +2. For each ALLOW policy: collect matching rules +3. If any ALLOW rule matches → ALLOW +4. Otherwise → DENY +``` + +#### Enforcement & Consistency + +Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. + +The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. + +The UX gets weird becuase even though you target a service, you essentially get a **workload** policy, thats enforced regardless. + + +> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a serivce are completely out of scope. -However, targeting a `Service` introduces several challenges: +#### **Option 3: Targeting xRoutes** -1. Authorization cannot be enforced on workloads not exposed via a `Service` - excluding use cases of pods/jobs without a Service. -2. If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. -3. UX and implementation challenges - are implementations expected to enforce the policy only if the traffic arrived through the specific Service? Or just to take the service selectors and enforce the policy regardless of how the traffic got to the destination? +We can target xRoutes. However we are back to -#### **Option 2: Targeting Pods via Label Selectors** +#### **Option 3: Targeting Pods via Label Selectors** Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. @@ -403,7 +455,7 @@ const ( type AuthorizationPolicySpec struct { // TargetRef identifies the resource this policy is attached to. // +kubebuilder:validation:Required - TargetRefs gatewayv1.PolicyTargetReferenceWithLabelSelectors `json:"targetRefs"` + TargetRefs []gatewayv1.PolicyTargetReferenceWithLabelSelectors `json:"targetRefs"` // Action specifies the action to take when a request matches the rules. // +kubebuilder:validation:Required From 03399e44e3e905e65d9c04b580e68d29bfd714a0 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 8 Jul 2025 22:59:36 +0000 Subject: [PATCH 04/15] some-fixes --- geps/gep-3779/index.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index bc44010eb3..a29752d13e 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -353,9 +353,15 @@ The UX gets weird becuase even though you target a service, you essentially get > Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a serivce are completely out of scope. -#### **Option 3: Targeting xRoutes** +#### **Option 2: Targeting xRoutes** -We can target xRoutes. However we are back to +The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. + +We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which service was dialed, we don't have the route information that was responsible for the routing. + +> Note: Linkerd solved this with [Reusing HTTPRoute Schema](https://linkerd.io/2.15/features/httproute/) to distinguish between Inbound and Outbound HTTPRoute. However, I doubt we want that as a community feature. (sorry @kflynn) + +Another (perhaps, easier-to-address) concern is that if we target xRoutes, it is likely that users would expect this Authorization to work for N/S traffic. Documentation and guidance are nice, but I think this still ends up more confusing for no real value. #### **Option 3: Targeting Pods via Label Selectors** From 724b41d00ba4b5731d5a771e0a74cfe4d868f204 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 9 Jul 2025 22:52:51 +0000 Subject: [PATCH 05/15] add Namespace wide section and more clarifications --- geps/gep-3779/index.md | 48 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index a29752d13e..4ad0666fa8 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -419,6 +419,50 @@ type PolicyTargetReferenceWithLabelSelectors struct { ``` +##### Namespace-Wide Policies + +A common case for authorization is to target a whole namespace. We can achieve the above with a few patterns: + +###### Option 1 + +Target a namespace, name MUST be empty (as this is already namespaced policy) + +```yaml +targetRefs: +- Kind: Namespace +``` + +This however gives the (confusing) impression that Gateways (whether in-cluster or off-cluster gateways) are targeted as well. Beyond the question of "does it really make sense for an E/W policy to be applicable to a N/S Gateway?" it leaves no way for users to do a namespace wide policy that excludes Gateways (no way to exclude Off-cluster Gateways with labels -- see option 3 for alternative). + +###### Option 2 + +Leaving an empty targetRefs. While this is theoretically possible without a breaking change, this would be another fundamental change to policy attachment (to allow policies without a targetRef). +Additionally, this is also suffer from the same problem of being perceived as an applicable scope for both Gateways and Workloads in the namespace. + +This option is also inconsistent with other API fields where an empty field or absence of a it does not mean select all. See [recent comment](https://github.com/kubernetes-sigs/gateway-api/pull/3887#discussion_r2176125600) on the proposal for empty ParentRef field. + +###### Option 3 + +An empty pod selector. Kubernetes official docs clarify that the semantics of empty selectors are the decision of the API owner. In fact, many Kubernetes APIs (I know Service API does the opposite :/) using empty selectors as a select-all mechanism. See [NetworkPolicy podSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#networkpolicy-v1-networking-k8s-io), PodDisruptionBudget, ResourceQuota, and more. + +```yaml +targetRefs: +- Kind: Pod + Selector: {} +``` + +This provides a clearer separation between workloads and gateways. Gateways that happen to be Pods in the cluster, will also get selected. However they can be excluded with the right `matchExpression` if desired. + +Below is a pseudo example: + +```yaml +targetRefs: +- Kind: Pod + Selector: + matchExpression: + - { key: "purpose", operator: NotIn, values: ["gateway"] } +``` + ##### **Enhanced Discoverability with `gwctl`** A key challenge with `LabelSelector` is the loss of discoverability. It’s easier to see which policies target a `Service` but difficult to determine which policies might affect a specific pod. @@ -564,9 +608,11 @@ Note: Existing AuthorizationAPIs recognized the need to support negation fields ## Conformance Details +### Feature Names -#### Feature Names +Two new feature sets will be added - AuthorizationPolicyCoreFeatures, and later, AuthorizationPolicyExtendedFeatures. +TBD exact FeatureNames. ### Conformance tests From e99e0d64a1c6fdef905409abe691f1ca8ff0926d Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Fri, 11 Jul 2025 23:51:38 +0000 Subject: [PATCH 06/15] add clarifications and link to google doc for targetRef --- geps/gep-3779/index.md | 134 +++++++++++++++++++++++++++++++++++------ 1 file changed, 114 insertions(+), 20 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 4ad0666fa8..9379b11d4f 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -308,7 +308,7 @@ However, targeting a `Service` introduces several challenges; ##### Loss Of Service Context -I we go with option 1, apply authorization policy to all traffic addressed to a service; +If we go with option 1, apply authorization policy to all traffic addressed to a service; This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. Here is the very high-level tarffic flow for sidecar-based meshes: @@ -350,8 +350,7 @@ The UX becomes very confusing. Are we going to enforce only if the traffic arriv The UX gets weird becuase even though you target a service, you essentially get a **workload** policy, thats enforced regardless. - -> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a serivce are completely out of scope. +> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Serivce are completely out of scope. #### **Option 2: Targeting xRoutes** @@ -475,6 +474,79 @@ TODO: complete gwctl commands Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. +#### Recommended Option - Hybrid TargetRef and VAP + +Adding only the recommendation below, please see [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) for a comprehensive comparison for design options for TargetRef. + +Create one unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent + +``` +# Network-scoped policy (L4 enforcement points) +kind: AuthorizationPolicy +metadata: + name: network-authz +spec: + enforcementLevel: "network" # Enforced at L4 proxies + targetRef: + kind: Pod + selector: {} + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + tcpAttributes: + ports: [9080] + +# Application-scoped policy (L7-only enforcement points and sidecars) +kind: AuthorizationPolicy +metadata: + name: app-authz +spec: + enforcementLevel: "application" # Enforced at L7 proxies + targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + tcpAttributes: + ports: [9080] + httpAttributes: + paths: ["/api/*"] + methods: ["GET", "POST"] + + +``` + +### Mesh Implementation Behavior + +Sidecar Meshes + +* **Network Level**: Sidecar enforces policy but only uses L4 attributes +* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities + +Ambient Meshes + +* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting +* **Application Level**: Waypoint proxy enforces policy using service targetRef targeting + +**VAP Validation**: + +* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) + * **Ambient**: Ensures application-level policies don't use label-selectors. + * **Both sidecar and ambient:** ensures network level policies **do** use label selectors + +Advantages + +* **Clear Intent**: Users explicitly state where they want enforcement +* **Flexible Targeting**: Different targetRef types for different enforcement points +* **Migration Path**: Users can start with network-level and upgrade to application-level easily +* **Implementation Alignment**: supporting different meshes architectures +* **Single API**: No duplication of schemas or concepts +* **Validation Clarity**: Clear rules about what's allowed at each level + +Disadvantages + +* **Complexity**: Users must understand enforcement levels +* **VAP Dependency**: Requires validation rules + ### API Design ```go @@ -511,33 +583,55 @@ type AuthorizationPolicySpec struct { // +kubebuilder:validation:Required Action AuthorizationPolicyAction `json:"action"` - // TCPRules defines the list of matching criteria. A request is considered to - // match the policy if it matches any of the rules. + // Rules defines the list of authorization rules. + // A request matches the policy if it matches any of these rules. // +optional - TCPRules []AuthorizationTCPRule `json:"tcpRules,omitempty"` + Rules []AuthorizationRule `json:"rules,omitempty"` } -// AuthorizationTCPRule defines a set of criteria for matching a TCP request. -// A request must match all specified criteria. -type AuthorizationTCPRule struct { - // Sources specifies a list of identities that are matched by this rule. - // If this field is empty, this rule matches all sources. - // A request matches if its identity is present in this list. +// AuthorizationRule defines a single authorization rule. +// A request matches the rule if it matches ALL fields specified. +type AuthorizationRule struct { + // AuthorizationSource specifies who is making the request. + // If omitted, matches any source. // +optional - Sources []AuthorizationSource `json:"sources,omitempty"` + AuthorizationSource *AuthorizationSource `json:"authorizationSource,omitempty"` - // Attributes specifies a list of properties that are matched by this rule. - // If this field is empty, this rule matches all attributes. - // A request matches if its attributes are present in this list. - // + // TCPAttributes specifies TCP-level matching criteria. + // If omitted, matches any TCP traffic. // +optional - Attributes []AuthorizationTCPAttributes `json:"attributes,omitempty"` + TCPAttributes *AuthorizationTCPAttributes `json:"tcpAttributes,omitempty"` + + + // FOR FUTURE ENHANCEMENT! + + // HTTPAttributes specifies HTTP-level matching criteria. + // If omitted, matches any HTTP traffic. + // +optional + HTTPAttributes *AuthorizationHTTPAttributes `json:"httpAttributes,omitempty"` } + // AuthorizationSource specifies the source of a request. -// Only one of its fields may be set. -// +kubebuilder:validation:XValidation:rule="(size(self.identities) > 0 ? 1 : 0) + (size(self.serviceAccounts) > 0 ? 1 : 0) + (size(self.namespaces) > 0 ? 1 : 0) == 1",message="Exactly one of identities, serviceAccounts, or namespaces must be specified." +// +// At least one field may be set. If multiple fields are set, +// a request matches this AuthorizationSource if it matches +// **any** of the specified criteria (logical OR across fields). +// +// For example, if both `Identities` and `Namespaces` are provided, +// the rule matches a request if either: +// - the request's identity is in `Identities` +// - OR the request originates from one of the `Namespaces`. +// +// Each list within the fields (e.g. `Identities`) is itself an OR list. +// +// If this struct is omitted in a rule, it matches any source. +// +// NOTE: In the future, if there’s a need to express more complex +// logical conditions (e.g. requiring a request to match multiple +// criteria simultaneously—logical AND), we may evolve this API +// to support richer match expressions or logical operators. type AuthorizationSource struct { // Identities specifies a list of identities that are matched by this rule. From 1d1771615725328a8611358180cdf5b5abf6ad27 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Thu, 17 Jul 2025 18:19:28 +0000 Subject: [PATCH 07/15] more feedback --- geps/gep-3779/index.md | 110 ++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 33 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 9379b11d4f..4df59937e4 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -469,7 +469,18 @@ A key challenge with `LabelSelector` is the loss of discoverability. It’s easi To address this, **investment in tooling is required.** Specifically, the `gwctl` CLI tool should be enhanced to provide insights such as: ```sh -TODO: complete gwctl commands +gwctl describe pods pod1 + +... +InheritedPolicies: + Type Name Target Kind Target Name/Expression + ---- ---- ----------- ----------- + AuthorizationPolicy demo-authz-policy-on-payment-pods Pod Selector={foo: a, bar: 2} +... + +# List all AuthorizationPolicy resources in json format in the active namespace +gwctl get authorizationPolicy -o json + ``` Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. @@ -478,7 +489,30 @@ Without dedicated tooling, the `LabelSelector` approach could significantly degr Adding only the recommendation below, please see [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) for a comprehensive comparison for design options for TargetRef. -Create one unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent +Create one unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. + +```go + +// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. +// +// There are two enforcement levels: +// +// - NETWORK: Enforces the policy at the network layer (L4), typically at +// network proxies or gateway dataplanes. Only supports attributes available +// at connection time (e.g., source identity, port). Recommended for broad, +// coarse-grained access controls. +// +// - APPLICATION: Enforces the policy at the application layer (L7), typically at +// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization +// using protocol-specific attributes (e.g., HTTP paths, methods). +// +// This field clarifies policy intent and informs where enforcement is expected +// to happen. It also enables implementation-specific validation and behavior. +// +// +kubebuilder:validation:Enum=NETWORK;APPLICATION +type EnforcementLevel string + +``` ``` # Network-scoped policy (L4 enforcement points) @@ -493,7 +527,7 @@ spec: rules: - authorizationSource: serviceAccount: ["default/productpage"] - tcpAttributes: + networkAttributes: ports: [9080] # Application-scoped policy (L7-only enforcement points and sidecars) @@ -506,9 +540,9 @@ spec: rules: - authorizationSource: serviceAccount: ["default/productpage"] - tcpAttributes: + networkAttributes: ports: [9080] - httpAttributes: + applicationAttributes: paths: ["/api/*"] methods: ["GET", "POST"] @@ -597,18 +631,27 @@ type AuthorizationRule struct { // +optional AuthorizationSource *AuthorizationSource `json:"authorizationSource,omitempty"` - // TCPAttributes specifies TCP-level matching criteria. + // NetworkAttributes specifies TCP-level matching criteria. // If omitted, matches any TCP traffic. // +optional - TCPAttributes *AuthorizationTCPAttributes `json:"tcpAttributes,omitempty"` + NetworkAttributes *AuthorizationNetworkAttributes `json:"networkAttributes,omitempty"` - - // FOR FUTURE ENHANCEMENT! + // FOR FUTURE ENHANCEMENT!! + + // ApplicationAttributes defines optional application-layer (L7) matching criteria + // used to authorize requests when enforcement is at the APPLICATION level. + // + // All specified fields must match for the rule to apply (logical AND). If omitted, + // the rule matches all application-layer traffic. + // + // Typical use cases include protocol-aware authorization for HTTP, gRPC, or other L7 traffic. + // Fields may vary in applicability based on the protocol and implementation support. + // + // NOTE: ApplicationAttributes are only meaningful when `enforcementLevel` is set to + // APPLICATION. Implementations MUST ignore or reject these fields if used at NETWORK level. - // HTTPAttributes specifies HTTP-level matching criteria. - // If omitted, matches any HTTP traffic. // +optional - HTTPAttributes *AuthorizationHTTPAttributes `json:"httpAttributes,omitempty"` + ApplicationAttributes *AuthorizationApplicationAttributes `json:"applicationAttributes,omitempty"` } @@ -619,10 +662,10 @@ type AuthorizationRule struct { // a request matches this AuthorizationSource if it matches // **any** of the specified criteria (logical OR across fields). // -// For example, if both `Identities` and `Namespaces` are provided, +// For example, if both `Identities` and `ServiceAccounts` are provided, // the rule matches a request if either: // - the request's identity is in `Identities` -// - OR the request originates from one of the `Namespaces`. +// - OR the request's service account matches an entry in `ServiceAccounts`. // // Each list within the fields (e.g. `Identities`) is itself an OR list. // @@ -663,32 +706,33 @@ type AuthorizationSource struct { Identities []string `json:"identities,omitempty"` // ServiceAccounts specifies a list of Kubernetes Service Accounts that are - // matched by this rule. Each service account must be specified in the format - // "/". A request originating from a pod - // associated with one of these service accounts will match the rule. + // matched by this rule. A request originating from a pod associated with + // one of these service accounts will match the rule. + // + // Values must be in one of the following formats: + // - "/": A specific service account in a namespace. + // - "/*": All service accounts in the given namespace. + // - "": A service account in the same namespace as the policy. + // + // Use of "*" alone (i.e., all service accounts in all namespaces) is not allowed. + // To select all service accounts in the current namespace, use "/*" explicitly. + // + // Example: + // - "default/bookstore" → Matches service account "bookstore" in namespace "default" + // - "payments/*" → Matches any service account in namespace "payments" + // - "frontend" → Matches "frontend" service account in the same namespace as the policy // // The ServiceAccounts listed here are expected to exist within the same // trust domain as the targeted workload, which in many environments means - // the same Kubernetes cluster. Cross-cluster or cross-trust-domain should - // be expressed with Identities field. - // +optional + // the same Kubernetes cluster. Cross-cluster or cross-trust-domain access + // should instead be expressed using the `Identities` field. + // + // +optional ServiceAccounts []string `json:"serviceAccounts,omitempty"` - - // Namespaces specifies a list of Kubernetes Namespaces that are matched - // by this rule. A request originating from any pod within one of these - // namespaces will match the rule, regardless of its specific Service Account. - // This provides a broader scope for authorization. - - // The Namespaces listed here are expected to exist within the same - // trust domain as the targeted workload, which in many environments means - // the same Kubernetes cluster. Cross-cluster or cross-trust-domain should - // be expressed with Identities field. - // +optional - Namespaces []string `json:"namespaces,omitempty"` } // AuthorizationAttribute defines L4 properties of a request destination. -type AuthorizationTCPAttributes struct { +type AuthorizationNetworkAttributes struct { // Ports specifies a list of destination ports to match on. // Traffic is matched if it is going to any of these ports. // If not specified, the rule applies to all ports. From 7c534291ec347473b743343a632c3530571c091b Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Mon, 21 Jul 2025 22:00:54 +0000 Subject: [PATCH 08/15] more feedback --- geps/gep-3779/index.md | 52 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 4df59937e4..ea296a6511 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -1,7 +1,7 @@ # GEP-3779: Identity Based Authz for East-West Traffic * Issue: [#3779](https://github.com/kubernetes-sigs/gateway-api/issues/3779) -* Status: Provisional +* Status: Implementable (See [status definitions](../overview.md#gep-states).) @@ -55,7 +55,7 @@ An identity-based authorization API is essential because it provides a structure | Aspect | Istio | Linkerd | Cilium | | ----- | ----- | ----- | ----- | | **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | -| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference service accounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like service accounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| +| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference Serviceaccounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like Serviceaccounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| | **Enforcement** | For Istio with sidecars - a proxy on each pod. For ambient, ztunnel node agent enforces mTLS based L4 authorization, L7 authorization is being enforced in waypoints if any.

Istio supports ALLOW, DENY, CUSTOM (often used for external authorization), and AUDIT. DENY policies in istio's context are used to enforce higher priority deny policies. The allow semantics is that whatever is not allowed explicitly (and assuming there is any policy for the same match) is implicitly denied | Linkerd data-plane proxy (injected into each pod). The proxy enforces policies via mTLS identity checks.

Linkerd supports AUDIT and ALLOW. There is not DENY policies, whats not allowed (and assuming there is any policy for the same match) is implicitly denied. | For L3/4 Ingress Rules, CiliumNetworkPolicy enforcement - an eBPF-based datapath in the Linux kernel on the destination node. If L7 http rules are specified, the packet is redirected for a node-local envoy for further enforcement.

Cilium supports ALLOW and DENY semantics - all policies generate audit logs.

Cilium service mesh also offers a kind of AuthN where a Cilium agent on the src node validates a workloads SPIFFE identity by talking to another agent on the destination node, performing the initial TLS handshake to do authentication.| | **Request Match criteria** | Policies can target a group of pods using label selector, a Gateway/Service (this means targeting a waypoint proxy) or a GatewayClass - meaning all the gateways created from this class. Policies without a label selector in a namespace implies the whole namespace is targeted.

Fine-grained L7 and L4 matching: HTTP/gRPC methods, paths, headers, ports, SNI, etc.Policies use logical OR over rules.

All match criterias are inline in the policy. See https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-To and https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-when | Policies can target:
  • A `Server` which describes a set of pods (using fancy label match expressions), and a single port on those pods.
  • A user can optionally restrict the authorization to a smaller subset of the traffic by targeting an HTTPRoute. (TODO: any plans to support sectionNames?)
  • A namespace - this indicates that the policy applies to all traffic to all Servers and HTTPRoutes defined in the namespace.
Note: We leave `ServerAuthorization` outside the scope as it planned to be deprecated (per linkerd website) | Policies can target groups of pods using label selector (`endpointSelector`), or by node-labels (`nodeSelector`). Cilium supports L7 via built-in HTTP parsing: rules can match HTTP methods, paths, etc. For example, a CiliumNetworkPolicy can allow only specific HTTP methods/paths on a port. | | **Default policies and admin policies** | If **no** ALLOW policy matches, traffic is **allowed** by default. You can deploy an overridable - default deny by default by deploying an **allow-nothing** policy in either the namespace or istio-system

AuthorizationPolicies in the `istio-system` namespace apply to the whole mesh and take precedence. These are not overridable by namespace-level policies. | Default inbound policy can be set at install time using `proxy.defaultInboundPolicy`. Supported values are:
  • `all-unauthenticated:` allow all traffic. This is the default.
  • `all-authenticated:` allow traffic from meshed clients in the same or from a different cluster (with multi-cluster).
  • `cluster-authenticated:` allow traffic from meshed clients in the same cluster.
  • `cluster-unauthenticated:` allow traffic from both meshed and non-meshed clients in the same cluster.
  • `deny:` all traffic are denied.
  • `audit:` Same as all-unauthenticated but requests get flagged in logs and metrics.

Users can override the default policies for namespaces/pods or by setting the [config.linkerd.io/default-inbound-policy](http://config.linkerd.io/default-inbound-policy) annotation There is no support for admin, non overridable policies. | Follows Kubernetes NetworkPolicy semantics by default: if no `CiliumNetworkPolicy` allows the traffic, it is allowed (no implicit deny). Once at least one `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` allows some traffic, all other traffic is implicitly denied. @@ -67,7 +67,7 @@ Every mesh vendor has their own API of such authorization. Below we describe bri #### Istio For the full spec and sematics of Istio AuthorizationPolicy: [Istio authorization policy docs](https://istio.io/latest/docs/reference/config/security/authorization-policy/) -Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated service account identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. +Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated Serviceaccount identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. ``` apiVersion: security.istio.io/v1beta1 @@ -212,7 +212,7 @@ spec: For the full spec and sematics of CiliumNetworkPolicy: https://docs.cilium.io/en/stable/network/kubernetes/policy/#ciliumnetworkpolicy & https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#cilium-s-ingress-config-and-ciliumnetworkpolicy -Beyond what's explained in the table above, Cilium also automatically labels each pod with its associated service account using the label io.cilium.k8s.policy.serviceaccount. This label can be used in CiliumNetworkPolicy to enforce identity-based access controls using [ServiceAccounts Based Identities](https://docs.cilium.io/en/latest/security/policy/kubernetes/#serviceaccounts) within CiliumNetworkPolicy; +Beyond what's explained in the table above, Cilium also automatically labels each pod with its associated Serviceaccount using the label io.cilium.k8s.policy.serviceaccount. This label can be used in CiliumNetworkPolicy to enforce identity-based access controls using [ServiceAccounts Based Identities](https://docs.cilium.io/en/latest/security/policy/kubernetes/#serviceaccounts) within CiliumNetworkPolicy; See below for example. @@ -292,25 +292,27 @@ The `targetRef` of the policy specifies the workload(s) to which the policy appl The `targetRef` can point to a Kubernetes `Service`. -Two implementation options when targeting a service: +Two implementation options when targeting a Service: 1. Apply authorization policy to all traffic addressed to this Service. 1. Apply authorization policy to all workloads (pods) selected by the Service. -**Benefits:** +#### Benefits * **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. * **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. -**Downsides and Open Questions:** +#### Downsides and Open Questions However, targeting a `Service` introduces several challenges; ##### Loss Of Service Context -If we go with option 1, apply authorization policy to all traffic addressed to a service; - This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. - Here is the very high-level tarffic flow for sidecar-based meshes: +If we go with option 1, apply authorization policy to all traffic addressed to a Service; + +This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. + +Here is the very high-level tarffic flow for sidecar-based meshes: ```sh Client → Request to backend-service:8080 @@ -319,7 +321,7 @@ If we go with option 1, apply authorization policy to all traffic addressed to a → Destination sidecar has NO context that this came via "backend-service" ``` -Solving this problem either introduces security concern (e.g adding request metadata to indicate which service was dialed), or unnecessarily complex or in-efficient to solve. +Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. #### A Workload is Part of Multiple Services @@ -348,7 +350,7 @@ Assuming we go with option 2, apply authorization policy to all workloads (pods) The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. -The UX gets weird becuase even though you target a service, you essentially get a **workload** policy, thats enforced regardless. +The UX gets weird becuase even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. > Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Serivce are completely out of scope. @@ -356,7 +358,7 @@ The UX gets weird becuase even though you target a service, you essentially get The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. -We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which service was dialed, we don't have the route information that was responsible for the routing. +We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which Service was dialed, we don't have the route information that was responsible for the routing. > Note: Linkerd solved this with [Reusing HTTPRoute Schema](https://linkerd.io/2.15/features/httproute/) to distinguish between Inbound and Outbound HTTPRoute. However, I doubt we want that as a community feature. (sorry @kflynn) @@ -369,7 +371,7 @@ Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` **Benefits:** * Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. -* Directly applies policy to pods, avoiding ambiguity present when targeting services. Ensures policies are enforced exactly where intended, regardless of how many services a pod might belong to. +* Directly applies policy to pods, avoiding ambiguity present when targeting Services. Ensures policies are enforced exactly where intended, regardless of how many Services a pod might belong to. * Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. **Downsides and Open Questions:** @@ -559,7 +561,7 @@ Sidecar Meshes Ambient Meshes * **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting -* **Application Level**: Waypoint proxy enforces policy using service targetRef targeting +* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting **VAP Validation**: @@ -665,7 +667,7 @@ type AuthorizationRule struct { // For example, if both `Identities` and `ServiceAccounts` are provided, // the rule matches a request if either: // - the request's identity is in `Identities` -// - OR the request's service account matches an entry in `ServiceAccounts`. +// - OR the request's Serviceaccount matches an entry in `ServiceAccounts`. // // Each list within the fields (e.g. `Identities`) is itself an OR list. // @@ -707,20 +709,20 @@ type AuthorizationSource struct { // ServiceAccounts specifies a list of Kubernetes Service Accounts that are // matched by this rule. A request originating from a pod associated with - // one of these service accounts will match the rule. + // one of these Serviceaccounts will match the rule. // // Values must be in one of the following formats: - // - "/": A specific service account in a namespace. - // - "/*": All service accounts in the given namespace. - // - "": A service account in the same namespace as the policy. + // - "/": A specific Serviceaccount in a namespace. + // - "/*": All Serviceaccounts in the given namespace. + // - "": a Serviceaccount in the same namespace as the policy. // - // Use of "*" alone (i.e., all service accounts in all namespaces) is not allowed. - // To select all service accounts in the current namespace, use "/*" explicitly. + // Use of "*" alone (i.e., all Serviceaccounts in all namespaces) is not allowed. + // To select all Serviceaccounts in the current namespace, use "/*" explicitly. // // Example: - // - "default/bookstore" → Matches service account "bookstore" in namespace "default" - // - "payments/*" → Matches any service account in namespace "payments" - // - "frontend" → Matches "frontend" service account in the same namespace as the policy + // - "default/bookstore" → Matches Serviceaccount "bookstore" in namespace "default" + // - "payments/*" → Matches any Serviceaccount in namespace "payments" + // - "frontend" → Matches "frontend" Serviceaccount in the same namespace as the policy // // The ServiceAccounts listed here are expected to exist within the same // trust domain as the targeted workload, which in many environments means From 876fdd50ff1a3082db3ee11685227979595de476 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Fri, 25 Jul 2025 01:42:49 +0000 Subject: [PATCH 09/15] add feedback and agreements from meeting --- geps/gep-3779/index.md | 296 ++++++++++++++++++++++++----------------- mkdocs.yml | 2 + 2 files changed, 173 insertions(+), 125 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index ea296a6511..50f0fb0f09 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -5,12 +5,10 @@ (See [status definitions](../overview.md#gep-states).) - ## TLDR Provide a method for configuring Gateway API Mesh implementations to enforce east-west identity-based Authorization controls. At the time of writing this we leave Authentication for specific implementation and outside of this proposal scope. - ## Goals (Using the [Gateway API Personas](../../concepts/roles-and-personas.md)) @@ -33,7 +31,6 @@ Provide a method for configuring Gateway API Mesh implementations to enforce eas * (Potentially) Support enforcement on attributes beyond identities and ports. - ## Introduction Authorization is positioned as one of core mesh values. Every mesh supports some kind of east/west authorization between the workloads it controls. @@ -48,10 +45,8 @@ Kubernetes core provides NetworkPolicies as one way to do it. Network Policies h An identity-based authorization API is essential because it provides a structured way to control authorization between identities within the cluster. - ### State of the World - | Aspect | Istio | Linkerd | Cilium | | ----- | ----- | ----- | ----- | | **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | @@ -248,9 +243,9 @@ More on https://docs.cilium.io/en/stable/internals/security-identities/ & https: ## API -This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (`ALLOW` or `DENY`), and a set of rules that include sources (the “who”) and an optional port attribute. +This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (to begin with - `ALLOW`, and will likely add `DENY` in future iterations), and a set of rules that include sources (the “who”) and an optional port attribute. -### **Policy Rules** +### Policy Rules Each `AuthorizationPolicy` resource contains a list of rules. A request matches the policy if it matches **any** rule in the list (logical OR). Each rule defines multiple matching criteria; a request matches a rule only if it matches **all** criteria within that rule (logical AND). @@ -263,32 +258,162 @@ A rule may specify: * **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. -### **ALLOW Policies** +Note: This GEP is written as if DENY is also in scope, however, the GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. + +### ALLOW Policies * An **ALLOW** policy is permissive. * A request is allowed if: * It matches at least one rule in any ALLOW policy targeting the workload **and** * It is not explicitly denied by any DENY policy. - * If no ALLOW policy exists for a workload, traffic is permitted by default, unless any DENY policy applies. + * If no ALLOW policy exists for a workload, traffic is permitted by default. -### **DENY Policies** +### DENY Policies * A **DENY** policy is restrictive and takes precedence over ALLOW. * If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. * DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). -### **ALLOW vs. DENY Semantics** +### ALLOW vs. DENY Semantics * **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. * The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. * Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. -### **Target of Authorization** +### Target of Authorization + +The `targetRef` of the policy specifies the workload(s) to which the policy applies + +> Note: in sidecar mode, it happens to also be the policy enforcement point, in ambient however, this is not true. + +Before we are jumping into the options, lets start with some background. + +#### Mesh Implementation Types + +#### Sidecar-Based Meshes + +* **Architecture**: Sidecar proxy deployed alongside every pod +* **Capabilities**: Can enforce all request attributes (L4 and L7) +* **Targeting**: Uses label selectors to target sidecars for policy enforcement points (and destination) +* **Enforcement Point**: Single enforcement point (the destination sidecar) + +#### Ambient Meshes + +* **Architecture**: Two-tier proxy system + * Node-L4-proxy: Handles identity-based policies and port enforcement + * L7 enforcement point (waypoint proxy): Handles advanced L7 features +* **Targeting**: + * Label selectors for node proxy distribution + * Service targetRef for L7 enforcement at waypoints + * **Constraint**: Selectors and targetRef cannot be used together + +### Key Challenges + +1. **Architectural Differences**: Ambient meshes separate L4 and L7 enforcement, while sidecars handle both +2. **Targeting Mechanisms**: + * Ambient struggles with label selectors for L7 enforcement on waypoints ([#label-selectors-aren't-good-for-ambient-l7](#label-selectors-arent-good-for-ambient-l7)) + * Sidecars have difficulty supporting Service targeting for L7 enforcement ([#loss-of-service-context](#loss-of-service-context)) +3. **API Consistency**: Need a unified approach that works across all implementations + +There a few options are available for `targetRef`. This GEP starts by specifying the recommendation, but you will **highly** benefit from going over the alternatives a few times and the detailed comparison at [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) to understand how we got to this recommendation. + +#### Recommended Option - Hybrid TargetRef and VAP + +One unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. + +```go + +// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. +// +// There are two enforcement levels: +// +// - NETWORK: Enforces the policy at the network layer (L4), typically at +// network proxies or gateway dataplanes. Only supports attributes available +// at connection time (e.g., source identity, port). Recommended for broad, +// coarse-grained access controls. +// +// - APPLICATION: Enforces the policy at the application layer (L7), typically at +// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization +// using protocol-specific attributes (e.g., HTTP paths, methods). +// +// This field clarifies policy intent and informs where enforcement is expected +// to happen. It also enables implementation-specific validation and behavior. +// +// +kubebuilder:validation:Enum=NETWORK;APPLICATION +type EnforcementLevel string + +``` + +```yaml +# Network-scoped policy (L4 enforcement points) +kind: AuthorizationPolicy +metadata: + name: network-authz +spec: + enforcementLevel: "network" # Enforced at L4 proxies + targetRef: + kind: Pod + selector: {} + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + networkAttributes: + ports: [9080] + +# Application-scoped policy (L7-only enforcement points and sidecars) +kind: AuthorizationPolicy +metadata: + name: app-authz +spec: + enforcementLevel: "application" # Enforced at L7 proxies + targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + networkAttributes: + ports: [9080] + applicationAttributes: + paths: ["/api/*"] + methods: ["GET", "POST"] + + +``` + +##### Mesh Implementation Behavior + +Sidecar Meshes + +* **Network Level**: Sidecar enforces policy but only uses L4 attributes +* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities + +Ambient Meshes + +* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting +* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting + +**VAP Validation**: + +* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) + * **Ambient**: Ensures application-level policies don't use label-selectors. + * **Both sidecar and ambient:** ensures network level policies **do** use label selectors -The `targetRef` of the policy specifies the workload(s) to which the policy applies. Two options are available for `targetRef`: +Advantages -#### **Option 1: Targeting a Service** +* **Clear Intent**: Users explicitly state where they want enforcement +* **Flexible Targeting**: Different targetRef types for different enforcement points +* **Migration Path**: Users can start with network-level and upgrade to application-level easily +* **Implementation Alignment**: supporting different meshes architectures +* **Single API**: No duplication of schemas or concepts +* **Validation Clarity**: Clear rules about what's allowed at each level + +Disadvantages + +* **Complexity**: Users must understand enforcement levels +* **VAP Dependency**: Requires validation rules + + +#### Alternative 1: Targeting a Service The `targetRef` can point to a Kubernetes `Service`. @@ -298,21 +423,22 @@ Two implementation options when targeting a Service: 1. Apply authorization policy to all workloads (pods) selected by the Service. -#### Benefits +##### Benefits * **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. * **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. -#### Downsides and Open Questions +##### Downsides and Open Questions + However, targeting a `Service` introduces several challenges; -##### Loss Of Service Context +###### Loss Of Service Context If we go with option 1, apply authorization policy to all traffic addressed to a Service; This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. -Here is the very high-level tarffic flow for sidecar-based meshes: +Here is the very high-level traffic flow for sidecar-based meshes: ```sh Client → Request to backend-service:8080 @@ -323,7 +449,7 @@ Here is the very high-level tarffic flow for sidecar-based meshes: Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. -#### A Workload is Part of Multiple Services +##### A Workload is Part of Multiple Services Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. @@ -344,17 +470,17 @@ For traffic to workload W: 4. Otherwise → DENY ``` -#### Enforcement & Consistency +##### Enforcement & Consistency Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. -The UX gets weird becuase even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. +The UX gets weird because even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. -> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Serivce are completely out of scope. +> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Service are completely out of scope. -#### **Option 2: Targeting xRoutes** +#### Alternative 2: Targeting xRoutes The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. @@ -364,7 +490,7 @@ We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [ Another (perhaps, easier-to-address) concern is that if we target xRoutes, it is likely that users would expect this Authorization to work for N/S traffic. Documentation and guidance are nice, but I think this still ends up more confusing for no real value. -#### **Option 3: Targeting Pods via Label Selectors** +#### Alternative 3: Targeting Pods via Label Selectors Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. @@ -376,13 +502,23 @@ Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` **Downsides and Open Questions:** -The main downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See below for more info. +##### Label-Selectors aren't Good for Ambient L7 + +In L7 Ambient, AuthorizationPolicy targets a Service. This Service has to have a waypoint proxy. The policy enforcement point is the waypoint, but it is also the point where the Service VIP resolution happens. + +If we were to target Label Selectors, the waypoint proxy would get the request, do VIP resolution and select an endpoint, and then it would require round-tripping to itself for doing policy enforcement. + +@howardjohn has actually added that this was actually the first way ambient had implemented authorization, but it has proved to be much less performant. + +##### Discoverability Challenge + +The additional (and main) downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See below for more info. **Requirement: Enhancing Policy Attachment:** This option depends on enhancements to Gateway API’s policy attachment model to support `LabelSelector` as a valid `targetRef`. This capability was discussed and received consensus at KubeCon North America 2024 and was originally in scope for GEP-713 but deferred for a future PR to keep GEP-713 focused on stabilizing what we already have (See [https://github.com/kubernetes-sigs/gateway-api/pull/3609#discussion_r2053376938](https://github.com/kubernetes-sigs/gateway-api/pull/3609#discussion_r2053376938)). -##### **Experimental Pattern** +##### Experimental Pattern To mitigate some of the concerns, `LabelSelector` support in policy attachment is designated as an **experimental pattern**. @@ -437,12 +573,12 @@ This however gives the (confusing) impression that Gateways (whether in-cluster ###### Option 2 -Leaving an empty targetRefs. While this is theoretically possible without a breaking change, this would be another fundamental change to policy attachment (to allow policies without a targetRef). +Leaving an empty targetRefs. While this is theoretically possible without a breaking change, this would be another fundamental change to policy attachment (to allow policies without a targetRef). Additionally, this is also suffer from the same problem of being perceived as an applicable scope for both Gateways and Workloads in the namespace. This option is also inconsistent with other API fields where an empty field or absence of a it does not mean select all. See [recent comment](https://github.com/kubernetes-sigs/gateway-api/pull/3887#discussion_r2176125600) on the proposal for empty ParentRef field. -###### Option 3 +###### Option 3 (Recommended) An empty pod selector. Kubernetes official docs clarify that the semantics of empty selectors are the decision of the API owner. In fact, many Kubernetes APIs (I know Service API does the opposite :/) using empty selectors as a select-all mechanism. See [NetworkPolicy podSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#networkpolicy-v1-networking-k8s-io), PodDisruptionBudget, ResourceQuota, and more. @@ -464,7 +600,7 @@ targetRefs: - { key: "purpose", operator: NotIn, values: ["gateway"] } ``` -##### **Enhanced Discoverability with `gwctl`** +##### Enhanced Discoverability with `gwctl` A key challenge with `LabelSelector` is the loss of discoverability. It’s easier to see which policies target a `Service` but difficult to determine which policies might affect a specific pod. @@ -487,102 +623,6 @@ gwctl get authorizationPolicy -o json Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. -#### Recommended Option - Hybrid TargetRef and VAP - -Adding only the recommendation below, please see [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) for a comprehensive comparison for design options for TargetRef. - -Create one unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. - -```go - -// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. -// -// There are two enforcement levels: -// -// - NETWORK: Enforces the policy at the network layer (L4), typically at -// network proxies or gateway dataplanes. Only supports attributes available -// at connection time (e.g., source identity, port). Recommended for broad, -// coarse-grained access controls. -// -// - APPLICATION: Enforces the policy at the application layer (L7), typically at -// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization -// using protocol-specific attributes (e.g., HTTP paths, methods). -// -// This field clarifies policy intent and informs where enforcement is expected -// to happen. It also enables implementation-specific validation and behavior. -// -// +kubebuilder:validation:Enum=NETWORK;APPLICATION -type EnforcementLevel string - -``` - -``` -# Network-scoped policy (L4 enforcement points) -kind: AuthorizationPolicy -metadata: - name: network-authz -spec: - enforcementLevel: "network" # Enforced at L4 proxies - targetRef: - kind: Pod - selector: {} - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - -# Application-scoped policy (L7-only enforcement points and sidecars) -kind: AuthorizationPolicy -metadata: - name: app-authz -spec: - enforcementLevel: "application" # Enforced at L7 proxies - targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - applicationAttributes: - paths: ["/api/*"] - methods: ["GET", "POST"] - - -``` - -### Mesh Implementation Behavior - -Sidecar Meshes - -* **Network Level**: Sidecar enforces policy but only uses L4 attributes -* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities - -Ambient Meshes - -* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting -* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting - -**VAP Validation**: - -* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) - * **Ambient**: Ensures application-level policies don't use label-selectors. - * **Both sidecar and ambient:** ensures network level policies **do** use label selectors - -Advantages - -* **Clear Intent**: Users explicitly state where they want enforcement -* **Flexible Targeting**: Different targetRef types for different enforcement points -* **Migration Path**: Users can start with network-level and upgrade to application-level easily -* **Implementation Alignment**: supporting different meshes architectures -* **Single API**: No duplication of schemas or concepts -* **Validation Clarity**: Clear rules about what's allowed at each level - -Disadvantages - -* **Complexity**: Users must understand enforcement levels -* **VAP Dependency**: Requires validation rules - ### API Design ```go @@ -605,6 +645,9 @@ type AuthorizationPolicyAction string const ( // ActionAllow allows requests that match the policy rules. ActionAllow AuthorizationPolicyAction = "ALLOW" + + // NOTE FOR REVIEWERS AGAIN: GAMMA leads met on 24th July and DENY action is likely going to be pushed to 1.5 and will potentially be extended conformance. + // ActionDeny denies requests that match the policy rules. ActionDeny AuthorizationPolicyAction = "DENY" ) @@ -612,6 +655,9 @@ const ( // AuthorizationPolicySpec defines the desired state of AuthorizationPolicy. type AuthorizationPolicySpec struct { // TargetRef identifies the resource this policy is attached to. + // (will be translated to CEL later): + // - When Kind is Pod, Name MUST be Empty, Selector MUST be set, Max targetRef length is 1. + // - Otherwise multiple refs as long as Kind isn't Pod, selector MUST NOT be set // +kubebuilder:validation:Required TargetRefs []gatewayv1.PolicyTargetReferenceWithLabelSelectors `json:"targetRefs"` diff --git a/mkdocs.yml b/mkdocs.yml index 18393ce4c6..9bebb0378d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -136,6 +136,8 @@ nav: - geps/gep-91/index.md - geps/gep-3567/index.md - geps/gep-3949/index.md + - geps/gep-3793/index.md + - geps/gep-3779/index.md - Experimental: - geps/gep-1619/index.md - geps/gep-1713/index.md From 1391dd4ee990c3fd82fb1cc66a48596705f6e3a8 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Mon, 28 Jul 2025 17:30:28 +0000 Subject: [PATCH 10/15] formatting --- geps/gep-3779/index.md | 67 ++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 50f0fb0f09..8211da1896 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -13,7 +13,7 @@ Provide a method for configuring Gateway API Mesh implementations to enforce eas (Using the [Gateway API Personas](../../concepts/roles-and-personas.md)) -* A way for Ana the Application Developer to configure a Gateway API for Mesh implementation to enforce authorization policy that **allows** or **denies** identity or multiple identities to talk with some set (could be namespace or more granualr) of the workloads she controls. +* A way for Ana the Application Developer to configure a Gateway API for Mesh implementation to enforce authorization policy that **allows** identity or multiple identities to talk with some set (could be namespace or more granualr) of the workloads she controls. * A way for both Ana and Chihiro to restrict the scope of the policies they deploy to specific ports. @@ -29,7 +29,7 @@ Provide a method for configuring Gateway API Mesh implementations to enforce eas ## Deferred Goals -* (Potentially) Support enforcement on attributes beyond identities and ports. +* Support enforcement on attributes beyond identities and ports. ## Introduction @@ -39,7 +39,7 @@ Kubernetes core provides NetworkPolicies as one way to do it. Network Policies h * Network policies leverage labels as identities. * Labels are mutable at runtime. This opens a path for escalating privileges - * Most implementations of network policies translate labels to IPs, this involves an eventual consistency nature which can and has lea to over permissiveness in the past. + * Most implementations of network policies translate labels to IPs, this involves an eventual consistency nature which can and has led to over permissiveness in the past. * Scale. Network Policies are enforced using IPs (different selectors in the APIs get translated to IPs). This does not scale well with large clusters or beyond a single cluster @@ -60,11 +60,12 @@ An identity-based authorization API is essential because it provides a structure Every mesh vendor has their own API of such authorization. Below we describe brief UX for different implementations: #### Istio + For the full spec and sematics of Istio AuthorizationPolicy: [Istio authorization policy docs](https://istio.io/latest/docs/reference/config/security/authorization-policy/) Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated Serviceaccount identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. -``` +```yaml apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: @@ -83,7 +84,7 @@ spec: OR targeting a gateway for example. -``` +```yaml apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: @@ -100,6 +101,7 @@ spec: - source: principals: ["cluster.local/ns/default/sa/sleep"] ``` + #### Linkerd For the full spec and sematics of Linkerd AuthorizationPolicy: [Linkerd authorization policy docs](https://linkerd.io/2-edge/reference/authorization-policy/) @@ -110,7 +112,7 @@ Linkerd Policy can by applied to two different targets. ##### Pod Labels with Server Resource -``` +```yaml apiVersion: policy.linkerd.io/v1beta1 kind: Server metadata: @@ -154,7 +156,7 @@ spec: ##### HTTPRoutes -``` +```yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: @@ -173,7 +175,7 @@ spec: - name: httpbin port: 80 ------ +--- apiVersion: policy.linkerd.io/v1beta1 kind: MeshTLSAuthentication @@ -183,7 +185,7 @@ metadata: spec: identities: - sleep.default.serviceaccount.identity.linkerd.cluster.local ------ +--- apiVersion: policy.linkerd.io/v1beta1 kind: AuthorizationPolicy @@ -202,7 +204,6 @@ spec: --- ``` - #### Cilium For the full spec and sematics of CiliumNetworkPolicy: https://docs.cilium.io/en/stable/network/kubernetes/policy/#ciliumnetworkpolicy & https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#cilium-s-ingress-config-and-ciliumnetworkpolicy @@ -211,7 +212,7 @@ Beyond what's explained in the table above, Cilium also automatically labels eac See below for example. -``` +```yaml apiVersion: "cilium.io/v2" kind: CiliumNetworkPolicy metadata: @@ -234,13 +235,11 @@ spec: path: "/" ``` - ##### CiliumIdentity Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ - ## API This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (to begin with - `ALLOW`, and will likely add `DENY` in future iterations), and a set of rules that include sources (the “who”) and an optional port attribute. @@ -258,7 +257,7 @@ A rule may specify: * **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. -Note: This GEP is written as if DENY is also in scope, however, the GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. +Note: This GEP is written as if DENY is also in scope, however, GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. ### ALLOW Policies @@ -300,21 +299,25 @@ Before we are jumping into the options, lets start with some background. #### Ambient Meshes -* **Architecture**: Two-tier proxy system - * Node-L4-proxy: Handles identity-based policies and port enforcement - * L7 enforcement point (waypoint proxy): Handles advanced L7 features -* **Targeting**: - * Label selectors for node proxy distribution - * Service targetRef for L7 enforcement at waypoints - * **Constraint**: Selectors and targetRef cannot be used together + * **Architecture**: Two-tier proxy system + * Node-L4-proxy: Handles identity-based policies and port enforcement + * L7 enforcement point (waypoint proxy): Handles advanced L7 features + + * **Targeting**: + * Label selectors for node proxy distribution + * Service targetRef for L7 enforcement at waypoints + * **Constraint**: Selectors and targetRefs cannot be used together + + * **Enforcement Point**: When using label selectors, enforcement at the node-proxy, when targeting a Service, enforcement happens at the Waypoint delegate for that service. ### Key Challenges -1. **Architectural Differences**: Ambient meshes separate L4 and L7 enforcement, while sidecars handle both -2. **Targeting Mechanisms**: - * Ambient struggles with label selectors for L7 enforcement on waypoints ([#label-selectors-aren't-good-for-ambient-l7](#label-selectors-arent-good-for-ambient-l7)) - * Sidecars have difficulty supporting Service targeting for L7 enforcement ([#loss-of-service-context](#loss-of-service-context)) -3. **API Consistency**: Need a unified approach that works across all implementations + 1. **Architectural Differences**: Ambient meshes separate L4 and L7 enforcement, while sidecars handle both + 2. **Targeting Mechanisms**: + * Ambient struggles with label selectors for L7 enforcement on waypoints ([#label-selectors-aren't-good-for-ambient-l7](#label-selectors-arent-good-for-ambient-l7)) + * Sidecars have difficulty supporting Service targeting for L7 enforcement ([#loss-of-service-context](#loss-of-service-context)) + + 3. **API Consistency**: Need a unified approach that works across all implementations There a few options are available for `targetRef`. This GEP starts by specifying the recommendation, but you will **highly** benefit from going over the alternatives a few times and the detailed comparison at [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) to understand how we got to this recommendation. @@ -328,19 +331,19 @@ One unified authorization policy API with implementation-specific validation usi // // There are two enforcement levels: // -// - NETWORK: Enforces the policy at the network layer (L4), typically at +// - Network: Enforces the policy at the network layer (L4), typically at // network proxies or gateway dataplanes. Only supports attributes available // at connection time (e.g., source identity, port). Recommended for broad, // coarse-grained access controls. // -// - APPLICATION: Enforces the policy at the application layer (L7), typically at +// - Application: Enforces the policy at the application layer (L7), typically at // HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization // using protocol-specific attributes (e.g., HTTP paths, methods). // // This field clarifies policy intent and informs where enforcement is expected // to happen. It also enables implementation-specific validation and behavior. // -// +kubebuilder:validation:Enum=NETWORK;APPLICATION +// +kubebuilder:validation:Enum=Network;Application type EnforcementLevel string ``` @@ -351,7 +354,7 @@ kind: AuthorizationPolicy metadata: name: network-authz spec: - enforcementLevel: "network" # Enforced at L4 proxies + enforcementLevel: "Network" # Enforced at L4 proxies targetRef: kind: Pod selector: {} @@ -366,7 +369,7 @@ kind: AuthorizationPolicy metadata: name: app-authz spec: - enforcementLevel: "application" # Enforced at L7 proxies + enforcementLevel: "Application" # Enforced at L7 proxies targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. rules: - authorizationSource: @@ -696,7 +699,7 @@ type AuthorizationRule struct { // Fields may vary in applicability based on the protocol and implementation support. // // NOTE: ApplicationAttributes are only meaningful when `enforcementLevel` is set to - // APPLICATION. Implementations MUST ignore or reject these fields if used at NETWORK level. + // Application. Implementations MUST ignore or reject these fields if used at Network level. // +optional ApplicationAttributes *AuthorizationApplicationAttributes `json:"applicationAttributes,omitempty"` From a2499ca29fce3ba6a64beadcf67f67a3845415f7 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Mon, 28 Jul 2025 18:01:08 +0000 Subject: [PATCH 11/15] add guardrails --- geps/gep-3779/index.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 8211da1896..408f4426d1 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -795,18 +795,26 @@ type AuthorizationNetworkAttributes struct { Note: Existing AuthorizationAPIs recognized the need to support negation fields like `not{field}`. To avoid duplicating fields with negation, we plan to support richer match expressions for fields in `AuthorizationSource` such as `matchExpressions: { operator: In|NotIn, values: []}`. +## Graduation Criteria and Guardrails + +This GEP is starting as Experimental with X-prefix. We would like to define some guardrails to avoid being stuck with experimental api in the project forever. + +GEP is removed after 3 releases unless: + + 1. There is more than 1 implementation (implementations that are nearing completion can count here) + 2. There are conformance tests in place + +GEP is removed after 6 releases if it hasn't graduated to GA. + ## Conformance Details ### Feature Names Two new feature sets will be added - AuthorizationPolicyCoreFeatures, and later, AuthorizationPolicyExtendedFeatures. +AuthorizationPolicyExtendedFeatures features, if and when introduced, would likely have individual granularity, like AuthorizationPolicyDeny, AuthorizationPolicyHTTP, AuthorizationPolicyGRPC, etc. + TBD exact FeatureNames. ### Conformance tests - -## Alternatives - - -## References \ No newline at end of file From 9aa4019dd097fa2e76f42851cc4d3481310ec274 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 29 Jul 2025 13:49:40 +0000 Subject: [PATCH 12/15] organize the GEP --- geps/gep-3779/index.md | 950 ++++++++++++++++++++++------------------- 1 file changed, 510 insertions(+), 440 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 408f4426d1..000c159e19 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -17,16 +17,14 @@ Provide a method for configuring Gateway API Mesh implementations to enforce eas * A way for both Ana and Chihiro to restrict the scope of the policies they deploy to specific ports. -## TBD Goals +## Non-Goals + +* Support identity based authorization for north-south traffic or define the composition with this API. * A way for Chihiro, the Cluster Admin, to configure a Gateway API for Mesh implementation to enforce non-overridable cluster-wide, authorization policies that **allows** or **denies** identity or multiple identities to talk with some set of the workloads in the cluster. * A way for Chihiro, the Cluster Admin, to configure a Gateway API for Mesh implementation to enforce default, overridable, cluster-wide, authorization policies that **allows** or **denies** identity or multiple identities to talk with some set of the workloads in the cluster. -## Non-Goals - -* Support identity based authorization for north-south traffic or define the composition with this API. - ## Deferred Goals * Support enforcement on attributes beyond identities and ports. @@ -45,240 +43,40 @@ Kubernetes core provides NetworkPolicies as one way to do it. Network Policies h An identity-based authorization API is essential because it provides a structured way to control authorization between identities within the cluster. -### State of the World - -| Aspect | Istio | Linkerd | Cilium | -| ----- | ----- | ----- | ----- | -| **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | -| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference Serviceaccounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like Serviceaccounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| -| **Enforcement** | For Istio with sidecars - a proxy on each pod. For ambient, ztunnel node agent enforces mTLS based L4 authorization, L7 authorization is being enforced in waypoints if any.

Istio supports ALLOW, DENY, CUSTOM (often used for external authorization), and AUDIT. DENY policies in istio's context are used to enforce higher priority deny policies. The allow semantics is that whatever is not allowed explicitly (and assuming there is any policy for the same match) is implicitly denied | Linkerd data-plane proxy (injected into each pod). The proxy enforces policies via mTLS identity checks.

Linkerd supports AUDIT and ALLOW. There is not DENY policies, whats not allowed (and assuming there is any policy for the same match) is implicitly denied. | For L3/4 Ingress Rules, CiliumNetworkPolicy enforcement - an eBPF-based datapath in the Linux kernel on the destination node. If L7 http rules are specified, the packet is redirected for a node-local envoy for further enforcement.

Cilium supports ALLOW and DENY semantics - all policies generate audit logs.

Cilium service mesh also offers a kind of AuthN where a Cilium agent on the src node validates a workloads SPIFFE identity by talking to another agent on the destination node, performing the initial TLS handshake to do authentication.| -| **Request Match criteria** | Policies can target a group of pods using label selector, a Gateway/Service (this means targeting a waypoint proxy) or a GatewayClass - meaning all the gateways created from this class. Policies without a label selector in a namespace implies the whole namespace is targeted.

Fine-grained L7 and L4 matching: HTTP/gRPC methods, paths, headers, ports, SNI, etc.Policies use logical OR over rules.

All match criterias are inline in the policy. See https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-To and https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-when | Policies can target:
  • A `Server` which describes a set of pods (using fancy label match expressions), and a single port on those pods.
  • A user can optionally restrict the authorization to a smaller subset of the traffic by targeting an HTTPRoute. (TODO: any plans to support sectionNames?)
  • A namespace - this indicates that the policy applies to all traffic to all Servers and HTTPRoutes defined in the namespace.
Note: We leave `ServerAuthorization` outside the scope as it planned to be deprecated (per linkerd website) | Policies can target groups of pods using label selector (`endpointSelector`), or by node-labels (`nodeSelector`). Cilium supports L7 via built-in HTTP parsing: rules can match HTTP methods, paths, etc. For example, a CiliumNetworkPolicy can allow only specific HTTP methods/paths on a port. | -| **Default policies and admin policies** | If **no** ALLOW policy matches, traffic is **allowed** by default. You can deploy an overridable - default deny by default by deploying an **allow-nothing** policy in either the namespace or istio-system

AuthorizationPolicies in the `istio-system` namespace apply to the whole mesh and take precedence. These are not overridable by namespace-level policies. | Default inbound policy can be set at install time using `proxy.defaultInboundPolicy`. Supported values are:
  • `all-unauthenticated:` allow all traffic. This is the default.
  • `all-authenticated:` allow traffic from meshed clients in the same or from a different cluster (with multi-cluster).
  • `cluster-authenticated:` allow traffic from meshed clients in the same cluster.
  • `cluster-unauthenticated:` allow traffic from both meshed and non-meshed clients in the same cluster.
  • `deny:` all traffic are denied.
  • `audit:` Same as all-unauthenticated but requests get flagged in logs and metrics.

Users can override the default policies for namespaces/pods or by setting the [config.linkerd.io/default-inbound-policy](http://config.linkerd.io/default-inbound-policy) annotation There is no support for admin, non overridable policies. | Follows Kubernetes NetworkPolicy semantics by default: if no `CiliumNetworkPolicy` allows the traffic, it is allowed (no implicit deny). Once at least one `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` allows some traffic, all other traffic is implicitly denied. -

Operators must apply explicit deny rules or “default-deny” policies to block traffic in the absence of allow rules.

`CiliumClusterwideNetworkPolicy` exists for whole-cluster enforcement.)| - - -Every mesh vendor has their own API of such authorization. Below we describe brief UX for different implementations: - -#### Istio - -For the full spec and sematics of Istio AuthorizationPolicy: [Istio authorization policy docs](https://istio.io/latest/docs/reference/config/security/authorization-policy/) - -Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated Serviceaccount identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. - -```yaml -apiVersion: security.istio.io/v1beta1 -kind: AuthorizationPolicy -metadata: - name: allow-sleep - namespace: default -spec: - selector: - matchLabels: - app: httpbin # The policy applies to pods with this label - action: ALLOW - rules: - - from: - - source: - principals: ["cluster.local/ns/default/sa/sleep"] -``` - -OR targeting a gateway for example. - -```yaml -apiVersion: security.istio.io/v1beta1 -kind: AuthorizationPolicy -metadata: - name: allow-sleep - namespace: default -spec: - targetRefs: - - name: waypoint - kind: Gateway # note: supported target Refs are Gateway, GatewayClass, Service, and ServiceEntry - group: gateway.networking.k8s.io - action: ALLOW - rules: - - from: - - source: - principals: ["cluster.local/ns/default/sa/sleep"] -``` - -#### Linkerd - -For the full spec and sematics of Linkerd AuthorizationPolicy: [Linkerd authorization policy docs](https://linkerd.io/2-edge/reference/authorization-policy/) - -In Linkerd, identity-based authorization is enforced using AuthorizationPolicy and MeshTLSAuthentication, where MeshTLSAuthentication specifies allowed ServiceAccounts or mTLS identities (e.g., sleep.default.serviceaccount.identity.linkerd.cluster.local), ensuring that only authenticated workloads can access a resource. - -Linkerd Policy can by applied to two different targets. - -##### Pod Labels with Server Resource - -```yaml -apiVersion: policy.linkerd.io/v1beta1 -kind: Server -metadata: - namespace: default - name: httpbin-server -spec: - podSelector: - matchLabels: - app: httpbin - port: 8080 - proxyProtocol: HTTP/2 - ----- -apiVersion: policy.linkerd.io/v1beta1 -kind: MeshTLSAuthentication -metadata: - name: sleep-authn - namespace: default -spec: - identities: - - sleep.default.serviceaccount.identity.linkerd.cluster.local ----- - -apiVersion: policy.linkerd.io/v1beta1 -kind: AuthorizationPolicy -metadata: - name: allow-sleep - namespace: default -spec: - targetRef: - group: policy.linkerd.io - kind: Server - name: httpbin-server - requiredAuthenticationRefs: - - name: sleep-authn - kind: MeshTLSAuthentication - group: policy.linkerd.io/v1beta1 - ---- -``` - -##### HTTPRoutes - -```yaml -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: httpbin-route - namespace: default -spec: - parentRefs: - - name: httpbin - kind: Service - rules: - - matches: - - path: - type: PathPrefix - value: / - backendRefs: - - name: httpbin - port: 80 - ---- - -apiVersion: policy.linkerd.io/v1beta1 -kind: MeshTLSAuthentication -metadata: - name: sleep-authn - namespace: default -spec: - identities: - - sleep.default.serviceaccount.identity.linkerd.cluster.local ---- - -apiVersion: policy.linkerd.io/v1beta1 -kind: AuthorizationPolicy -metadata: - name: allow-sleep-http - namespace: default -spec: - targetRef: - group: gateway.networking.k8s.io - kind: HTTPRoute - name: httpbin-route - requiredAuthenticationRefs: - - name: sleep-authn - kind: MeshTLSAuthentication - group: policy.linkerd.io/v1beta1 ---- -``` - -#### Cilium - -For the full spec and sematics of CiliumNetworkPolicy: https://docs.cilium.io/en/stable/network/kubernetes/policy/#ciliumnetworkpolicy & https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#cilium-s-ingress-config-and-ciliumnetworkpolicy - -Beyond what's explained in the table above, Cilium also automatically labels each pod with its associated Serviceaccount using the label io.cilium.k8s.policy.serviceaccount. This label can be used in CiliumNetworkPolicy to enforce identity-based access controls using [ServiceAccounts Based Identities](https://docs.cilium.io/en/latest/security/policy/kubernetes/#serviceaccounts) within CiliumNetworkPolicy; - -See below for example. - -```yaml -apiVersion: "cilium.io/v2" -kind: CiliumNetworkPolicy -metadata: - name: "k8s-svc-account-policy" -spec: - endpointSelector: - matchLabels: - io.cilium.k8s.policy.serviceaccount: httpbin - ingress: - - fromEndpoints: - - matchLabels: - io.cilium.k8s.policy.serviceaccount: sleep - toPorts: - - ports: - - port: '80' - protocol: TCP - rules: - http: - - method: GET - path: "/" -``` - -##### CiliumIdentity -Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. +### Current AuthZ Support within Meshes -More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ +Istio, Linkerd, and Cilium all support identity-aware authorization via vendored policies, but differ in mechanics and philosophy. Istio and Linkerd rely on mTLS-derived identities tightly coupled with service accounts, while Cilium broadens the scope using BPF-based identities tied to labels, IPs, and SPIFFE. Istio offers policy layering (namespace/system-wide), including support for DENY and CUSTOM rules, enforced at sidecars or ztunnel/waypoints. Linkerd injects proxies, emphasizes mTLS, and supports ALLOW/AUDIT — there's no DENY. Cilium stands apart with L3–L7 policy enforcement (via kernel or envoy), and broader match targets including pod/node selectors and CIDRs. It also uniquely maps identities into the datapath ([#CiliumIdentity[#CiliumIdentity]]), and supports explicit default-deny enforcement patterns. See [#state-of-the-world](#state-of-the-world) for more detailed comparison. ## API This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (to begin with - `ALLOW`, and will likely add `DENY` in future iterations), and a set of rules that include sources (the “who”) and an optional port attribute. +This GEP has also a comprehensive Future Enhancement section to discuss L7 support within this policy. + ### Policy Rules Each `AuthorizationPolicy` resource contains a list of rules. A request matches the policy if it matches **any** rule in the list (logical OR). Each rule defines multiple matching criteria; a request matches a rule only if it matches **all** criteria within that rule (logical AND). A rule may specify: - * **Sources:** The source identities to which the rule applies. A request’s identity must match one of the listed sources. Supported source kinds are: + * **Sources:** The source identities to which the rule applies. A request’s identity must match one of the listed sources. Supported sources are: * **SPIFFE ID** - * **Kubernetes ServiceAccount** - * **Kubernetes Namespace** + * **Kubernetes ServiceAccount** (with the ability to specify a whole namespace) * **Attributes:** Conditions on the target workload, at the time of writing this, only port is supported. If no attributes are specified, the rule applies to all traffic toward the target. -Note: This GEP is written as if DENY is also in scope, however, GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. -### ALLOW Policies +### Policy Actions + +Note: GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. * An **ALLOW** policy is permissive. * A request is allowed if: - * It matches at least one rule in any ALLOW policy targeting the workload **and** - * It is not explicitly denied by any DENY policy. + * It matches at least one rule in any ALLOW policy targeting the workload * If no ALLOW policy exists for a workload, traffic is permitted by default. -### DENY Policies - -* A **DENY** policy is restrictive and takes precedence over ALLOW. -* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. -* DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). - -### ALLOW vs. DENY Semantics - -* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. -* The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. -* Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. +See [#ALLOW and DENY](#allow-and-deny-policies) for interaction with DENY and how above semantics is slightly changed with the presence of DENY policies. ### Target of Authorization @@ -288,16 +86,14 @@ The `targetRef` of the policy specifies the workload(s) to which the policy appl Before we are jumping into the options, lets start with some background. -#### Mesh Implementation Types - -#### Sidecar-Based Meshes +##### Sidecar-Based Meshes * **Architecture**: Sidecar proxy deployed alongside every pod * **Capabilities**: Can enforce all request attributes (L4 and L7) * **Targeting**: Uses label selectors to target sidecars for policy enforcement points (and destination) * **Enforcement Point**: Single enforcement point (the destination sidecar) -#### Ambient Meshes +##### Ambient Meshes * **Architecture**: Two-tier proxy system * Node-L4-proxy: Handles identity-based policies and port enforcement @@ -310,7 +106,7 @@ Before we are jumping into the options, lets start with some background. * **Enforcement Point**: When using label selectors, enforcement at the node-proxy, when targeting a Service, enforcement happens at the Waypoint delegate for that service. -### Key Challenges +##### Key Challenges 1. **Architectural Differences**: Ambient meshes separate L4 and L7 enforcement, while sidecars handle both 2. **Targeting Mechanisms**: @@ -319,203 +115,22 @@ Before we are jumping into the options, lets start with some background. 3. **API Consistency**: Need a unified approach that works across all implementations -There a few options are available for `targetRef`. This GEP starts by specifying the recommendation, but you will **highly** benefit from going over the alternatives a few times and the detailed comparison at [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) to understand how we got to this recommendation. +#### Label Selectors -#### Recommended Option - Hybrid TargetRef and VAP + +This GEP is focused on L4 only, for which LabelSelectors is widely supported, across all implementations. The future l7 enhancement gets into more background, complications, and recommended solution for incorporating L7 support to this policy. -One unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. +We add support for `LabelSelector` inside targetRef to allow targeting set of pods. -```go +**Benefits:** -// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. -// -// There are two enforcement levels: -// -// - Network: Enforces the policy at the network layer (L4), typically at -// network proxies or gateway dataplanes. Only supports attributes available -// at connection time (e.g., source identity, port). Recommended for broad, -// coarse-grained access controls. -// -// - Application: Enforces the policy at the application layer (L7), typically at -// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization -// using protocol-specific attributes (e.g., HTTP paths, methods). -// -// This field clarifies policy intent and informs where enforcement is expected -// to happen. It also enables implementation-specific validation and behavior. -// -// +kubebuilder:validation:Enum=Network;Application -type EnforcementLevel string +* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. +* Directly applies policy to pods, avoiding ambiguity present when targeting Services. Ensures policies are enforced exactly where intended, regardless of how many Services a pod might belong to. +* Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. -``` +**Downsides and Open Questions:** -```yaml -# Network-scoped policy (L4 enforcement points) -kind: AuthorizationPolicy -metadata: - name: network-authz -spec: - enforcementLevel: "Network" # Enforced at L4 proxies - targetRef: - kind: Pod - selector: {} - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - -# Application-scoped policy (L7-only enforcement points and sidecars) -kind: AuthorizationPolicy -metadata: - name: app-authz -spec: - enforcementLevel: "Application" # Enforced at L7 proxies - targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - applicationAttributes: - paths: ["/api/*"] - methods: ["GET", "POST"] - - -``` - -##### Mesh Implementation Behavior - -Sidecar Meshes - -* **Network Level**: Sidecar enforces policy but only uses L4 attributes -* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities - -Ambient Meshes - -* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting -* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting - -**VAP Validation**: - -* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) - * **Ambient**: Ensures application-level policies don't use label-selectors. - * **Both sidecar and ambient:** ensures network level policies **do** use label selectors - -Advantages - -* **Clear Intent**: Users explicitly state where they want enforcement -* **Flexible Targeting**: Different targetRef types for different enforcement points -* **Migration Path**: Users can start with network-level and upgrade to application-level easily -* **Implementation Alignment**: supporting different meshes architectures -* **Single API**: No duplication of schemas or concepts -* **Validation Clarity**: Clear rules about what's allowed at each level - -Disadvantages - -* **Complexity**: Users must understand enforcement levels -* **VAP Dependency**: Requires validation rules - - -#### Alternative 1: Targeting a Service - -The `targetRef` can point to a Kubernetes `Service`. - -Two implementation options when targeting a Service: - -1. Apply authorization policy to all traffic addressed to this Service. - -1. Apply authorization policy to all workloads (pods) selected by the Service. - -##### Benefits - -* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. -* **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. - -##### Downsides and Open Questions - -However, targeting a `Service` introduces several challenges; - -###### Loss Of Service Context - -If we go with option 1, apply authorization policy to all traffic addressed to a Service; - -This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. - -Here is the very high-level traffic flow for sidecar-based meshes: - - ```sh - Client → Request to backend-service:8080 - → Source sidecar resolves service → backend-pod-1 (>:8080) - → Destination sidecar receives traffic on pod IP - → Destination sidecar has NO context that this came via "backend-service" - ``` - -Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. - -##### A Workload is Part of Multiple Services - -Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. - -If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. For example we _could_ apply the following algorithm: - -```sh -## Algorithm -For traffic to workload W: -1. Collect all Service-targeted AuthorizationPolicies where Service.selector matches W.labels -2. If no policies collected → Allow (default behavior) -3. If policies collected → Evaluate using union semantics - - -## Union semantics: -1. For each DENY policy: if request matches → DENY immediately -2. For each ALLOW policy: collect matching rules -3. If any ALLOW rule matches → ALLOW -4. Otherwise → DENY -``` - -##### Enforcement & Consistency - -Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. - -The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. - -The UX gets weird because even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. - -> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Service are completely out of scope. - -#### Alternative 2: Targeting xRoutes - -The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. - -We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which Service was dialed, we don't have the route information that was responsible for the routing. - -> Note: Linkerd solved this with [Reusing HTTPRoute Schema](https://linkerd.io/2.15/features/httproute/) to distinguish between Inbound and Outbound HTTPRoute. However, I doubt we want that as a community feature. (sorry @kflynn) - -Another (perhaps, easier-to-address) concern is that if we target xRoutes, it is likely that users would expect this Authorization to work for N/S traffic. Documentation and guidance are nice, but I think this still ends up more confusing for no real value. - -#### Alternative 3: Targeting Pods via Label Selectors - -Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. - -**Benefits:** - -* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. -* Directly applies policy to pods, avoiding ambiguity present when targeting Services. Ensures policies are enforced exactly where intended, regardless of how many Services a pod might belong to. -* Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. - -**Downsides and Open Questions:** - -##### Label-Selectors aren't Good for Ambient L7 - -In L7 Ambient, AuthorizationPolicy targets a Service. This Service has to have a waypoint proxy. The policy enforcement point is the waypoint, but it is also the point where the Service VIP resolution happens. - -If we were to target Label Selectors, the waypoint proxy would get the request, do VIP resolution and select an endpoint, and then it would require round-tripping to itself for doing policy enforcement. - -@howardjohn has actually added that this was actually the first way ambient had implemented authorization, but it has proved to be much less performant. - -##### Discoverability Challenge - -The additional (and main) downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See below for more info. +The main downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See below for more info. **Requirement: Enhancing Policy Attachment:** @@ -559,6 +174,29 @@ type PolicyTargetReferenceWithLabelSelectors struct { ``` +##### Enhanced Discoverability with `gwctl` + +A key challenge with `LabelSelector` is the loss of discoverability. It’s easier to see which policies target a `Service` but difficult to determine which policies might affect a specific pod. + +To address this, **investment in tooling is required.** Specifically, the `gwctl` CLI tool should be enhanced to provide insights such as: + +```sh +gwctl describe pods pod1 + +... +InheritedPolicies: + Type Name Target Kind Target Name/Expression + ---- ---- ----------- ----------- + AuthorizationPolicy demo-authz-policy-on-payment-pods Pod Selector={foo: a, bar: 2} +... + +# List all AuthorizationPolicy resources in json format in the active namespace +gwctl get authorizationPolicy -o json + +``` + +Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. + ##### Namespace-Wide Policies A common case for authorization is to target a whole namespace. We can achieve the above with a few patterns: @@ -603,29 +241,38 @@ targetRefs: - { key: "purpose", operator: NotIn, values: ["gateway"] } ``` -##### Enhanced Discoverability with `gwctl` - -A key challenge with `LabelSelector` is the loss of discoverability. It’s easier to see which policies target a `Service` but difficult to determine which policies might affect a specific pod. +##### New EnforcementLevel Enum -To address this, **investment in tooling is required.** Specifically, the `gwctl` CLI tool should be enhanced to provide insights such as: +To mitigate the challenges L7 support across dataplanes is going to present, and to encourage policy authors to be more explicit, we introduce a new EnforcementLevel Enum. -```sh -gwctl describe pods pod1 +We start by only support the Network value, and Application is kept for future iteration. -... -InheritedPolicies: - Type Name Target Kind Target Name/Expression - ---- ---- ----------- ----------- - AuthorizationPolicy demo-authz-policy-on-payment-pods Pod Selector={foo: a, bar: 2} -... +Note: The whole point of this Enum is to encourage explicitness, we **do not** want to start without it and default to Network if and when introduced later. -# List all AuthorizationPolicy resources in json format in the active namespace -gwctl get authorizationPolicy -o json +```go +// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. +// +// There are two enforcement levels: +// +// - Network: Enforces the policy at the network layer (L4), typically at +// network proxies or gateway dataplanes. Only supports attributes available +// at connection time (e.g., source identity, port). Recommended for broad, +// coarse-grained access controls. +// +// NOTE FOR REVIEWRS -- THIS IS FOR FUTURE ENHANCEMENT +// +// - Application: Enforces the policy at the application layer (L7), typically at +// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization +// using protocol-specific attributes (e.g., HTTP paths, methods). +// +// This field clarifies policy intent and informs where enforcement is expected +// to happen. It also enables implementation-specific validation and behavior. +// +// +kubebuilder:validation:Enum=Network;Application +type EnforcementLevel string ``` -Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. - ### API Design ```go @@ -795,26 +442,449 @@ type AuthorizationNetworkAttributes struct { Note: Existing AuthorizationAPIs recognized the need to support negation fields like `not{field}`. To avoid duplicating fields with negation, we plan to support richer match expressions for fields in `AuthorizationSource` such as `matchExpressions: { operator: In|NotIn, values: []}`. -## Graduation Criteria and Guardrails -This GEP is starting as Experimental with X-prefix. We would like to define some guardrails to avoid being stuck with experimental api in the project forever. +## Future Enhancements -GEP is removed after 3 releases unless: +### ALLOW and Deny Policies - 1. There is more than 1 implementation (implementations that are nearing completion can count here) - 2. There are conformance tests in place +#### ALLOW Policy -GEP is removed after 6 releases if it hasn't graduated to GA. + * An **ALLOW** policy is permissive. + * A request is allowed if: + * It matches at least one rule in any ALLOW policy targeting the workload **and** + * It is not explicitly denied by any DENY policy. -## Conformance Details + * If no ALLOW policy exists for a workload, traffic is permitted by default. -### Feature Names +#### DENY Policies -Two new feature sets will be added - AuthorizationPolicyCoreFeatures, and later, AuthorizationPolicyExtendedFeatures. +* A **DENY** policy is restrictive and takes precedence over ALLOW. +* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. +* DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). -AuthorizationPolicyExtendedFeatures features, if and when introduced, would likely have individual granularity, like AuthorizationPolicyDeny, AuthorizationPolicyHTTP, AuthorizationPolicyGRPC, etc. +#### ALLOW vs. DENY Semantics -TBD exact FeatureNames. +* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. +* The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. +* Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. -### Conformance tests +### Future L7 Support + +There a few options are available for `targetRef`. This GEP starts by specifying the recommendation, but you will **highly** benefit from going over the alternatives a few times and the detailed comparison at [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) to understand how we got to this recommendation. + +#### Recommended Option - Hybrid TargetRef and VAP + +One unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. + +```go +// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. +// +// There are two enforcement levels: +// +// - Network: Enforces the policy at the network layer (L4), typically at +// network proxies or gateway dataplanes. Only supports attributes available +// at connection time (e.g., source identity, port). Recommended for broad, +// coarse-grained access controls. +// +// - Application: Enforces the policy at the application layer (L7), typically at +// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization +// using protocol-specific attributes (e.g., HTTP paths, methods). +// +// This field clarifies policy intent and informs where enforcement is expected +// to happen. It also enables implementation-specific validation and behavior. +// +// +kubebuilder:validation:Enum=Network;Application +type EnforcementLevel string + +``` + +```yaml +# Network-scoped policy (L4 enforcement points) +kind: AuthorizationPolicy +metadata: + name: network-authz +spec: + enforcementLevel: "Network" # Enforced at L4 proxies + targetRef: + kind: Pod + selector: {} + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + networkAttributes: + ports: [9080] + +# Application-scoped policy (L7-only enforcement points and sidecars) +kind: AuthorizationPolicy +metadata: + name: app-authz +spec: + enforcementLevel: "Application" # Enforced at L7 proxies + targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. + rules: + - authorizationSource: + serviceAccount: ["default/productpage"] + networkAttributes: + ports: [9080] + applicationAttributes: + paths: ["/api/*"] + methods: ["GET", "POST"] + + +``` + +##### Mesh Implementation Behavior + +Sidecar Meshes + +* **Network Level**: Sidecar enforces policy but only uses L4 attributes +* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities + +Ambient Meshes + +* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting +* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting + +**VAP Validation**: + +* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) + * **Ambient**: Ensures application-level policies don't use label-selectors. + * **Both sidecar and ambient:** ensures network level policies **do** use label selectors + +Advantages + +* **Clear Intent**: Users explicitly state where they want enforcement +* **Flexible Targeting**: Different targetRef types for different enforcement points +* **Migration Path**: Users can start with network-level and upgrade to application-level easily +* **Implementation Alignment**: supporting different meshes architectures +* **Single API**: No duplication of schemas or concepts +* **Validation Clarity**: Clear rules about what's allowed at each level + +Disadvantages + +* **Complexity**: Users must understand enforcement levels +* **VAP Dependency**: Requires validation rules + + +#### Alternative 1: Targeting a Service + +The `targetRef` can point to a Kubernetes `Service`. + +Two implementation options when targeting a Service: + +1. Apply authorization policy to all traffic addressed to this Service. + +1. Apply authorization policy to all workloads (pods) selected by the Service. + +##### Benefits + +* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. +* **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. + +##### Downsides and Open Questions + +However, targeting a `Service` introduces several challenges; + +###### Loss Of Service Context + +If we go with option 1, apply authorization policy to all traffic addressed to a Service; + +This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. + +Here is the very high-level traffic flow for sidecar-based meshes: + + ```sh + Client → Request to backend-service:8080 + → Source sidecar resolves service → backend-pod-1 (>:8080) + → Destination sidecar receives traffic on pod IP + → Destination sidecar has NO context that this came via "backend-service" + ``` + +Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. + +##### A Workload is Part of Multiple Services + +Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. + +If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. For example we _could_ apply the following algorithm: + +```sh +## Algorithm +For traffic to workload W: +1. Collect all Service-targeted AuthorizationPolicies where Service.selector matches W.labels +2. If no policies collected → Allow (default behavior) +3. If policies collected → Evaluate using union semantics + + +## Union semantics: +1. For each DENY policy: if request matches → DENY immediately +2. For each ALLOW policy: collect matching rules +3. If any ALLOW rule matches → ALLOW +4. Otherwise → DENY +``` + +##### Enforcement & Consistency + +Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. + +The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. + +The UX gets weird because even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. + +> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Service are completely out of scope. + +#### Alternative 2: Targeting xRoutes + +The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. + +We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which Service was dialed, we don't have the route information that was responsible for the routing. + +> Note: Linkerd solved this with [Reusing HTTPRoute Schema](https://linkerd.io/2.15/features/httproute/) to distinguish between Inbound and Outbound HTTPRoute. However, I doubt we want that as a community feature. (sorry @kflynn) + +Another (perhaps, easier-to-address) concern is that if we target xRoutes, it is likely that users would expect this Authorization to work for N/S traffic. Documentation and guidance are nice, but I think this still ends up more confusing for no real value. + +#### Alternative 3: Targeting Pods via Label Selectors + +Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. + +**Benefits:** + +* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. +* Directly applies policy to pods, avoiding ambiguity present when targeting Services. Ensures policies are enforced exactly where intended, regardless of how many Services a pod might belong to. +* Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. + +**Downsides and Open Questions:** + +##### Label-Selectors aren't Good for Ambient L7 + +In L7 Ambient, AuthorizationPolicy targets a Service. This Service has to have a waypoint proxy. The policy enforcement point is the waypoint, but it is also the point where the Service VIP resolution happens. + +If we were to target Label Selectors, the waypoint proxy would get the request, do VIP resolution and select an endpoint, and then it would require round-tripping to itself for doing policy enforcement. + +@howardjohn has actually added that this was actually the first way ambient had implemented authorization, but it has proved to be much less performant. + +##### Discoverability Challenge + +The additional (and main) downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See more in [#Enhanced Discoverability with `gwctl`](#enhanced-discoverability-with-gwctl) for more info. + + +## Graduation Criteria and Guardrails + +This GEP is starting as Experimental with X-prefix. We would like to define some guardrails to avoid being stuck with experimental api in the project forever. + +GEP is removed after 3 releases unless: + + 1. There is more than 1 implementation (implementations that are nearing completion can count here) + 2. There are conformance tests in place + +GEP is removed after 6 releases if it hasn't graduated to GA. + +## Conformance Details + +### Feature Names + +Two new feature sets will be added - AuthorizationPolicyCoreFeatures, and later, AuthorizationPolicyExtendedFeatures. + +AuthorizationPolicyExtendedFeatures features, if and when introduced, would likely have individual granularity, like AuthorizationPolicyDeny, AuthorizationPolicyHTTP, AuthorizationPolicyGRPC, etc. + +TBD exact FeatureNames. + +### Conformance tests + +## Appendix + +### State of the World + +| Aspect | Istio | Linkerd | Cilium | +| ----- | ----- | ----- | ----- | +| **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | +| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference Serviceaccounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like Serviceaccounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| +| **Enforcement** | For Istio with sidecars - a proxy on each pod. For ambient, ztunnel node agent enforces mTLS based L4 authorization, L7 authorization is being enforced in waypoints if any.

Istio supports ALLOW, DENY, CUSTOM (often used for external authorization), and AUDIT. DENY policies in istio's context are used to enforce higher priority deny policies. The allow semantics is that whatever is not allowed explicitly (and assuming there is any policy for the same match) is implicitly denied | Linkerd data-plane proxy (injected into each pod). The proxy enforces policies via mTLS identity checks.

Linkerd supports AUDIT and ALLOW. There is not DENY policies, whats not allowed (and assuming there is any policy for the same match) is implicitly denied. | For L3/4 Ingress Rules, CiliumNetworkPolicy enforcement - an eBPF-based datapath in the Linux kernel on the destination node. If L7 http rules are specified, the packet is redirected for a node-local envoy for further enforcement.

Cilium supports ALLOW and DENY semantics - all policies generate audit logs.

Cilium service mesh also offers a kind of AuthN where a Cilium agent on the src node validates a workloads SPIFFE identity by talking to another agent on the destination node, performing the initial TLS handshake to do authentication.| +| **Request Match criteria** | Policies can target a group of pods using label selector, a Gateway/Service (this means targeting a waypoint proxy) or a GatewayClass - meaning all the gateways created from this class. Policies without a label selector in a namespace implies the whole namespace is targeted.

Fine-grained L7 and L4 matching: HTTP/gRPC methods, paths, headers, ports, SNI, etc.Policies use logical OR over rules.

All match criterias are inline in the policy. See https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-To and https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-when | Policies can target:
  • A `Server` which describes a set of pods (using fancy label match expressions), and a single port on those pods.
  • A user can optionally restrict the authorization to a smaller subset of the traffic by targeting an HTTPRoute. (TODO: any plans to support sectionNames?)
  • A namespace - this indicates that the policy applies to all traffic to all Servers and HTTPRoutes defined in the namespace.
Note: We leave `ServerAuthorization` outside the scope as it planned to be deprecated (per linkerd website) | Policies can target groups of pods using label selector (`endpointSelector`), or by node-labels (`nodeSelector`). Cilium supports L7 via built-in HTTP parsing: rules can match HTTP methods, paths, etc. For example, a CiliumNetworkPolicy can allow only specific HTTP methods/paths on a port. | +| **Default policies and admin policies** | If **no** ALLOW policy matches, traffic is **allowed** by default. You can deploy an overridable - default deny by default by deploying an **allow-nothing** policy in either the namespace or istio-system

AuthorizationPolicies in the `istio-system` namespace apply to the whole mesh and take precedence. These are not overridable by namespace-level policies. | Default inbound policy can be set at install time using `proxy.defaultInboundPolicy`. Supported values are:
  • `all-unauthenticated:` allow all traffic. This is the default.
  • `all-authenticated:` allow traffic from meshed clients in the same or from a different cluster (with multi-cluster).
  • `cluster-authenticated:` allow traffic from meshed clients in the same cluster.
  • `cluster-unauthenticated:` allow traffic from both meshed and non-meshed clients in the same cluster.
  • `deny:` all traffic are denied.
  • `audit:` Same as all-unauthenticated but requests get flagged in logs and metrics.

Users can override the default policies for namespaces/pods or by setting the [config.linkerd.io/default-inbound-policy](http://config.linkerd.io/default-inbound-policy) annotation There is no support for admin, non overridable policies. | Follows Kubernetes NetworkPolicy semantics by default: if no `CiliumNetworkPolicy` allows the traffic, it is allowed (no implicit deny). Once at least one `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` allows some traffic, all other traffic is implicitly denied. +

Operators must apply explicit deny rules or “default-deny” policies to block traffic in the absence of allow rules.

`CiliumClusterwideNetworkPolicy` exists for whole-cluster enforcement.)| + + +Every mesh vendor has their own API of such authorization. Below we describe brief UX for different implementations: + +#### Istio + +For the full spec and sematics of Istio AuthorizationPolicy: [Istio authorization policy docs](https://istio.io/latest/docs/reference/config/security/authorization-policy/) + +Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated Serviceaccount identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. + +```yaml +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + selector: + matchLabels: + app: httpbin # The policy applies to pods with this label + action: ALLOW + rules: + - from: + - source: + principals: ["cluster.local/ns/default/sa/sleep"] +``` + +OR targeting a gateway for example. + +```yaml +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + targetRefs: + - name: waypoint + kind: Gateway # note: supported target Refs are Gateway, GatewayClass, Service, and ServiceEntry + group: gateway.networking.k8s.io + action: ALLOW + rules: + - from: + - source: + principals: ["cluster.local/ns/default/sa/sleep"] +``` + +#### Linkerd + +For the full spec and sematics of Linkerd AuthorizationPolicy: [Linkerd authorization policy docs](https://linkerd.io/2-edge/reference/authorization-policy/) + +In Linkerd, identity-based authorization is enforced using AuthorizationPolicy and MeshTLSAuthentication, where MeshTLSAuthentication specifies allowed ServiceAccounts or mTLS identities (e.g., sleep.default.serviceaccount.identity.linkerd.cluster.local), ensuring that only authenticated workloads can access a resource. + +Linkerd Policy can by applied to two different targets. + +##### Pod Labels with Server Resource + +```yaml +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: default + name: httpbin-server +spec: + podSelector: + matchLabels: + app: httpbin + port: 8080 + proxyProtocol: HTTP/2 + +---- +apiVersion: policy.linkerd.io/v1beta1 +kind: MeshTLSAuthentication +metadata: + name: sleep-authn + namespace: default +spec: + identities: + - sleep.default.serviceaccount.identity.linkerd.cluster.local +---- + +apiVersion: policy.linkerd.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + targetRef: + group: policy.linkerd.io + kind: Server + name: httpbin-server + requiredAuthenticationRefs: + - name: sleep-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io/v1beta1 + +--- +``` + +##### HTTPRoutes + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: httpbin-route + namespace: default +spec: + parentRefs: + - name: httpbin + kind: Service + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: httpbin + port: 80 + +--- + +apiVersion: policy.linkerd.io/v1beta1 +kind: MeshTLSAuthentication +metadata: + name: sleep-authn + namespace: default +spec: + identities: + - sleep.default.serviceaccount.identity.linkerd.cluster.local +--- + +apiVersion: policy.linkerd.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep-http + namespace: default +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httpbin-route + requiredAuthenticationRefs: + - name: sleep-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io/v1beta1 +--- +``` + +#### Cilium + +For the full spec and sematics of CiliumNetworkPolicy: https://docs.cilium.io/en/stable/network/kubernetes/policy/#ciliumnetworkpolicy & https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#cilium-s-ingress-config-and-ciliumnetworkpolicy + +Beyond what's explained in the table above, Cilium also automatically labels each pod with its associated Serviceaccount using the label io.cilium.k8s.policy.serviceaccount. This label can be used in CiliumNetworkPolicy to enforce identity-based access controls using [ServiceAccounts Based Identities](https://docs.cilium.io/en/latest/security/policy/kubernetes/#serviceaccounts) within CiliumNetworkPolicy; + +See below for example. + +```yaml +apiVersion: "cilium.io/v2" +kind: CiliumNetworkPolicy +metadata: + name: "k8s-svc-account-policy" +spec: + endpointSelector: + matchLabels: + io.cilium.k8s.policy.serviceaccount: httpbin + ingress: + - fromEndpoints: + - matchLabels: + io.cilium.k8s.policy.serviceaccount: sleep + toPorts: + - ports: + - port: '80' + protocol: TCP + rules: + http: + - method: GET + path: "/" +``` + +##### CiliumIdentity +Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. + +More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ From c81d714cd3331899b9dfcd0e277df8ebea19982e Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 6 Aug 2025 00:41:44 +0000 Subject: [PATCH 13/15] remove l7 and deny language from the gep --- geps/gep-3779/index.md | 285 ++++++----------------------------------- 1 file changed, 37 insertions(+), 248 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 000c159e19..38ce8a16e8 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -68,7 +68,7 @@ A rule may specify: ### Policy Actions -Note: GAMMA leads met on 24th July 2025, and agreed that DENY is likely going to be pushed to 1.5 and will _potentially_ be "extended" conformance. +Note: GAMMA leads met on 24th July 2025, and agreed that DENY is not going to be in scope for the initial iteration and will _potentially_ be added later. * An **ALLOW** policy is permissive. * A request is allowed if: @@ -289,17 +289,12 @@ type AuthorizationPolicy struct { } // AuthorizationPolicyAction specifies the action to take. -// +kubebuilder:validation:Enum=ALLOW;DENY +// +kubebuilder:validation:Enum=ALLOW type AuthorizationPolicyAction string const ( // ActionAllow allows requests that match the policy rules. ActionAllow AuthorizationPolicyAction = "ALLOW" - - // NOTE FOR REVIEWERS AGAIN: GAMMA leads met on 24th July and DENY action is likely going to be pushed to 1.5 and will potentially be extended conformance. - - // ActionDeny denies requests that match the policy rules. - ActionDeny AuthorizationPolicyAction = "DENY" ) // AuthorizationPolicySpec defines the desired state of AuthorizationPolicy. @@ -324,40 +319,23 @@ type AuthorizationPolicySpec struct { // AuthorizationRule defines a single authorization rule. // A request matches the rule if it matches ALL fields specified. type AuthorizationRule struct { - // AuthorizationSource specifies who is making the request. + // Source specifies who is making the request. // If omitted, matches any source. // +optional - AuthorizationSource *AuthorizationSource `json:"authorizationSource,omitempty"` + Source *AuthorizationSource `json:"source,omitempty"` // NetworkAttributes specifies TCP-level matching criteria. // If omitted, matches any TCP traffic. // +optional NetworkAttributes *AuthorizationNetworkAttributes `json:"networkAttributes,omitempty"` - - // FOR FUTURE ENHANCEMENT!! - - // ApplicationAttributes defines optional application-layer (L7) matching criteria - // used to authorize requests when enforcement is at the APPLICATION level. - // - // All specified fields must match for the rule to apply (logical AND). If omitted, - // the rule matches all application-layer traffic. - // - // Typical use cases include protocol-aware authorization for HTTP, gRPC, or other L7 traffic. - // Fields may vary in applicability based on the protocol and implementation support. - // - // NOTE: ApplicationAttributes are only meaningful when `enforcementLevel` is set to - // Application. Implementations MUST ignore or reject these fields if used at Network level. - - // +optional - ApplicationAttributes *AuthorizationApplicationAttributes `json:"applicationAttributes,omitempty"` } -// AuthorizationSource specifies the source of a request. +// Source specifies the source of a request. // // At least one field may be set. If multiple fields are set, -// a request matches this AuthorizationSource if it matches +// a request matches this Source if it matches // **any** of the specified criteria (logical OR across fields). // // For example, if both `Identities` and `ServiceAccounts` are provided, @@ -373,7 +351,7 @@ type AuthorizationRule struct { // logical conditions (e.g. requiring a request to match multiple // criteria simultaneously—logical AND), we may evolve this API // to support richer match expressions or logical operators. -type AuthorizationSource struct { +type Source struct { // Identities specifies a list of identities that are matched by this rule. // A request's identity must be present in this list to match the rule. @@ -445,229 +423,13 @@ Note: Existing AuthorizationAPIs recognized the need to support negation fields ## Future Enhancements -### ALLOW and Deny Policies +### DENY Policies -#### ALLOW Policy - - * An **ALLOW** policy is permissive. - * A request is allowed if: - * It matches at least one rule in any ALLOW policy targeting the workload **and** - * It is not explicitly denied by any DENY policy. - - * If no ALLOW policy exists for a workload, traffic is permitted by default. - -#### DENY Policies - -* A **DENY** policy is restrictive and takes precedence over ALLOW. -* If a request matches any rule in a DENY policy, it is immediately rejected, regardless of matching ALLOW rules elsewhere. -* DENY policies enable to define global blocks or exceptions (for example: “block all traffic from Namespace X”). - -#### ALLOW vs. DENY Semantics - -* **DENY always wins.** If both an ALLOW and a DENY policy match a request, the DENY policy blocks it. -* The presence of any authorization policy causes the system to default to **deny-by-default** for matching workloads. -* Another bullet to re-clarify the one above - the default behavior when no policies select a target workload is to allow all traffic. However, **as soon as at least one `AuthorizationPolicy` targets a workload, the model becomes implicitly deny-if-not-allowed**. +We start without DENY policies in scope, DENY policies _may_ be added in future iterations. ### Future L7 Support -There a few options are available for `targetRef`. This GEP starts by specifying the recommendation, but you will **highly** benefit from going over the alternatives a few times and the detailed comparison at [https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0](https://docs.google.com/document/d/1CeagBnHDPbzpYAxBmtJqTshxAW8l-aRPwvwgAGbnv2I/edit?tab=t.0) to understand how we got to this recommendation. - -#### Recommended Option - Hybrid TargetRef and VAP - -One unified authorization policy API with implementation-specific validation using Validating Admission Policies (VAP). Additionally introducing a new `enforcementLevel` enum to simplify validation and enable the user to clarify intent. - -```go - -// EnforcementLevel defines the scope at which an AuthorizationPolicy is enforced. -// -// There are two enforcement levels: -// -// - Network: Enforces the policy at the network layer (L4), typically at -// network proxies or gateway dataplanes. Only supports attributes available -// at connection time (e.g., source identity, port). Recommended for broad, -// coarse-grained access controls. -// -// - Application: Enforces the policy at the application layer (L7), typically at -// HTTP/gRPC-aware sidecars or L7 proxies. Enables fine-grained authorization -// using protocol-specific attributes (e.g., HTTP paths, methods). -// -// This field clarifies policy intent and informs where enforcement is expected -// to happen. It also enables implementation-specific validation and behavior. -// -// +kubebuilder:validation:Enum=Network;Application -type EnforcementLevel string - -``` - -```yaml -# Network-scoped policy (L4 enforcement points) -kind: AuthorizationPolicy -metadata: - name: network-authz -spec: - enforcementLevel: "Network" # Enforced at L4 proxies - targetRef: - kind: Pod - selector: {} - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - -# Application-scoped policy (L7-only enforcement points and sidecars) -kind: AuthorizationPolicy -metadata: - name: app-authz -spec: - enforcementLevel: "Application" # Enforced at L7 proxies - targetRef: # Service for Ambient implementations, label-selector for sidecar implementations. - rules: - - authorizationSource: - serviceAccount: ["default/productpage"] - networkAttributes: - ports: [9080] - applicationAttributes: - paths: ["/api/*"] - methods: ["GET", "POST"] - - -``` - -##### Mesh Implementation Behavior - -Sidecar Meshes - -* **Network Level**: Sidecar enforces policy but only uses L4 attributes -* **Application Level**: Sidecar enforces policy with full L4+L7 capabilities - -Ambient Meshes - -* **Network Level**: Node-L4-proxy enforces policy using labelSelector targeting -* **Application Level**: Waypoint proxy enforces policy using Service targetRef targeting - -**VAP Validation**: - -* **Sidecar mesh**: Ensures application-level policies don't use targetRef: Service (since sidecars use labelSelector) - * **Ambient**: Ensures application-level policies don't use label-selectors. - * **Both sidecar and ambient:** ensures network level policies **do** use label selectors - -Advantages - -* **Clear Intent**: Users explicitly state where they want enforcement -* **Flexible Targeting**: Different targetRef types for different enforcement points -* **Migration Path**: Users can start with network-level and upgrade to application-level easily -* **Implementation Alignment**: supporting different meshes architectures -* **Single API**: No duplication of schemas or concepts -* **Validation Clarity**: Clear rules about what's allowed at each level - -Disadvantages - -* **Complexity**: Users must understand enforcement levels -* **VAP Dependency**: Requires validation rules - - -#### Alternative 1: Targeting a Service - -The `targetRef` can point to a Kubernetes `Service`. - -Two implementation options when targeting a Service: - -1. Apply authorization policy to all traffic addressed to this Service. - -1. Apply authorization policy to all workloads (pods) selected by the Service. - -##### Benefits - -* **No API Extension Required:** Works with the current PolicyAttachment model in Gateway API without modification. -* **Simplicity:** Intuitive for users familiar with Kubernetes networking concepts. - -##### Downsides and Open Questions - -However, targeting a `Service` introduces several challenges; - -###### Loss Of Service Context - -If we go with option 1, apply authorization policy to all traffic addressed to a Service; - -This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. - -Here is the very high-level traffic flow for sidecar-based meshes: - - ```sh - Client → Request to backend-service:8080 - → Source sidecar resolves service → backend-pod-1 (>:8080) - → Destination sidecar receives traffic on pod IP - → Destination sidecar has NO context that this came via "backend-service" - ``` - -Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. - -##### A Workload is Part of Multiple Services - -Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. - -If a Pod belongs to multiple Services targeted by different authorization policies, precedence rules, may become unclear, leading to unpredictable or insecure outcomes. Even if such rules are explicitly defined, UX could potentially be confusing for users. For example we _could_ apply the following algorithm: - -```sh -## Algorithm -For traffic to workload W: -1. Collect all Service-targeted AuthorizationPolicies where Service.selector matches W.labels -2. If no policies collected → Allow (default behavior) -3. If policies collected → Evaluate using union semantics - - -## Union semantics: -1. For each DENY policy: if request matches → DENY immediately -2. For each ALLOW policy: collect matching rules -3. If any ALLOW rule matches → ALLOW -4. Otherwise → DENY -``` - -##### Enforcement & Consistency - -Assuming we go with option 2, apply authorization policy to all workloads (pods) selected by the Service. - -The UX becomes very confusing. Are we going to enforce only if the traffic arrived through the specific Service? Probably not, cause then we are back to the first problem of Service context. - -The UX gets weird because even though you target a Service, you essentially get a **workload** policy, thats enforced regardless. - -> Note: with Service as a targetRef, of course we are going to need a Service in order to enforce Authorization -- meaning pods/jobs without a Service are completely out of scope. - -#### Alternative 2: Targeting xRoutes - -The main benefit of this option is that we can more easily scope the authorization enforcement only for "GAMMA" traffic. Whether its more or less confusing is still unclear. - -We can target xRoutes (TCPRoute, HTTPRoute, GRPCRoute). However we are back to [Loss Of Service Context](#loss-of-service-context). In sidecar mode, same as we don't have the context of which Service was dialed, we don't have the route information that was responsible for the routing. - -> Note: Linkerd solved this with [Reusing HTTPRoute Schema](https://linkerd.io/2.15/features/httproute/) to distinguish between Inbound and Outbound HTTPRoute. However, I doubt we want that as a community feature. (sorry @kflynn) - -Another (perhaps, easier-to-address) concern is that if we target xRoutes, it is likely that users would expect this Authorization to work for N/S traffic. Documentation and guidance are nice, but I think this still ends up more confusing for no real value. - -#### Alternative 3: Targeting Pods via Label Selectors - -Alternatively, the `targetRef` can specify a set of pods using a `LabelSelector` for a more flexible and direct approach. - -**Benefits:** - -* Aligns with established practices. Mesh implementations (Istio, Linkerd, Cilium) already use label selectors as the primary mechanism for targeting workloads in their native authorization policies, creating a consistent user experience. -* Directly applies policy to pods, avoiding ambiguity present when targeting Services. Ensures policies are enforced exactly where intended, regardless of how many Services a pod might belong to. -* Policies can apply to any workload, including pods not exposed via a `Service`, providing a comprehensive authorization solution. - -**Downsides and Open Questions:** - -##### Label-Selectors aren't Good for Ambient L7 - -In L7 Ambient, AuthorizationPolicy targets a Service. This Service has to have a waypoint proxy. The policy enforcement point is the waypoint, but it is also the point where the Service VIP resolution happens. - -If we were to target Label Selectors, the waypoint proxy would get the request, do VIP resolution and select an endpoint, and then it would require round-tripping to itself for doing policy enforcement. - -@howardjohn has actually added that this was actually the first way ambient had implemented authorization, but it has proved to be much less performant. - -##### Discoverability Challenge - -The additional (and main) downside of `LabelSelector` is the huge increase to the complexity of policy discoverability. See more in [#Enhanced Discoverability with `gwctl`](#enhanced-discoverability-with-gwctl) for more info. - +It is very likely that graduation of this API will also require adding L7 support to it. However, after numerous conversations on this topic, the decision is to start with L4 only and leave L7 for future iterations. The details of how L7 support could look like is not in scope for this GEP. ## Graduation Criteria and Guardrails @@ -694,6 +456,7 @@ TBD exact FeatureNames. ## Appendix + ### State of the World | Aspect | Istio | Linkerd | Cilium | @@ -885,6 +648,32 @@ spec: ``` ##### CiliumIdentity + Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ + +### Loss Of Service Context + +When applying authorization policy to all traffic addressed to a Service; + +This option is very tricky to implement for sidecar-based meshes where the destination sidecar has no knowledge of which Service the request came through. + +Here is the very high-level traffic flow for sidecar-based meshes: + + ```sh + Client → Request to backend-service:8080 + → Source sidecar resolves service → backend-pod-1 (>:8080) + → Destination sidecar receives traffic on pod IP + → Destination sidecar has NO context that this came via "backend-service" + ``` + +Solving this problem either introduces security concern (e.g adding request metadata to indicate which Service was dialed), or unnecessarily complex or in-efficient to solve. + +### Label-Selectors aren't Good for Ambient L7 + +In L7 Ambient, AuthorizationPolicy targets a Service. This Service has to have a waypoint proxy. The policy enforcement point is the waypoint, but it is also the point where the Service VIP resolution happens. + +If we were to target Label Selectors, the waypoint proxy would get the request, do VIP resolution and select an endpoint, and then it would require round-tripping to itself for doing policy enforcement. + +@howardjohn has actually added that this was actually the first way ambient had implemented authorization, but it has proved to be much less performant. \ No newline at end of file From e0e06b0a8fdbe86052d2ad136207a3cc94f33d04 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Mon, 25 Aug 2025 21:20:25 +0000 Subject: [PATCH 14/15] flynns feedback --- geps/gep-3779/index.md | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 38ce8a16e8..2bcfedbbe3 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -49,9 +49,9 @@ Istio, Linkerd, and Cilium all support identity-aware authorization via vendored ## API -This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single action (to begin with - `ALLOW`, and will likely add `DENY` in future iterations), and a set of rules that include sources (the “who”) and an optional port attribute. +This GEP introduces a new policy resource, `AuthorizationPolicy`, for **identity-based** authorization. The policy defines a target, a single `ALLOW`, and a set of rules that include sources (the “who”) and an optional port attribute. -This GEP has also a comprehensive Future Enhancement section to discuss L7 support within this policy. +This GEP does not define support for L7 authorization policy (see the [Future Enhancement](#future-enhancements) section to for more information). ### Policy Rules @@ -68,15 +68,9 @@ A rule may specify: ### Policy Actions -Note: GAMMA leads met on 24th July 2025, and agreed that DENY is not going to be in scope for the initial iteration and will _potentially_ be added later. +The only currently-defined policy action is `ALLOW`. A request is allowed if and only if it matches at least one rule in any ALLOW policy targeting the workload. - * An **ALLOW** policy is permissive. - * A request is allowed if: - * It matches at least one rule in any ALLOW policy targeting the workload - - * If no ALLOW policy exists for a workload, traffic is permitted by default. - -See [#ALLOW and DENY](#allow-and-deny-policies) for interaction with DENY and how above semantics is slightly changed with the presence of DENY policies. +If no authorization policies exist for a workload, traffic is permitted by default. ### Target of Authorization @@ -117,10 +111,10 @@ Before we are jumping into the options, lets start with some background. #### Label Selectors - -This GEP is focused on L4 only, for which LabelSelectors is widely supported, across all implementations. The future l7 enhancement gets into more background, complications, and recommended solution for incorporating L7 support to this policy. +Given these challenges, this GEP focuses on L4 only, leaving L7 authorization policy is for potential future work. +Since Label selectors are widely supported by all implementations for L4 authorization, we will begin with a `LabelSelector` inside targetRef to allow targeting a set of pods. -We add support for `LabelSelector` inside targetRef to allow targeting set of pods. +The [Future-Enhancements](#future-enhancements) section of this GEP gets into more background, complications, and recommended solution for incorporating L7 support to this policy. **Benefits:** @@ -269,7 +263,7 @@ Note: The whole point of this Enum is to encourage explicitness, we **do not** w // This field clarifies policy intent and informs where enforcement is expected // to happen. It also enables implementation-specific validation and behavior. // -// +kubebuilder:validation:Enum=Network;Application +// +kubebuilder:validation:Enum=Network; type EnforcementLevel string ``` @@ -347,10 +341,10 @@ type AuthorizationRule struct { // // If this struct is omitted in a rule, it matches any source. // -// NOTE: In the future, if there’s a need to express more complex +// NOTE: In the future, if there’s a need to express more complex // logical conditions (e.g. requiring a request to match multiple // criteria simultaneously—logical AND), we may evolve this API -// to support richer match expressions or logical operators. +// to support richer match expressions or logical operators. type Source struct { // Identities specifies a list of identities that are matched by this rule. @@ -418,8 +412,7 @@ type AuthorizationNetworkAttributes struct { ``` -Note: Existing AuthorizationAPIs recognized the need to support negation fields like `not{field}`. To avoid duplicating fields with negation, we plan to support richer match expressions for fields in `AuthorizationSource` such as `matchExpressions: { operator: In|NotIn, values: []}`. - +Note: More advanced logic like negation or explicit Boolean operations is left for potential future work. ## Future Enhancements @@ -456,13 +449,12 @@ TBD exact FeatureNames. ## Appendix - ### State of the World | Aspect | Istio | Linkerd | Cilium | | ----- | ----- | ----- | ----- | | **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | -| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference Serviceaccounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like Serviceaccounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| +| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference Serviceaccounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#ciliumidentity).

Policies target abstractions like Serviceaccounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| | **Enforcement** | For Istio with sidecars - a proxy on each pod. For ambient, ztunnel node agent enforces mTLS based L4 authorization, L7 authorization is being enforced in waypoints if any.

Istio supports ALLOW, DENY, CUSTOM (often used for external authorization), and AUDIT. DENY policies in istio's context are used to enforce higher priority deny policies. The allow semantics is that whatever is not allowed explicitly (and assuming there is any policy for the same match) is implicitly denied | Linkerd data-plane proxy (injected into each pod). The proxy enforces policies via mTLS identity checks.

Linkerd supports AUDIT and ALLOW. There is not DENY policies, whats not allowed (and assuming there is any policy for the same match) is implicitly denied. | For L3/4 Ingress Rules, CiliumNetworkPolicy enforcement - an eBPF-based datapath in the Linux kernel on the destination node. If L7 http rules are specified, the packet is redirected for a node-local envoy for further enforcement.

Cilium supports ALLOW and DENY semantics - all policies generate audit logs.

Cilium service mesh also offers a kind of AuthN where a Cilium agent on the src node validates a workloads SPIFFE identity by talking to another agent on the destination node, performing the initial TLS handshake to do authentication.| | **Request Match criteria** | Policies can target a group of pods using label selector, a Gateway/Service (this means targeting a waypoint proxy) or a GatewayClass - meaning all the gateways created from this class. Policies without a label selector in a namespace implies the whole namespace is targeted.

Fine-grained L7 and L4 matching: HTTP/gRPC methods, paths, headers, ports, SNI, etc.Policies use logical OR over rules.

All match criterias are inline in the policy. See https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-To and https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-when | Policies can target:
  • A `Server` which describes a set of pods (using fancy label match expressions), and a single port on those pods.
  • A user can optionally restrict the authorization to a smaller subset of the traffic by targeting an HTTPRoute. (TODO: any plans to support sectionNames?)
  • A namespace - this indicates that the policy applies to all traffic to all Servers and HTTPRoutes defined in the namespace.
Note: We leave `ServerAuthorization` outside the scope as it planned to be deprecated (per linkerd website) | Policies can target groups of pods using label selector (`endpointSelector`), or by node-labels (`nodeSelector`). Cilium supports L7 via built-in HTTP parsing: rules can match HTTP methods, paths, etc. For example, a CiliumNetworkPolicy can allow only specific HTTP methods/paths on a port. | | **Default policies and admin policies** | If **no** ALLOW policy matches, traffic is **allowed** by default. You can deploy an overridable - default deny by default by deploying an **allow-nothing** policy in either the namespace or istio-system

AuthorizationPolicies in the `istio-system` namespace apply to the whole mesh and take precedence. These are not overridable by namespace-level policies. | Default inbound policy can be set at install time using `proxy.defaultInboundPolicy`. Supported values are:
  • `all-unauthenticated:` allow all traffic. This is the default.
  • `all-authenticated:` allow traffic from meshed clients in the same or from a different cluster (with multi-cluster).
  • `cluster-authenticated:` allow traffic from meshed clients in the same cluster.
  • `cluster-unauthenticated:` allow traffic from both meshed and non-meshed clients in the same cluster.
  • `deny:` all traffic are denied.
  • `audit:` Same as all-unauthenticated but requests get flagged in logs and metrics.

Users can override the default policies for namespaces/pods or by setting the [config.linkerd.io/default-inbound-policy](http://config.linkerd.io/default-inbound-policy) annotation There is no support for admin, non overridable policies. | Follows Kubernetes NetworkPolicy semantics by default: if no `CiliumNetworkPolicy` allows the traffic, it is allowed (no implicit deny). Once at least one `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` allows some traffic, all other traffic is implicitly denied. From 950c6639afd099b7bba4236f8b894ae4b891d26a Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Thu, 28 Aug 2025 21:39:04 +0000 Subject: [PATCH 15/15] clarify whats being targeted in a namespace-wide policy --- geps/gep-3779/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md index 2bcfedbbe3..574417131d 100644 --- a/geps/gep-3779/index.md +++ b/geps/gep-3779/index.md @@ -191,13 +191,13 @@ gwctl get authorizationPolicy -o json Without dedicated tooling, the `LabelSelector` approach could significantly degrade the user experience and observability. -##### Namespace-Wide Policies +##### Targeting All **Pods** in a Namespace -A common case for authorization is to target a whole namespace. We can achieve the above with a few patterns: +A common case for authorization is to target all the workloads in the namespace (where the policy resource lives). We can achieve the above with a few patterns: ###### Option 1 -Target a namespace, name MUST be empty (as this is already namespaced policy) +Target a namespace, `name` MUST be empty (will be the namespace where the policy resource lives). ```yaml targetRefs: @@ -215,7 +215,7 @@ This option is also inconsistent with other API fields where an empty field or a ###### Option 3 (Recommended) -An empty pod selector. Kubernetes official docs clarify that the semantics of empty selectors are the decision of the API owner. In fact, many Kubernetes APIs (I know Service API does the opposite :/) using empty selectors as a select-all mechanism. See [NetworkPolicy podSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#networkpolicy-v1-networking-k8s-io), PodDisruptionBudget, ResourceQuota, and more. +An empty pod selector to target all **workloads** in the namespace. Kubernetes official docs clarify that the semantics of empty selectors are the decision of the API owner. In fact, many Kubernetes APIs (I know Service API does the opposite :/) using empty selectors as a select-all mechanism. See [NetworkPolicy podSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/#networkpolicy-v1-networking-k8s-io), PodDisruptionBudget, ResourceQuota, and more. ```yaml targetRefs: