Skip to content

Commit

Permalink
Adding GEP for Policy Attachment
Browse files Browse the repository at this point in the history
  • Loading branch information
robscott committed Jul 12, 2021
1 parent 920b029 commit 3866d94
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 0 deletions.
332 changes: 332 additions & 0 deletions site-src/geps/gep-713.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,332 @@
# GEP-713: Policy Attachment

* Issue URL: https://github.com/kubernetes-sigs/gateway-api/issues/713
* Status: Implementable

## TLDR

This GEP aims to standardize policy attachment to resources associated with
Gateway API. This will be important for providing a consistent experience across
implementations of the API, even for configuration details that may not be fully
portable.

## Goals

* Establish a pattern for policy attachment which will be used for any policies
included in the Gateway API spec
* Establish a pattern for policy attachment which should be used for any
implementation specific policies used with Gateway API resources
* Provide a way to distinguish between required and default values
* Enable policy attachment at all relevant scopes, including Gateways, Routes,
Backends, and maybe Namespaces
* Provide a means of attachment that works for both ingress and mesh uses of
this API
* Provide a consistent way that both included and implementation-specific
policies can be interpreted

## API

This approach is building on concepts from all 3 of the alternatives discussed
below. This is very similar to the existing BackendPolicy resource in the API,
but also borrows some concepts from the ServicePolicy proposal.

### Policy Attachment for Ingress
Attaching policy to Gateway resources for ingress use cases is relatively
straightforward. A policy can reference the resource it wants to apply to.
Access is granted with RBAC - anyone that has access to create a RetryPolicy in
a given namespace can attach it to any resource within that namespace.

![Simple Ingress Example](images/713-ingress-simple.png)

Attaching policy to Gateway resources for ingress use cases is relatively
straightforward. A policy can reference the resource it wants to apply to.
Access is granted with RBAC - anyone that has access to create a RetryPolicy in
a given namespace can attach it to any resource within that namespace.

![Complex Ingress Example](images/713-ingress-complex.png)

### Policy Attachment for Mesh
Although there is a great deal of overlap between ingress and mesh use cases,
mesh enables more complex policy attachment scenarios. For example, you may want
to apply policy to requests from a specific namespace to a backend in another
namespace.

![Simple Mesh Example](images/713-mesh-simple.png)

Policy attachment can be quite simple with mesh. Policy can be applied to any
resource in any namespace but it can only apply to requests from the same
namespace if the target is in a different namespace.

At the other extreme, policy can be used to apply to requests from a specific
workload to a backend in another namespace. A route can be used to intercept
these requests and split them between different backends (foo-a and foo-b in
this case).

![Complex Mesh Example](images/713-mesh-complex.png)

### Policy TargetRef API

Each Policy resource should include a single `targetRef` field. It must not
target more than one resource at a time, but it can be used target larger
resources such as Gateways or Namespaces that may apply to multiple child
resources. This field should have the following structure:

```go
// PolicyTargetReference identifies an API object to apply policy to.
type PolicyTargetReference struct {
// Group is the group of the target resource.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
Group string `json:"group"`

// Kind is kind of the target resource.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
Kind string `json:"kind"`

// Name is the name of the target resource.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
Name string `json:"name"`

// SectionName is the name of a section within the target resource. When
// unspecified, this targets the entire resource. In the following
// resources, SectionName is interpreted as the following:
// * Gateway: Listener Name
// * Route: Rule Name
// * Service: Port Name
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +optional
SectionName string `json:"sectionName,omitempty"`

// Namespace is the namespace of the referent. When unspecified, the local
// namespace is inferred. Even when policy targets a resource in a different
// namespace, it may only apply to traffic originating from the same
// namespace as the policy.
//
// Support: Extended
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +optional
Namespace string `json:"namespace,omitempty"`

// ClassName is the name of the class this policy should refer to. When
// unspecified, the policy will apply to all classes that support it.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +optional
ClassName string `json:"className,omitempty"`
}
```

### Status
A new `Policies` field will be added to status on Gateways and Routes. This will
be a list of `PolicyTargetReference` structs with the fields instead used to
refer to the Policy resource that has been applied.

### Hierarchy
Policy precedence is determined in the same direction a request flows. For
ingress, that means from Gateway to Backend, and for mesh that means from
Consumer to Backend.

