From a375ffb43a2fc5d49dec368970cb8bf4284fde48 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 9 May 2023 11:46:43 -0700 Subject: [PATCH 1/8] feat: EnvoyPatchPolicy API Relates to https://github.com/envoyproxy/gateway/issues/24 Signed-off-by: Arko Dasgupta --- api/v1alpha1/envoypatchpolicy_types.go | 124 +++++++++++ api/v1alpha1/zz_generated.deepcopy.go | 134 +++++++++++ ...eway.envoyproxy.io_envoypatchpolicies.yaml | 209 ++++++++++++++++++ docs/latest/api/extension_types.md | 107 +++++++++ 4 files changed, 574 insertions(+) create mode 100644 api/v1alpha1/envoypatchpolicy_types.go create mode 100644 charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml diff --git a/api/v1alpha1/envoypatchpolicy_types.go b/api/v1alpha1/envoypatchpolicy_types.go new file mode 100644 index 0000000000..f5bc6a5fe5 --- /dev/null +++ b/api/v1alpha1/envoypatchpolicy_types.go @@ -0,0 +1,124 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +const ( + // KindEnvoyPatchPolicy is the name of the EnvoyPatchPolicy kind. + KindEnvoyPatchPolicy = "EnvoyPatchPolicy" +) + +// +kubebuilder:object:root=true + +// EnvoyPatchPolicy allows the user to modify the generated Envoy xDS +// resources by Envoy Gateway using this patch API +type EnvoyPatchPolicy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of EnvoyPatchPolicy. + Spec EnvoyPatchPolicySpec `json:"spec"` + + // Status defines the current status of EnvoyPatchPolicy. + Status EnvoyPatchPolicyStatus `json:"status"` +} + +// EnvoyPatchPolicySpec defines the desired state of RateLimitFilter. +// +union +type EnvoyPatchPolicySpec struct { + // Type decides the type of patch. + // Valid EnvoyPatchType values are "JSONPatch". + // + // +unionDiscriminator + Type EnvoyPatchType `json:"type"` + // JSONPatch defines the JSONPatch configuration. + // + // +optional + JSONPatches []EnvoyJSONPatchConfig `json:"jsonPatches,omitempty"` + // TargetRef is the name of the Gateway API resource this policy + // is being attached to. + // Currently only attaching to Gateway is supported + // This Policy and the TargetRef MUST be in the same namespace + // for this Policy to have effect and be applied to the Gateway + // TargetRef + TargetRef gwapiv1a2.PolicyTargetReference `json:"targetRef"` +} + +// EnvoyPatchType specifies the types of Envoy patching mechanisms. +// +kubebuilder:validation:Enum=JSONPatch +type EnvoyPatchType string + +const ( + // JSONPatchEnvoyPatchType allows the user to patch the generated xDS resources using JSONPatch semantics. + // For more details on the semantics, please refer to https://datatracker.ietf.org/doc/html/rfc6902 + JSONPatchEnvoyPatchType EnvoyPatchType = "JSONPatch" +) + +// EnvoyJSONPatchConfig defines the configuration for patching a Envoy xDS Resource +// using JSONPatch semantic +type EnvoyJSONPatchConfig struct { + // Type is the typed URL of the Envoy xDS Resource + Type EnvoyResourceType `json:"type"` + // Name is the name of the resource + Name string `json:"name"` + // Patch defines the JSON Patch Operation + Operation JSONPatchOperation `json:"operation"` +} + +// EnvoyResourceType specifies the type URL of the Envoy resource. +// +kubebuilder:validation:Enum=type.googleapis.com/envoy.config.listener.v3.Listener;type.googleapis.com/envoy.config.route.v3.RouteConfiguration;type.googleapis.com/envoy.config.cluster.v3.Cluster;type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment +type EnvoyResourceType string + +const ( + // ListenerEnvoyResourceType defines the Type URL of the Listener resource + ListenerEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.listener.v3.Listener" + // RouteConfigurationEnvoyResourceType defines the Type URL of the RouteConfiguration resource + RouteConfigurationEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.listener.v3.RouteConfiguration" + // ClusterEnvoyResourceType defines the Type URL of the Cluster resource + ClusterEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.cluster.v3.Cluster" + // ClusterLoadAssignmentEnvoyResourceType defines the Type URL of the ClusterLoadAssignment resource + ClusterLoadAssignmentEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment" +) + +// JSONPatchOperation defines the JSON Patch Operation as defined in +// https://datatracker.ietf.org/doc/html/rfc6902 +type JSONPatchOperation struct { + // Op is the type of operation to perform + Op string `json:"op"` + // Path is the location of the target document/field where the operation will be performed + // Refer to https://datatracker.ietf.org/doc/html/rfc6901 for more details. + Path string `json:"path"` + // Value is the new value of the path location. + Value string `json:"value"` +} + +// EnvoyPatchPolicyStatus defines the state of EnvoyPatchPolicy +type EnvoyPatchPolicyStatus struct { + // Conditions describe the current conditions of the EnvoyPatchPolicy. + // + // +optional + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MaxItems=8 + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +//+kubebuilder:object:root=true + +// EnvoyPatchPolicyList contains a list of EnvoyPatchPolicy resources. +type EnvoyPatchPolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []EnvoyPatchPolicy `json:"items"` +} + +func init() { + SchemeBuilder.Register(&EnvoyPatchPolicy{}, &EnvoyPatchPolicyList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index cf139703a9..f04385414e 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -11,6 +11,7 @@ package v1alpha1 import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -94,6 +95,124 @@ func (in *AuthenticationFilterSpec) DeepCopy() *AuthenticationFilterSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyJSONPatchConfig) DeepCopyInto(out *EnvoyJSONPatchConfig) { + *out = *in + out.Operation = in.Operation +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyJSONPatchConfig. +func (in *EnvoyJSONPatchConfig) DeepCopy() *EnvoyJSONPatchConfig { + if in == nil { + return nil + } + out := new(EnvoyJSONPatchConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyPatchPolicy) DeepCopyInto(out *EnvoyPatchPolicy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyPatchPolicy. +func (in *EnvoyPatchPolicy) DeepCopy() *EnvoyPatchPolicy { + if in == nil { + return nil + } + out := new(EnvoyPatchPolicy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EnvoyPatchPolicy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyPatchPolicyList) DeepCopyInto(out *EnvoyPatchPolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]EnvoyPatchPolicy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyPatchPolicyList. +func (in *EnvoyPatchPolicyList) DeepCopy() *EnvoyPatchPolicyList { + if in == nil { + return nil + } + out := new(EnvoyPatchPolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *EnvoyPatchPolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyPatchPolicySpec) DeepCopyInto(out *EnvoyPatchPolicySpec) { + *out = *in + if in.JSONPatches != nil { + in, out := &in.JSONPatches, &out.JSONPatches + *out = make([]EnvoyJSONPatchConfig, len(*in)) + copy(*out, *in) + } + in.TargetRef.DeepCopyInto(&out.TargetRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyPatchPolicySpec. +func (in *EnvoyPatchPolicySpec) DeepCopy() *EnvoyPatchPolicySpec { + if in == nil { + return nil + } + out := new(EnvoyPatchPolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EnvoyPatchPolicyStatus) DeepCopyInto(out *EnvoyPatchPolicyStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvoyPatchPolicyStatus. +func (in *EnvoyPatchPolicyStatus) DeepCopy() *EnvoyPatchPolicyStatus { + if in == nil { + return nil + } + out := new(EnvoyPatchPolicyStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GlobalRateLimit) DeepCopyInto(out *GlobalRateLimit) { *out = *in @@ -141,6 +260,21 @@ func (in *HeaderMatch) DeepCopy() *HeaderMatch { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JSONPatchOperation) DeepCopyInto(out *JSONPatchOperation) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONPatchOperation. +func (in *JSONPatchOperation) DeepCopy() *JSONPatchOperation { + if in == nil { + return nil + } + out := new(JSONPatchOperation) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *JwtAuthenticationFilterProvider) DeepCopyInto(out *JwtAuthenticationFilterProvider) { *out = *in diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml new file mode 100644 index 0000000000..961b2327ec --- /dev/null +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml @@ -0,0 +1,209 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: envoypatchpolicies.gateway.envoyproxy.io +spec: + group: gateway.envoyproxy.io + names: + kind: EnvoyPatchPolicy + listKind: EnvoyPatchPolicyList + plural: envoypatchpolicies + singular: envoypatchpolicy + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: EnvoyPatchPolicy allows the user to modify the generated Envoy + xDS resources by Envoy Gateway using this patch API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of EnvoyPatchPolicy. + properties: + jsonPatches: + description: JSONPatch defines the JSONPatch configuration. + items: + description: EnvoyJSONPatchConfig defines the configuration for + patching a Envoy xDS Resource using JSONPatch semantic + properties: + name: + description: Name is the name of the resource + type: string + operation: + description: Patch defines the JSON Patch Operation + properties: + op: + description: Op is the type of operation to perform + type: string + path: + description: Path is the location of the target document/field + where the operation will be performed Refer to https://datatracker.ietf.org/doc/html/rfc6901 + for more details. + type: string + value: + description: Value is the new value of the path location. + type: string + required: + - op + - path + - value + type: object + type: + description: Type is the typed URL of the Envoy xDS Resource + enum: + - type.googleapis.com/envoy.config.listener.v3.Listener + - type.googleapis.com/envoy.config.route.v3.RouteConfiguration + - type.googleapis.com/envoy.config.cluster.v3.Cluster + - type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment + type: string + required: + - name + - operation + - type + type: object + type: array + targetRef: + description: TargetRef is the name of the Gateway API resource this + policy is being attached to. Currently only attaching to Gateway + is supported This Policy and the TargetRef MUST be in the same namespace + for this Policy to have effect and be applied to the Gateway TargetRef + properties: + group: + description: Group is the group of the target resource. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the target resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the target resource. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: 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 MUST only apply + to traffic originating from the same namespace as the policy. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + type: + description: Type decides the type of patch. Valid EnvoyPatchType + values are "JSONPatch". + enum: + - JSONPatch + type: string + required: + - targetRef + - type + type: object + status: + description: Status defines the current status of EnvoyPatchPolicy. + properties: + conditions: + description: Conditions describe the current conditions of the EnvoyPatchPolicy. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + - status + type: object + served: true + storage: true diff --git a/docs/latest/api/extension_types.md b/docs/latest/api/extension_types.md index bcfe1ad5b8..740b3a7ec8 100644 --- a/docs/latest/api/extension_types.md +++ b/docs/latest/api/extension_types.md @@ -11,6 +11,8 @@ Package v1alpha1 contains API schema definitions for the gateway.envoyproxy.io A ### Resource Types - [AuthenticationFilter](#authenticationfilter) +- [EnvoyPatchPolicy](#envoypatchpolicy) +- [EnvoyPatchPolicyList](#envoypatchpolicylist) - [RateLimitFilter](#ratelimitfilter) @@ -57,6 +59,95 @@ _Appears in:_ +## EnvoyJSONPatchConfig + + + +EnvoyJSONPatchConfig defines the configuration for patching a Envoy xDS Resource using JSONPatch semantic + +_Appears in:_ +- [EnvoyPatchPolicySpec](#envoypatchpolicyspec) + +| Field | Description | +| --- | --- | +| `type` _[EnvoyResourceType](#envoyresourcetype)_ | Type is the typed URL of the Envoy xDS Resource | +| `name` _string_ | Name is the name of the resource | +| `operation` _[JSONPatchOperation](#jsonpatchoperation)_ | Patch defines the JSON Patch Operation | + + +## EnvoyPatchPolicy + + + +EnvoyPatchPolicy allows the user to modify the generated Envoy xDS resources by Envoy Gateway using this patch API + +_Appears in:_ +- [EnvoyPatchPolicyList](#envoypatchpolicylist) + +| Field | Description | +| --- | --- | +| `apiVersion` _string_ | `gateway.envoyproxy.io/v1alpha1` +| `kind` _string_ | `EnvoyPatchPolicy` +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | +| `spec` _[EnvoyPatchPolicySpec](#envoypatchpolicyspec)_ | Spec defines the desired state of EnvoyPatchPolicy. | + + +## EnvoyPatchPolicyList + + + +EnvoyPatchPolicyList contains a list of EnvoyPatchPolicy resources. + + + +| Field | Description | +| --- | --- | +| `apiVersion` _string_ | `gateway.envoyproxy.io/v1alpha1` +| `kind` _string_ | `EnvoyPatchPolicyList` +| `metadata` _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.26/#listmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | +| `items` _[EnvoyPatchPolicy](#envoypatchpolicy) array_ | | + + +## EnvoyPatchPolicySpec + + + +EnvoyPatchPolicySpec defines the desired state of RateLimitFilter. + +_Appears in:_ +- [EnvoyPatchPolicy](#envoypatchpolicy) + +| Field | Description | +| --- | --- | +| `type` _[EnvoyPatchType](#envoypatchtype)_ | Type decides the type of patch. Valid EnvoyPatchType values are "JSONPatch". | +| `jsonPatches` _[EnvoyJSONPatchConfig](#envoyjsonpatchconfig) array_ | JSONPatch defines the JSONPatch configuration. | +| `targetRef` _[PolicyTargetReference](#policytargetreference)_ | TargetRef is the name of the Gateway API resource this policy is being attached to. Currently only attaching to Gateway is supported This Policy and the TargetRef MUST be in the same namespace for this Policy to have effect and be applied to the Gateway TargetRef | + + + + +## EnvoyPatchType + +_Underlying type:_ `string` + +EnvoyPatchType specifies the types of Envoy patching mechanisms. + +_Appears in:_ +- [EnvoyPatchPolicySpec](#envoypatchpolicyspec) + + + +## EnvoyResourceType + +_Underlying type:_ `string` + +EnvoyResourceType specifies the type URL of the Envoy resource. + +_Appears in:_ +- [EnvoyJSONPatchConfig](#envoyjsonpatchconfig) + + + ## GlobalRateLimit @@ -98,6 +189,22 @@ _Appears in:_ +## JSONPatchOperation + + + +JSONPatchOperation defines the JSON Patch Operation as defined in https://datatracker.ietf.org/doc/html/rfc6902 + +_Appears in:_ +- [EnvoyJSONPatchConfig](#envoyjsonpatchconfig) + +| Field | Description | +| --- | --- | +| `op` _string_ | Op is the type of operation to perform | +| `path` _string_ | Path is the location of the target document/field where the operation will be performed Refer to https://datatracker.ietf.org/doc/html/rfc6901 for more details. | +| `value` _string_ | Value is the new value of the path location. | + + ## JwtAuthenticationFilterProvider From 82f9c6ad5b78ec3e700aeecbf43417b62376825a Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 9 May 2023 13:51:36 -0700 Subject: [PATCH 2/8] wip design doc Signed-off-by: Arko Dasgupta --- docs/latest/design/envoy-patch-policy.md | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/latest/design/envoy-patch-policy.md diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md new file mode 100644 index 0000000000..af43fc41e2 --- /dev/null +++ b/docs/latest/design/envoy-patch-policy.md @@ -0,0 +1,44 @@ +# EnvoyPatchPolicy + +## Overview + +This design introduces the `EnvoyPatchPolicy` API allowing users to modify the generated Envoy xDS Configuration +that Envoy Gateway generates before sending it to Envoy Proxy. + +Envoy Gateway allows users to configure networking and security intent using the +upstream [Gateway API][] as well as implementation specific [Extension APIs][] defined in this project +to provide a more batteries included experience for application developers. +* These APIs are an abstacted version of the underlying Envoy xDS API to provide a a better user experience for the application developer, exposing and setting only a subset of the fields for a specific feature, sometimes in a opinionated way (e.g [RateLimit][]) +* These APIs do not expose all the features capabilities that Envoy has either because these features are desired but the API +is not defined yet or the project cannot support such an extensive list of features. +To alleviate this problem, and provide an interim solution for a small section of advanced users who are well versed in +Envoy xDS API and its capabilities, this API is being introduced. + +## Goals + +## Non Goals + +## Example + +## State of the World + +## Design Decisions +* This API will only support a single `targetRef` and can bind to only a `Gateway` resource. This simplifies reasoning of how +patches will work. +* This API will always be an experimental API and cannot be graduated into a stable API because Envoy Gateway cannot garuntee + * that the naming scheme for the generated resources names wont change across releases + * that the underlying Envoy Proxy API wont change across releases + +## Alternatives + +* Users can customize the Envoy [Bootstrap configuration using EnvoyProxy API][] and provide static xDS configuration. +* Users can extend funtionality by [Extending the Control Plane][] and adding gRPC hooks to modify the generated xDS configuration. + + + +[PolicyAttachment]: https://gateway-api.sigs.k8s.io/references/policy-attachment/ +[Gateway API]: https://gateway-api.sigs.k8s.io/ +[Extension APIs]: https://gateway.envoyproxy.io/latest/api/extension_types.html +[RateLimit]: https://gateway.envoyproxy.io/latest/user/rate-limit.html +[Extending the Control Plane]: https://gateway.envoyproxy.io/latest/design/extending-envoy-gateway.html +[Bootstrap configuration using EnvoyProxy API]: https://gateway.envoyproxy.io/latest/user/customize-envoyproxy.html#customize-envoyproxy-bootstrap-config From 58be2bc337b76607b4458a1a8d611af939cf8952 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 9 May 2023 17:11:55 -0700 Subject: [PATCH 3/8] wrap up design Signed-off-by: Arko Dasgupta --- api/v1alpha1/envoypatchpolicy_types.go | 2 +- docs/latest/design/envoy-patch-policy.md | 112 +++++++++++++++++++++-- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/api/v1alpha1/envoypatchpolicy_types.go b/api/v1alpha1/envoypatchpolicy_types.go index f5bc6a5fe5..bcd393004d 100644 --- a/api/v1alpha1/envoypatchpolicy_types.go +++ b/api/v1alpha1/envoypatchpolicy_types.go @@ -80,7 +80,7 @@ const ( // ListenerEnvoyResourceType defines the Type URL of the Listener resource ListenerEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.listener.v3.Listener" // RouteConfigurationEnvoyResourceType defines the Type URL of the RouteConfiguration resource - RouteConfigurationEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.listener.v3.RouteConfiguration" + RouteConfigurationEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" // ClusterEnvoyResourceType defines the Type URL of the Cluster resource ClusterEnvoyResourceType EnvoyResourceType = "type.googleapis.com/envoy.config.cluster.v3.Cluster" // ClusterLoadAssignmentEnvoyResourceType defines the Type URL of the ClusterLoadAssignment resource diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md index af43fc41e2..76589c1928 100644 --- a/docs/latest/design/envoy-patch-policy.md +++ b/docs/latest/design/envoy-patch-policy.md @@ -15,30 +15,130 @@ To alleviate this problem, and provide an interim solution for a small section o Envoy xDS API and its capabilities, this API is being introduced. ## Goals +* Add an API allowing users to modify the generated xDS Configuration ## Non Goals +* Support multiple patch mechanisims -## Example +## Implementation +`EnvoyPatchPolicy` is a [Direct Policy Attachment][] type API that can be used to extend [Gateway API][] + +### Example +Here is an example highlighting how a user can configure global ratelimiting using an external rate limit service using this API. + +``` +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: eg-gw + namespace: default +spec: + gatewayClassName: eg-gc + listeners: + - name: example + protocol: HTTPS + port: 443 + hostname: example.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: example-cert +--- +apiVersion: gateway.envoyproxy.io/v1alpha1 +kind: EnvoyPatchPolicy +metadata: + name: ratelimit-patch-policy + namespace: default +spec: + targetRef: + group: gateway.networking.k8s.io/v1beta1 + kind: Gateway + name: eg-gw + namespace: default + type: JSONPatch + jsonPatches: + - type: "type.googleapis.com/envoy.config.listener.v3.Listener" + # The listener name is of the form -- + name: default-eg-gw-example + operation: + op: add + path: "/filter_chains/0/filters/0/http_filters/0" + value: | + name: "envoy.filters.http.ratelimit" + typed_config: + "@type": "type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit" + domain: "eag-ratelimit" + failure_mode_deny: true + timeout: 1s + rate_limit_service: + grpc_service: + envoy_grpc: + cluster_name: rate-limit-cluster + transport_api_version: V3 + - type: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration" + # The route name is of the form -- + name: default-eg-gw-example + operation: + op: add + path: "/virtual_hosts/0/rate_limits" + value: | + - actions: + - remote_address: {} + - type: "type.googleapis.com/envoy.config.cluster.v3.Cluster" + name: rate-limit-cluster + operation: + op: add + path: "/" + value: | + name: rate-limit-cluster + type: STRICT_DNS + connect_timeout: 10s + lb_policy: ROUND_ROBIN + http2_protocol_options: {} + load_assignment: + cluster_name: rate-limit-cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: ratelimit.svc.cluster.local + port_value: 8081 +``` + + +## Verification +* Offline - Leverage [egctl x translate][] to ensure that the `EnvoyPatchPolicy` can be successfully applied and the desired +output xDS is created. +* Runtime - Use the `Status` field within `EnvoyPatchPolicy` to highlight whether the patch was applied successfully or not. ## State of the World +* Istio - Supports the [EnvoyFilter][] API which allows users to customize the output xDS using patches and proto based merge +semantics. ## Design Decisions * This API will only support a single `targetRef` and can bind to only a `Gateway` resource. This simplifies reasoning of how patches will work. * This API will always be an experimental API and cannot be graduated into a stable API because Envoy Gateway cannot garuntee - * that the naming scheme for the generated resources names wont change across releases - * that the underlying Envoy Proxy API wont change across releases + * that the naming scheme for the generated resources names will not change across releases + * that the underlying Envoy Proxy API will not change across releases -## Alternatives +## Open Questions +* Should this be an Opt In API disabled by default ? +* Should the value only support JSON or YAML as well (which is a JSON superset) ? +## Alternatives * Users can customize the Envoy [Bootstrap configuration using EnvoyProxy API][] and provide static xDS configuration. -* Users can extend funtionality by [Extending the Control Plane][] and adding gRPC hooks to modify the generated xDS configuration. +* Users can extend functionality by [Extending the Control Plane][] and adding gRPC hooks to modify the generated xDS configuration. -[PolicyAttachment]: https://gateway-api.sigs.k8s.io/references/policy-attachment/ +[Direct Policy Attachment]: https://gateway-api.sigs.k8s.io/references/policy-attachment/#direct-policy-attachment [Gateway API]: https://gateway-api.sigs.k8s.io/ [Extension APIs]: https://gateway.envoyproxy.io/latest/api/extension_types.html [RateLimit]: https://gateway.envoyproxy.io/latest/user/rate-limit.html [Extending the Control Plane]: https://gateway.envoyproxy.io/latest/design/extending-envoy-gateway.html +[EnvoyFilter]: https://istio.io/latest/docs/reference/config/networking/envoy-filter +[egctl x translate]: https://gateway.envoyproxy.io/latest/user/egctl.html#egctl-experimental-translate [Bootstrap configuration using EnvoyProxy API]: https://gateway.envoyproxy.io/latest/user/customize-envoyproxy.html#customize-envoyproxy-bootstrap-config From e4544c48c026a859b9ed0e43e4d5c94510ef85d8 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 9 May 2023 17:21:55 -0700 Subject: [PATCH 4/8] lint Signed-off-by: Arko Dasgupta --- docs/latest/design/envoy-patch-policy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md index 76589c1928..a834322959 100644 --- a/docs/latest/design/envoy-patch-policy.md +++ b/docs/latest/design/envoy-patch-policy.md @@ -8,7 +8,7 @@ that Envoy Gateway generates before sending it to Envoy Proxy. Envoy Gateway allows users to configure networking and security intent using the upstream [Gateway API][] as well as implementation specific [Extension APIs][] defined in this project to provide a more batteries included experience for application developers. -* These APIs are an abstacted version of the underlying Envoy xDS API to provide a a better user experience for the application developer, exposing and setting only a subset of the fields for a specific feature, sometimes in a opinionated way (e.g [RateLimit][]) +* These APIs are an abstracted version of the underlying Envoy xDS API to provide a a better user experience for the application developer, exposing and setting only a subset of the fields for a specific feature, sometimes in a opinionated way (e.g [RateLimit][]) * These APIs do not expose all the features capabilities that Envoy has either because these features are desired but the API is not defined yet or the project cannot support such an extensive list of features. To alleviate this problem, and provide an interim solution for a small section of advanced users who are well versed in From 4decf03afa47e0f5b0288f9a4b0a4bae0a1da139 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 9 May 2023 17:52:55 -0700 Subject: [PATCH 5/8] update implementation Signed-off-by: Arko Dasgupta --- docs/latest/design/envoy-patch-policy.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md index a834322959..fb13fa94b6 100644 --- a/docs/latest/design/envoy-patch-policy.md +++ b/docs/latest/design/envoy-patch-policy.md @@ -22,6 +22,9 @@ Envoy xDS API and its capabilities, this API is being introduced. ## Implementation `EnvoyPatchPolicy` is a [Direct Policy Attachment][] type API that can be used to extend [Gateway API][] +Modifications to the generated xDS configuration can be provided as a JSON Patch which is defined in +[RFC 6902][]. This patching mechanism has been adopted in [Kubernetes][] as well as [Kustomize][] to update +resource objects. ### Example Here is an example highlighting how a user can configure global ratelimiting using an external rate limit service using this API. @@ -135,7 +138,10 @@ patches will work. [Direct Policy Attachment]: https://gateway-api.sigs.k8s.io/references/policy-attachment/#direct-policy-attachment +[RFC 6902]: https://datatracker.ietf.org/doc/html/rfc6902 [Gateway API]: https://gateway-api.sigs.k8s.io/ +[Kubernetes]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ +[Kustomize]: https://github.com/kubernetes-sigs/kustomize/blob/master/examples/jsonpatch.md [Extension APIs]: https://gateway.envoyproxy.io/latest/api/extension_types.html [RateLimit]: https://gateway.envoyproxy.io/latest/user/rate-limit.html [Extending the Control Plane]: https://gateway.envoyproxy.io/latest/design/extending-envoy-gateway.html From 2d2e1c4737eb16794620daf7a3acca8dd9f9a724 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 30 May 2023 18:41:22 -0700 Subject: [PATCH 6/8] address comments Signed-off-by: Arko Dasgupta --- api/v1alpha1/envoypatchpolicy_types.go | 9 ++++++++- docs/latest/api/extension_types.md | 3 ++- docs/latest/design/envoy-patch-policy.md | 5 +++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/api/v1alpha1/envoypatchpolicy_types.go b/api/v1alpha1/envoypatchpolicy_types.go index bcd393004d..f5e65a612b 100644 --- a/api/v1alpha1/envoypatchpolicy_types.go +++ b/api/v1alpha1/envoypatchpolicy_types.go @@ -30,7 +30,7 @@ type EnvoyPatchPolicy struct { Status EnvoyPatchPolicyStatus `json:"status"` } -// EnvoyPatchPolicySpec defines the desired state of RateLimitFilter. +// EnvoyPatchPolicySpec defines the desired state of EnvoyPatchPolicy. // +union type EnvoyPatchPolicySpec struct { // Type decides the type of patch. @@ -49,6 +49,13 @@ type EnvoyPatchPolicySpec struct { // for this Policy to have effect and be applied to the Gateway // TargetRef TargetRef gwapiv1a2.PolicyTargetReference `json:"targetRef"` + // Priority of the EnvoyPatchPolicy. + // If multiple EnvoyPatchPolicies are applied to the same + // TargetRef, they will be applied in the ascending order of + // the priority i.e. int32.min has the highest priority and + // int32.max has the lowest priority. + // Defaults to 0. + Priority int32 `json:"priority"` } // EnvoyPatchType specifies the types of Envoy patching mechanisms. diff --git a/docs/latest/api/extension_types.md b/docs/latest/api/extension_types.md index 740b3a7ec8..b69ecdd867 100644 --- a/docs/latest/api/extension_types.md +++ b/docs/latest/api/extension_types.md @@ -112,7 +112,7 @@ EnvoyPatchPolicyList contains a list of EnvoyPatchPolicy resources. -EnvoyPatchPolicySpec defines the desired state of RateLimitFilter. +EnvoyPatchPolicySpec defines the desired state of EnvoyPatchPolicy. _Appears in:_ - [EnvoyPatchPolicy](#envoypatchpolicy) @@ -122,6 +122,7 @@ _Appears in:_ | `type` _[EnvoyPatchType](#envoypatchtype)_ | Type decides the type of patch. Valid EnvoyPatchType values are "JSONPatch". | | `jsonPatches` _[EnvoyJSONPatchConfig](#envoyjsonpatchconfig) array_ | JSONPatch defines the JSONPatch configuration. | | `targetRef` _[PolicyTargetReference](#policytargetreference)_ | TargetRef is the name of the Gateway API resource this policy is being attached to. Currently only attaching to Gateway is supported This Policy and the TargetRef MUST be in the same namespace for this Policy to have effect and be applied to the Gateway TargetRef | +| `priority` _integer_ | Priority of the EnvoyPatchPolicy. If multiple EnvoyPatchPolicies are applied to the same TargetRef, they will be applied in the ascending order of the priority i.e. int32.min has the highest priority and int32.max has the lowest priority. Defaults to 0. | diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md index fb13fa94b6..e3d3c487d8 100644 --- a/docs/latest/design/envoy-patch-policy.md +++ b/docs/latest/design/envoy-patch-policy.md @@ -8,7 +8,7 @@ that Envoy Gateway generates before sending it to Envoy Proxy. Envoy Gateway allows users to configure networking and security intent using the upstream [Gateway API][] as well as implementation specific [Extension APIs][] defined in this project to provide a more batteries included experience for application developers. -* These APIs are an abstracted version of the underlying Envoy xDS API to provide a a better user experience for the application developer, exposing and setting only a subset of the fields for a specific feature, sometimes in a opinionated way (e.g [RateLimit][]) +* These APIs are an abstracted version of the underlying Envoy xDS API to provide a better user experience for the application developer, exposing and setting only a subset of the fields for a specific feature, sometimes in a opinionated way (e.g [RateLimit][]) * These APIs do not expose all the features capabilities that Envoy has either because these features are desired but the API is not defined yet or the project cannot support such an extensive list of features. To alleviate this problem, and provide an interim solution for a small section of advanced users who are well versed in @@ -126,9 +126,9 @@ patches will work. * This API will always be an experimental API and cannot be graduated into a stable API because Envoy Gateway cannot garuntee * that the naming scheme for the generated resources names will not change across releases * that the underlying Envoy Proxy API will not change across releases +* This API needs to be explictly enabled using the [EnvoyGateway][] API ## Open Questions -* Should this be an Opt In API disabled by default ? * Should the value only support JSON or YAML as well (which is a JSON superset) ? ## Alternatives @@ -144,6 +144,7 @@ patches will work. [Kustomize]: https://github.com/kubernetes-sigs/kustomize/blob/master/examples/jsonpatch.md [Extension APIs]: https://gateway.envoyproxy.io/latest/api/extension_types.html [RateLimit]: https://gateway.envoyproxy.io/latest/user/rate-limit.html +[EnvoyGateway]: https://gateway.envoyproxy.io/latest/api/config_types.html#envoygateway [Extending the Control Plane]: https://gateway.envoyproxy.io/latest/design/extending-envoy-gateway.html [EnvoyFilter]: https://istio.io/latest/docs/reference/config/networking/envoy-filter [egctl x translate]: https://gateway.envoyproxy.io/latest/user/egctl.html#egctl-experimental-translate From dc8b0e0c74dc0780bed3119ec65fffef899b0ac8 Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 30 May 2023 18:51:30 -0700 Subject: [PATCH 7/8] lint Signed-off-by: Arko Dasgupta --- docs/latest/design/envoy-patch-policy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/latest/design/envoy-patch-policy.md b/docs/latest/design/envoy-patch-policy.md index e3d3c487d8..1d7e82e15c 100644 --- a/docs/latest/design/envoy-patch-policy.md +++ b/docs/latest/design/envoy-patch-policy.md @@ -126,7 +126,7 @@ patches will work. * This API will always be an experimental API and cannot be graduated into a stable API because Envoy Gateway cannot garuntee * that the naming scheme for the generated resources names will not change across releases * that the underlying Envoy Proxy API will not change across releases -* This API needs to be explictly enabled using the [EnvoyGateway][] API +* This API needs to be explicitly enabled using the [EnvoyGateway][] API ## Open Questions * Should the value only support JSON or YAML as well (which is a JSON superset) ? From 28bb08e61cc0c459fdc8c78245aceea44ba6ae3f Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Tue, 30 May 2023 18:54:21 -0700 Subject: [PATCH 8/8] charts Signed-off-by: Arko Dasgupta --- .../gateway.envoyproxy.io_envoypatchpolicies.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml index 961b2327ec..0aa230ebb8 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoypatchpolicies.yaml @@ -78,6 +78,13 @@ spec: - type type: object type: array + priority: + description: Priority of the EnvoyPatchPolicy. If multiple EnvoyPatchPolicies + are applied to the same TargetRef, they will be applied in the ascending + order of the priority i.e. int32.min has the highest priority and + int32.max has the lowest priority. Defaults to 0. + format: int32 + type: integer targetRef: description: TargetRef is the name of the Gateway API resource this policy is being attached to. Currently only attaching to Gateway @@ -121,6 +128,7 @@ spec: - JSONPatch type: string required: + - priority - targetRef - type type: object