diff --git a/api/v1alpha1/ext_proc_types.go b/api/v1alpha1/ext_proc_types.go
index c94682198b4..7499b9f8e4f 100644
--- a/api/v1alpha1/ext_proc_types.go
+++ b/api/v1alpha1/ext_proc_types.go
@@ -14,8 +14,26 @@ import (
//
// ExtProc defines the configuration for External Processing filter.
type ExtProc struct {
- // Service defines the configuration of the external processing service
+ // BackendRef defines the configuration of the external processing service
BackendRef ExtProcBackendRef `json:"backendRef"`
+
+ // BackendRefs defines the configuration of the external processing service
+ //
+ // +optional
+ BackendRefs []BackendRef `json:"backendRefs,omitempty"`
+
+ // MessageTimeout is the timeout for a response to be returned from the external processor
+ // Default: 200ms
+ //
+ // +optional
+ MessageTimeout *gwapiv1.Duration `json:"messageTimeout,omitempty"`
+
+ // FailOpen defines if requests or responses that cannot be processed due to connectivity to the
+ // external processor are terminated or passed-through.
+ // Default: false
+ //
+ // +optional
+ FailOpen *bool `json:"failOpen,omitempty"`
}
// ExtProcService defines the gRPC External Processing service using the envoy grpc client
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 1b0a97fa77a..0055d7669f1 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -1573,6 +1573,23 @@ func (in *ExtAuth) DeepCopy() *ExtAuth {
func (in *ExtProc) DeepCopyInto(out *ExtProc) {
*out = *in
in.BackendRef.DeepCopyInto(&out.BackendRef)
+ if in.BackendRefs != nil {
+ in, out := &in.BackendRefs, &out.BackendRefs
+ *out = make([]BackendRef, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ if in.MessageTimeout != nil {
+ in, out := &in.MessageTimeout, &out.MessageTimeout
+ *out = new(v1.Duration)
+ **out = **in
+ }
+ if in.FailOpen != nil {
+ in, out := &in.FailOpen, &out.FailOpen
+ *out = new(bool)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtProc.
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
index 37becdd417f..4861dd1fcc0 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
@@ -58,7 +58,7 @@ spec:
filter.
properties:
backendRef:
- description: Service defines the configuration of the external
+ description: BackendRef defines the configuration of the external
processing service
properties:
group:
@@ -134,6 +134,99 @@ spec:
- message: Must have port for Service reference
rule: '(size(self.group) == 0 && self.kind == ''Service'')
? has(self.port) : true'
+ backendRefs:
+ description: BackendRefs defines the configuration of the external
+ processing service
+ items:
+ description: BackendRef defines how an ObjectReference that
+ is specific to BackendRef.
+ properties:
+ group:
+ default: ""
+ description: |-
+ Group is the group of the referent. For example, "gateway.networking.k8s.io".
+ When unspecified or empty string, core API group is inferred.
+ maxLength: 253
+ pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ kind:
+ default: Service
+ description: |-
+ Kind is the Kubernetes resource kind of the referent. For example
+ "Service".
+
+
+ Defaults to "Service" when not specified.
+
+
+ ExternalName services can refer to CNAME DNS records that may live
+ outside of the cluster and as such are difficult to reason about in
+ terms of conformance. They also may not be safe to forward to (see
+ CVE-2021-25740 for more information). Implementations SHOULD NOT
+ support ExternalName Services.
+
+
+ Support: Core (Services with a type other than ExternalName)
+
+
+ Support: Implementation-specific (Services with type ExternalName)
+ 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 referent.
+ maxLength: 253
+ minLength: 1
+ type: string
+ namespace:
+ description: |-
+ Namespace is the namespace of the backend. When unspecified, the local
+ namespace is inferred.
+
+
+ Note that when a namespace different than the local namespace is specified,
+ a ReferenceGrant object is required in the referent namespace to allow that
+ namespace's owner to accept the reference. See the ReferenceGrant
+ documentation for details.
+
+
+ Support: Core
+ maxLength: 63
+ minLength: 1
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
+ type: string
+ port:
+ description: |-
+ Port specifies the destination port number to use for this resource.
+ Port is required when the referent is a Kubernetes Service. In this
+ case, the port number is the service port number, not the target port.
+ For other resources, destination port might be derived from the referent
+ resource or this field.
+ format: int32
+ maximum: 65535
+ minimum: 1
+ type: integer
+ required:
+ - name
+ type: object
+ x-kubernetes-validations:
+ - message: Must have port for Service reference
+ rule: '(size(self.group) == 0 && self.kind == ''Service'')
+ ? has(self.port) : true'
+ type: array
+ failOpen:
+ description: |-
+ FailOpen defines if requests or responses that cannot be processed due to connectivity to the
+ external processor are terminated or passed-through.
+ Default: false
+ type: boolean
+ messageTimeout:
+ description: |-
+ MessageTimeout is the timeout for a response to be returned from the external processor
+ Default: 200ms
+ pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$
+ type: string
required:
- backendRef
type: object
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 7c9b355fefb..a9847ac0645 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -192,6 +192,7 @@ BackendRef defines how an ObjectReference that is specific to BackendRef.
_Appears in:_
- [ALSEnvoyProxyAccessLog](#alsenvoyproxyaccesslog)
+- [ExtProc](#extproc)
- [OpenTelemetryEnvoyProxyAccessLog](#opentelemetryenvoyproxyaccesslog)
- [ProxyOpenTelemetrySink](#proxyopentelemetrysink)
- [TracingProvider](#tracingprovider)
@@ -1137,7 +1138,10 @@ _Appears in:_
| Field | Type | Required | Description |
| --- | --- | --- | --- |
-| `backendRef` | _[ExtProcBackendRef](#extprocbackendref)_ | true | Service defines the configuration of the external processing service |
+| `backendRef` | _[ExtProcBackendRef](#extprocbackendref)_ | true | BackendRef defines the configuration of the external processing service |
+| `backendRefs` | _[BackendRef](#backendref) array_ | false | BackendRefs defines the configuration of the external processing service |
+| `messageTimeout` | _[Duration](#duration)_ | false | MessageTimeout is the timeout for a response to be returned from the external processor
Default: 200ms |
+| `failOpen` | _boolean_ | false | FailOpen defines if requests or responses that cannot be processed due to connectivity to the
external processor are terminated or passed-through.
Default: false |
#### ExtProcBackendRef
diff --git a/test/cel-validation/envoyextensionpolicy_test.go b/test/cel-validation/envoyextensionpolicy_test.go
index 4a179c84ec3..2283212cd5c 100644
--- a/test/cel-validation/envoyextensionpolicy_test.go
+++ b/test/cel-validation/envoyextensionpolicy_test.go
@@ -15,9 +15,12 @@ import (
"testing"
"time"
+ "k8s.io/utils/ptr"
+
egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
)
@@ -151,6 +154,85 @@ func TestEnvoyExtensionPolicyTarget(t *testing.T) {
"spec.targetRef: Invalid value: \"object\": this policy does not yet support the sectionName field",
},
},
+
+ // ExtProc
+ {
+ desc: "ExtProc with BackendRef",
+ mutate: func(sp *egv1a1.EnvoyExtensionPolicy) {
+ sp.Spec = egv1a1.EnvoyExtensionPolicySpec{
+ ExtProc: []egv1a1.ExtProc{
+ {
+ BackendRef: egv1a1.ExtProcBackendRef{
+ BackendObjectReference: gwapiv1.BackendObjectReference{
+ Name: "grpc-proc-service",
+ Port: ptr.To(gwapiv1.PortNumber(80)),
+ },
+ },
+ },
+ },
+ TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{
+ PolicyTargetReference: gwapiv1a2.PolicyTargetReference{
+ Group: "gateway.networking.k8s.io",
+ Kind: "Gateway",
+ Name: "eg",
+ },
+ },
+ }
+ },
+ wantErrors: []string{},
+ },
+ {
+ desc: "ExtProc with invalid BackendRef Group",
+ mutate: func(sp *egv1a1.EnvoyExtensionPolicy) {
+ sp.Spec = egv1a1.EnvoyExtensionPolicySpec{
+ ExtProc: []egv1a1.ExtProc{
+ {
+ BackendRef: egv1a1.ExtProcBackendRef{
+ BackendObjectReference: gwapiv1.BackendObjectReference{
+ Group: ptr.To(gwapiv1.Group("unsupported")),
+ Name: "grpc-proc-service",
+ Port: ptr.To(gwapiv1.PortNumber(80)),
+ },
+ },
+ },
+ },
+ TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{
+ PolicyTargetReference: gwapiv1a2.PolicyTargetReference{
+ Group: "gateway.networking.k8s.io",
+ Kind: "Gateway",
+ Name: "eg",
+ },
+ },
+ }
+ },
+ wantErrors: []string{"spec.extProc[0]: Invalid value: \"object\": group is invalid, only the core API group (specified by omitting the group field or setting it to an empty string) is supported"},
+ },
+ {
+ desc: "ExtProc with invalid BackendRef Kind",
+ mutate: func(sp *egv1a1.EnvoyExtensionPolicy) {
+ sp.Spec = egv1a1.EnvoyExtensionPolicySpec{
+ ExtProc: []egv1a1.ExtProc{
+ {
+ BackendRef: egv1a1.ExtProcBackendRef{
+ BackendObjectReference: gwapiv1.BackendObjectReference{
+ Kind: ptr.To(gwapiv1.Kind("unsupported")),
+ Name: "grpc-proc-service",
+ Port: ptr.To(gwapiv1.PortNumber(80)),
+ },
+ },
+ },
+ },
+ TargetRef: gwapiv1a2.PolicyTargetReferenceWithSectionName{
+ PolicyTargetReference: gwapiv1a2.PolicyTargetReference{
+ Group: "gateway.networking.k8s.io",
+ Kind: "Gateway",
+ Name: "eg",
+ },
+ },
+ }
+ },
+ wantErrors: []string{"spec.extProc[0]: Invalid value: \"object\": kind is invalid, only Service (specified by omitting the kind field or setting it to 'Service') is supported"},
+ },
}
for _, tc := range cases {