| Ingress | Sidecar Consumer |
|-|-|
| Gateway Namespace | Consumer Namespace |
| Gateway | Consumer |
| Route Namespace | Route Namespace |
| Route | Route |
| Backend Namespace | Backend Namespace |
| Backend | Backend |


Some implementations may wish to provide default or enforced values. For default
values, the hierarchies above would be used. For example, if a default value was
specified for both a Route and Backend, the value attached to the backend would
be given precedence. For enforced values, precedence would be given to the
policy attached higher in the hierarchy.

Each policy resource would include 2 structs within the spec. One with enforced
values and the other with default values. In the following example, the policy
attached to the Gateway requires cdn to be enabled and provides some default
configuration for that. The policy attached to the Route changes the value for
one of those fields (includeQueryString).

```yaml
kind: GKEServicePolicy # Example of implementation specific policy name
spec:
enforce:
cdn:
enabled: true
default:
cdn:
cachePolicy:
includeHost: true
includeProtocol: true
includeQueryString: true
targetRef:
kind: Gateway
name: example
---
kind: GKEServicePolicy
spec:
default:
cdn:
cachePolicy:
includeQueryString: false
targetRef:
kind: HTTPRoute
name: example
```
### Targeting External Services
In some cases (likely limited to mesh) we may want to apply policies to requests
to external services. To accomplish this, implementations can choose to support
a refernce to a virtual resource type:
```yaml
kind: RetryPolicy
apiVersion: networking.acme.io/v1alpha1
metadata:
name: foo
spec:
default:
maxRetries: 5
targetRef:
group: networking.acme.io
kind: ExternalService
hostname: foo.com
```
### Apply Policies to Specific Matches
In some cases we may want to target specific matches within nested objects. For
example, it may be useful to attach policies to a specific Gateway listener or
Route rule.
Each Route rule or Gateway listener should be expanded with an optional name
field. The target ref would be expanded with an optional sectionName field that
could be used to refer to that specific section of the resource. It would refer
to the following concepts on these resources:
* Gateway.Listeners.Name
* xRoute.Rules.Name
* Service.Ports.Name
```yaml
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
name: http-app-1
labels:
app: foo
spec:
hostnames:
- "foo.com"
rules:
- name: bar
matches:
- path:
type: Prefix
value: /bar
forwardTo:
- serviceName: my-service1
port: 8080
---
kind: RetryPolicy
apiVersion: networking.acme.io/v1alpha1
metadata:
name: foo
spec:
maxRetries: 5
targetRef:
name: foo
group: networking.x-k8s.io
kind: HTTPRoute
sectionName: bar
```
This would require adding a `Name` field to Gateway listeners and Route rules:

```go
type Listener struct {
// Name is the name of the Listener.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +optional
Name string `json:"name,omitempty"`
// ...
}
```

```go
type RouteRule struct {
// Name is the name of the Route rule.
//
// Support: Core
//
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +optional
Name string `json:"name,omitempty"`
// ...
}
```

### Kubectl Plugin
To help improve UX and standardization, a kubectl plugin will be developed that
will be capable of describing the computed sum of policy that applies to a given
resource, including policies applied to parent resources.

Each Policy CRD that wants to be supported by this plugin will need to follow
the API structure defined above and add a `networking.x-k8s.io/policy: true` to
the CRD.

### Advantages
* Incredibly flexible approach that should work well for both ingress and mesh
* Conceptually similar to existing ServicePolicy proposal and BackendPolicy
pattern
* Easy to attach policy to resources we don’t control (Service, ServiceImport,
etc)
* Minimal API changes required (just expansion of status)
* Simplifies packaging an application for deployment as policy references do not
need to be part of the templating

### Disadvantages
* May be difficult to understand which policies apply to a request


## Alternatives

TODO

## Out of scope

* Define all potential policies that may be attached to resources
* Design the full structure and configuration of policies

## References

**Issues**
* [Extensible Service Policy and Configuration](https://github.com/kubernetes-sigs/gateway-api/issues/611)

**Docs**
* [Policy Attachment and Binding](https://docs.google.com/document/d/13fyptUtO9NV_ZAgkoJlfukcBf2PVGhsKWG37yLkppJo/edit?resourcekey=0-Urhtj9gBkGBkSL1gHgbWKw)
Binary file added site-src/geps/images/713-ingress-complex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added site-src/geps/images/713-ingress-simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added site-src/geps/images/713-mesh-complex.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added site-src/geps/images/713-mesh-simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3866d94

Please sign in to comment.