diff --git a/api/v1alpha1/backend_types.go b/api/v1alpha1/backend_types.go
index ceec9083492..4cc32696246 100644
--- a/api/v1alpha1/backend_types.go
+++ b/api/v1alpha1/backend_types.go
@@ -134,12 +134,31 @@ type BackendSpec struct {
// Endpoints defines the endpoints to be used when connecting to the backend.
//
// +kubebuilder:validation:MinItems=1
- // +kubebuilder:validation:MaxItems=64
- // +kubebuilder:validation:XValidation:rule="self.all(f, has(f.fqdn)) || !self.exists(f, has(f.fqdn))",message="fqdn addresses cannot be mixed with other address types"
- Endpoints []BackendEndpoint `json:"endpoints,omitempty"`
+ // +kubebuilder:validation:MaxItems=4
+ // +kubebuilder:validation:XValidation:rule="self.all(f, has(f.fqdn)) || !self.exists(f, has(f.fqdn))",message="fqdn addresses cannot be mixed with other address types"
+ // +optional Endpoints []BackendEndpoint `json:"endpoints,omitempty"`
// AppProtocols defines the application protocols to be supported when connecting to the backend.
- //
+ //
+ // +optional
+ AppProtocols []AppProtocolType `json:"appProtocols,omitempty"`
+
+ // FQDN defines the FQDN used to contact the backend.
+ //
+ // +kubebuilder:validation:MaxLength=253
+ // +optional
+ FQDN *string `json:"fqdn,omitempty"`
+
+ // Fallback indicates whether the backend is designated as a fallback.
+ // It is highly recommended to configure active or passive health checks to ensure that failover can be detected
+ // when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
+ // The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
+ // the health of the active backends falls below 72%.
+ //
+ // +optional
+ Fallback *bool `json:"fallback,omitempty"`
+
+ // TLS defines the TLS configuration for the backend. //
// +optional
AppProtocols []AppProtocolType `json:"appProtocols,omitempty"`
@@ -152,10 +171,26 @@ type BackendSpec struct {
// +optional
Fallback *bool `json:"fallback,omitempty"`
- // TLS defines the TLS settings for the backend.
- // TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
- // TLS.InsecureSkipVerify can be specified for any Backends
- //
+ //
+ // +optional
+ AppProtocols []AppProtocolType `json:"appProtocols,omitempty"`
+
+ // FQDN defines the FQDN used to contact the backend.
+ //
+ // +kubebuilder:validation:MaxLength=253
+ // +optional
+ FQDN *string `json:"fqdn,omitempty"`
+
+ // Fallback indicates whether the backend is designated as a fallback.
+ // It is highly recommended to configure active or passive health checks to ensure that failover can be detected
+ // when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
+ // The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
+ // the health of the active backends falls below 72%.
+ //
+ // +optional
+ Fallback *bool `json:"fallback,omitempty"`
+
+ // TLS defines the TLS configuration for the backend. //
// +optional
TLS *BackendTLSSettings `json:"tls,omitempty"`
}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 0ae6350b2b4..459a21f9d6b 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -464,18 +464,16 @@ func (in *BackendSpec) DeepCopyInto(out *BackendSpec) {
*out = new(BackendType)
**out = **in
}
- if in.Endpoints != nil {
- in, out := &in.Endpoints, &out.Endpoints
- *out = make([]BackendEndpoint, len(*in))
- for i := range *in {
- (*in)[i].DeepCopyInto(&(*out)[i])
- }
- }
if in.AppProtocols != nil {
in, out := &in.AppProtocols, &out.AppProtocols
*out = make([]AppProtocolType, len(*in))
copy(*out, *in)
}
+ if in.FQDN != nil {
+ in, out := &in.FQDN, &out.FQDN
+ *out = new(string)
+ **out = **in
+ }
if in.Fallback != nil {
in, out := &in.Fallback, &out.Fallback
*out = new(bool)
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
index 3688b15c9cc..26d1d882d08 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backends.yaml
@@ -140,7 +140,7 @@ spec:
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
- maxItems: 64
+ maxItems: 4
minItems: 1
type: array
x-kubernetes-validations:
@@ -154,11 +154,41 @@ spec:
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%.
type: boolean
- tls:
+ fqdn:
+ description: FQDN defines the FQDN used to contact the backend.
+ maxLength: 253
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ originalDestinationSettings:
description: |-
- TLS defines the TLS settings for the backend.
- TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
- TLS.InsecureSkipVerify can be specified for any Backends
+ OriginalDestinationSettings defines settings for Original Destination backend type.
+ This field is only valid when Type is "OriginalDestination".
+ properties:
+ allowedDestinations:
+ description: |-
+ AllowedDestinations specifies CIDR blocks or hostnames that are permitted
+ as routing destinations. If empty, all destinations are allowed.
+ Use this for security to prevent routing to unintended endpoints.
+
+ Examples:
+ - "10.0.0.0/8" (private networks)
+ - "backend.example.com" (specific hostname)
+ - "*.example.com" (wildcard hostname)
+ items:
+ type: string
+ maxItems: 20
+ type: array
+ header:
+ default: x-envoy-original-dst-host
+ description: |-
+ Header specifies the header name containing the destination address.
+ The header value must be in "host:port" format (e.g., "backend.example.com:8080").
+ If not specified, defaults to "x-envoy-original-dst-host".
+ pattern: ^[a-zA-Z0-9]([a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])?$
+ type: string
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for the backend.
properties:
caCertificateRefs:
description: |-
@@ -248,11 +278,16 @@ spec:
enum:
- Endpoints
- DynamicResolver
+ - OriginalDestination
type: string
type: object
x-kubernetes-validations:
- message: DynamicResolver type cannot have endpoints specified
rule: self.type != 'DynamicResolver' || !has(self.endpoints)
+ - message: OriginalDestination type cannot have endpoints specified
+ rule: self.type != 'OriginalDestination' || !has(self.endpoints)
+ - message: OriginalDestination type must specify originalDestinationSettings
+ rule: self.type != 'OriginalDestination' || has(self.originalDestinationSettings)
status:
description: Status defines the current status of Backend.
properties:
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
index a821ded07ee..f8deced3552 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backends.yaml
@@ -139,7 +139,7 @@ spec:
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
- maxItems: 64
+ maxItems: 4
minItems: 1
type: array
x-kubernetes-validations:
@@ -153,11 +153,41 @@ spec:
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%.
type: boolean
- tls:
+ fqdn:
+ description: FQDN defines the FQDN used to contact the backend.
+ maxLength: 253
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ originalDestinationSettings:
description: |-
- TLS defines the TLS settings for the backend.
- TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
- TLS.InsecureSkipVerify can be specified for any Backends
+ OriginalDestinationSettings defines settings for Original Destination backend type.
+ This field is only valid when Type is "OriginalDestination".
+ properties:
+ allowedDestinations:
+ description: |-
+ AllowedDestinations specifies CIDR blocks or hostnames that are permitted
+ as routing destinations. If empty, all destinations are allowed.
+ Use this for security to prevent routing to unintended endpoints.
+
+ Examples:
+ - "10.0.0.0/8" (private networks)
+ - "backend.example.com" (specific hostname)
+ - "*.example.com" (wildcard hostname)
+ items:
+ type: string
+ maxItems: 20
+ type: array
+ header:
+ default: x-envoy-original-dst-host
+ description: |-
+ Header specifies the header name containing the destination address.
+ The header value must be in "host:port" format (e.g., "backend.example.com:8080").
+ If not specified, defaults to "x-envoy-original-dst-host".
+ pattern: ^[a-zA-Z0-9]([a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])?$
+ type: string
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for the backend.
properties:
caCertificateRefs:
description: |-
@@ -247,11 +277,16 @@ spec:
enum:
- Endpoints
- DynamicResolver
+ - OriginalDestination
type: string
type: object
x-kubernetes-validations:
- message: DynamicResolver type cannot have endpoints specified
rule: self.type != 'DynamicResolver' || !has(self.endpoints)
+ - message: OriginalDestination type cannot have endpoints specified
+ rule: self.type != 'OriginalDestination' || !has(self.endpoints)
+ - message: OriginalDestination type must specify originalDestinationSettings
+ rule: self.type != 'OriginalDestination' || has(self.originalDestinationSettings)
status:
description: Status defines the current status of Backend.
properties:
diff --git a/internal/gatewayapi/backend.go b/internal/gatewayapi/backend.go
index 59a3cf5d0a8..09ca1622dea 100644
--- a/internal/gatewayapi/backend.go
+++ b/internal/gatewayapi/backend.go
@@ -41,25 +41,57 @@ func (t *Translator) ProcessBackends(backends []*egv1a1.Backend) []*egv1a1.Backe
}
func validateBackend(backend *egv1a1.Backend) status.Error {
- if backend.Spec.Type != nil &&
- *backend.Spec.Type == egv1a1.BackendTypeDynamicResolver {
- if len(backend.Spec.Endpoints) > 0 {
- return status.NewRouteStatusError(
- fmt.Errorf("DynamicResolver type cannot have endpoints specified"),
- status.RouteReasonInvalidBackendRef,
- )
- }
+ if backend.Spec.Type != nil {
+ switch *backend.Spec.Type {
+ case egv1a1.BackendTypeDynamicResolver:
+ if len(backend.Spec.Endpoints) > 0 {
+ return status.NewRouteStatusError(
+ fmt.Errorf("DynamicResolver type cannot have endpoints specified"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
- if backend.Spec.TLS != nil &&
- !ptr.Deref(backend.Spec.TLS.InsecureSkipVerify, false) &&
- backend.Spec.TLS.WellKnownCACertificates == nil &&
- len(backend.Spec.TLS.CACertificateRefs) == 0 {
- return status.NewRouteStatusError(
- fmt.Errorf("must specify either CACertificateRefs or WellKnownCACertificates for DynamicResolver type when InsecureSkipVerify is unset or false"),
- status.RouteReasonInvalidBackendRef,
- )
- }
+ if backend.Spec.TLS != nil &&
+ !ptr.Deref(backend.Spec.TLS.InsecureSkipVerify, false) &&
+ backend.Spec.TLS.WellKnownCACertificates == nil &&
+ len(backend.Spec.TLS.CACertificateRefs) == 0 {
+ return status.NewRouteStatusError(
+ fmt.Errorf("must specify either CACertificateRefs or WellKnownCACertificates for DynamicResolver type when InsecureSkipVerify is unset or false"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
+
+ case egv1a1.BackendTypeOriginalDestination:
+ if len(backend.Spec.Endpoints) > 0 {
+ return status.NewRouteStatusError(
+ fmt.Errorf("OriginalDestination type cannot have endpoints specified"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
+ if backend.Spec.OriginalDestinationSettings == nil {
+ return status.NewRouteStatusError(
+ fmt.Errorf("OriginalDestination type must have OriginalDestinationSettings specified"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
+
+ default:
+ if backend.Spec.TLS != nil {
+ if backend.Spec.TLS.WellKnownCACertificates != nil {
+ return status.NewRouteStatusError(
+ fmt.Errorf("TLS.WellKnownCACertificates settings can only be specified for DynamicResolver backends"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
+ if len(backend.Spec.TLS.CACertificateRefs) > 0 {
+ return status.NewRouteStatusError(
+ fmt.Errorf("TLS.CACertificateRefs settings can only be specified for DynamicResolver backends"),
+ status.RouteReasonInvalidBackendRef,
+ )
+ }
+ }
+ }
} else if backend.Spec.TLS != nil {
if backend.Spec.TLS.WellKnownCACertificates != nil {
return status.NewRouteStatusError(
diff --git a/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml b/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml
index 1d655683d02..112f1287502 100644
--- a/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml
+++ b/internal/gatewayapi/testdata/accesslog-als-backend.out.yaml
@@ -183,7 +183,7 @@ xdsIR:
name: backend-fqdn
namespace: envoy-gateway
name: accesslog_otel_0_0/backend/-1
- protocol: HTTP2
+ protocol: TCP
- addressType: IP
endpoints:
- host: 1.1.1.1
diff --git a/internal/gatewayapi/testdata/backend-with-fallback.out.yaml b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml
index cf6beeb9adc..682e1805386 100644
--- a/internal/gatewayapi/testdata/backend-with-fallback.out.yaml
+++ b/internal/gatewayapi/testdata/backend-with-fallback.out.yaml
@@ -184,7 +184,6 @@ xdsIR:
name: backend-2
namespace: default
name: httproute/default/httproute-1/rule/0/backend/1
- priority: 1
protocol: HTTP
weight: 1
hostname: '*'
diff --git a/internal/gatewayapi/testdata/envoyproxy-priority-backend.out.yaml b/internal/gatewayapi/testdata/envoyproxy-priority-backend.out.yaml
index a56756b74a0..900d030fa9b 100644
--- a/internal/gatewayapi/testdata/envoyproxy-priority-backend.out.yaml
+++ b/internal/gatewayapi/testdata/envoyproxy-priority-backend.out.yaml
@@ -49,19 +49,7 @@ backendTLSPolicies:
name: ca-cmap
hostname: ip-backend
status:
- ancestors:
- - ancestorRef:
- group: gateway.envoyproxy.io
- kind: EnvoyExtensionPolicy
- name: policy-for-http-route
- namespace: default
- conditions:
- - lastTransitionTime: null
- message: Policy has been accepted.
- reason: Accepted
- status: "True"
- type: Accepted
- controllerName: gateway.envoyproxy.io/gatewayclass-controller
+ ancestors: null
backends:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
@@ -123,7 +111,11 @@ envoyExtensionPolicies:
group: gateway.envoyproxy.io
kind: Backend
name: backend-ip-tls
+ - group: gateway.envoyproxy.io
+ kind: Backend
+ name: grpc-backend-2
namespace: envoy-gateway
+ port: 9000
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
@@ -138,9 +130,9 @@ envoyExtensionPolicies:
sectionName: http
conditions:
- lastTransitionTime: null
- message: Policy has been accepted.
- reason: Accepted
- status: "True"
+ message: 'ExtProc: backend envoy-gateway/grpc-backend-2 not found.'
+ reason: Invalid
+ status: "False"
type: Accepted
controllerName: gateway.envoyproxy.io/gatewayclass-controller
gateways:
@@ -320,75 +312,8 @@ xdsIR:
name: httproute/default/httproute-1/rule/0/backend/0
protocol: HTTP
weight: 1
- envoyExtensions:
- extProcs:
- - authority: grpc-backend.envoy-gateway:8000
- destination:
- metadata:
- kind: EnvoyExtensionPolicy
- name: policy-for-http-route
- namespace: default
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0
- settings:
- - addressType: IP
- metadata:
- kind: Service
- name: grpc-backend
- namespace: envoy-gateway
- sectionName: "8000"
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0/backend/0
- protocol: GRPC
- tls:
- alpnProtocols: null
- caCertificate:
- certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
- name: policy-btls-grpc/envoy-gateway-ca
- sni: grpc-backend
- weight: 1
- - addressType: IP
- endpoints:
- - host: 8.8.8.8
- port: 9000
- metadata:
- kind: Service
- name: grpc-backend-2
- namespace: default
- sectionName: "9000"
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0/backend/1
- priority: 1
- protocol: GRPC
- weight: 1
- - addressType: IP
- endpoints:
- - host: 1.1.1.1
- port: 3001
- metadata:
- kind: Backend
- name: backend-ip
- namespace: default
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0/backend/2
- priority: 1
- protocol: GRPC
- weight: 1
- - addressType: IP
- endpoints:
- - host: 2.2.2.2
- port: 3443
- metadata:
- kind: Backend
- name: backend-ip-tls
- namespace: envoy-gateway
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0/backend/3
- priority: 1
- protocol: GRPC
- tls:
- alpnProtocols: null
- caCertificate:
- certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lVQWw2VUtJdUttenRlODFjbGx6NVBmZE4ySWxJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHQTFVRUNnd0dhM1ZpWldSaU1CNFhEVEl6TVRBdwpNakExTkRFMU4xb1hEVEkwTVRBd01UQTFOREUxTjFvd0l6RVFNQTRHQTFVRUF3d0hiWGxqYVdWdWRERVBNQTBHCkExVUVDZ3dHYTNWaVpXUmlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdTVGMKMXlqOEhXNjJueW5rRmJYbzRWWEt2MmpDMFBNN2RQVmt5ODdGd2VaY1RLTG9XUVZQUUUycDJrTERLNk9Fc3ptTQp5eXIreHhXdHlpdmVyZW1yV3FuS2tOVFloTGZZUGhnUWtjemliN2VVYWxtRmpVYmhXZEx2SGFrYkVnQ29kbjNiCmt6NTdtSW5YMlZwaURPS2c0a3lIZml1WFdwaUJxckN4MEtOTHB4bzNERVFjRmNzUVRlVEh6aDQ3NTJHVjA0UlUKVGkvR0VXeXpJc2w0Umc3dEd0QXdtY0lQZ1VOVWZZMlEzOTBGR3FkSDRhaG4rbXcvNmFGYlczMVc2M2Q5WUpWcQppb3lPVmNhTUlwTTVCL2M3UWM4U3VoQ0kxWUdoVXlnNGNSSExFdzVWdGlraW95RTNYMDRrbmEzalFBajU0WWJSCmJwRWhjMzVhcEtMQjIxSE9VUUlEQVFBQm8xTXdVVEFkQmdOVkhRNEVGZ1FVeXZsMFZJNXZKVlN1WUZYdTdCNDgKNlBiTUVBb3dId1lEVlIwakJCZ3dGb0FVeXZsMFZJNXZKVlN1WUZYdTdCNDg2UGJNRUFvd0R3WURWUjBUQVFILwpCQVV3QXdFQi96QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFNTHhyZ0ZWTXVOUnEyd0F3Y0J0N1NuTlI1Q2Z6CjJNdlhxNUVVbXVhd0lVaTlrYVlqd2RWaURSRUdTams3SlcxN3ZsNTc2SGpEa2RmUndpNEUyOFN5ZFJJblpmNkoKaThIWmNaN2NhSDZEeFIzMzVmZ0hWekxpNU5pVGNlL09qTkJRelEyTUpYVkRkOERCbUc1ZnlhdEppT0pRNGJXRQpBN0ZsUDBSZFAzQ08zR1dFME01aVhPQjJtMXFXa0UyZXlPNFVIdndUcU5RTGRyZEFYZ0RRbGJhbTllNEJHM0dnCmQvNnRoQWtXRGJ0L1FOVCtFSkhEQ3ZoRFJLaDFSdUdIeWcrWSsvbmViVFdXckZXc2t0UnJiT29IQ1ppQ3BYSTEKM2VYRTZudDBZa2d0RHhHMjJLcW5ocEFnOWdVU3MyaGxob3h5dmt6eUYwbXU2TmhQbHdBZ25xNysvUT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
- name: policy-btls-backend-ip/envoy-gateway-ca
- sni: ip-backend
- weight: 1
- name: envoyextensionpolicy/default/policy-for-http-route/extproc/0
+ directResponse:
+ statusCode: 500
hostname: www.foo.com
isHTTP2: false
metadata:
diff --git a/internal/gatewayapi/testdata/httproute-dynamic-resolver.out.yaml b/internal/gatewayapi/testdata/httproute-dynamic-resolver.out.yaml
index e2da694bf10..35d06523a38 100644
--- a/internal/gatewayapi/testdata/httproute-dynamic-resolver.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-dynamic-resolver.out.yaml
@@ -202,7 +202,7 @@ xdsIR:
settings:
- isDynamicResolver: true
name: httproute/default/httproute-1/rule/0/backend/0
- protocol: HTTP2
+ protocol: HTTP
tls:
alpnProtocols: null
caCertificate:
diff --git a/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-app-protocols.out.yaml b/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-app-protocols.out.yaml
index 22d9b51958b..c24e74a906f 100644
--- a/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-app-protocols.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-rule-with-non-service-backends-and-app-protocols.out.yaml
@@ -221,7 +221,7 @@ xdsIR:
name: backend-mixed-ip-uds
namespace: default
name: httproute/default/httproute-1/rule/0/backend/1
- protocol: HTTP2
+ protocol: HTTP
weight: 1
hostname: '*'
isHTTP2: false
@@ -250,7 +250,7 @@ xdsIR:
name: backend-fqdn
namespace: default
name: httproute/default/httproute-2/rule/0/backend/0
- protocol: HTTP2
+ protocol: HTTP
weight: 1
hostname: '*'
isHTTP2: false
diff --git a/internal/xds/translator/cluster_test.go b/internal/xds/translator/cluster_test.go
index a05363a7a22..9f49177e537 100644
--- a/internal/xds/translator/cluster_test.go
+++ b/internal/xds/translator/cluster_test.go
@@ -47,6 +47,291 @@ func TestBuildXdsCluster(t *testing.T) {
assert.True(t, proto.Equal(bootstrapXdsCluster.ConnectTimeout, dynamicXdsCluster.ConnectTimeout))
}
+func TestCheckZoneAwareRouting(t *testing.T) {
+ tests := []struct {
+ name string
+ zoneRouting *ir.ZoneAwareRouting
+ loadBalancerCfg *ir.LoadBalancer
+ }{
+ {
+ name: "zone-routing with default lb",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{
+ LeastRequest: &ir.LeastRequest{},
+ },
+ },
+ {
+ name: "zone-routing with default lb and topology aware routing",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 3},
+ loadBalancerCfg: &ir.LoadBalancer{
+ LeastRequest: &ir.LeastRequest{},
+ },
+ },
+ {
+ name: "zone-routing with nil lb",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: nil,
+ },
+ {
+ name: "zone-routing with least request",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{
+ LeastRequest: &ir.LeastRequest{
+ SlowStart: &ir.SlowStart{Window: &metav1.Duration{Duration: 1 * time.Second}},
+ },
+ },
+ },
+ {
+ name: "zone-routing with round robin",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{
+ RoundRobin: &ir.RoundRobin{
+ SlowStart: &ir.SlowStart{Window: &metav1.Duration{Duration: 1 * time.Second}},
+ },
+ },
+ },
+ {
+ name: "zone-routing with random",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{Random: &ir.Random{}},
+ },
+ {
+ name: "zone-routing with maglev",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{
+ ConsistentHash: &ir.ConsistentHash{
+ TableSize: proto.Uint64(65537),
+ },
+ },
+ },
+ {
+ name: "zone-routing with round robin",
+ zoneRouting: &ir.ZoneAwareRouting{MinSize: 1},
+ loadBalancerCfg: &ir.LoadBalancer{
+ RoundRobin: &ir.RoundRobin{
+ SlowStart: &ir.SlowStart{Window: &metav1.Duration{Duration: 1 * time.Second}},
+ },
+ },
+ },
+ {
+ name: "zone-routing disabled",
+ zoneRouting: nil,
+ loadBalancerCfg: &ir.LoadBalancer{
+ LeastRequest: &ir.LeastRequest{},
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ bootstrapXdsCluster := getXdsClusterObjFromBootstrap(t)
+ ds := &ir.DestinationSetting{
+ Endpoints: []*ir.DestinationEndpoint{{Host: envoyGatewayXdsServerHost, Port: bootstrap.DefaultXdsServerPort}},
+ ZoneAwareRouting: tt.zoneRouting,
+ }
+ args := &xdsClusterArgs{
+ name: bootstrapXdsCluster.Name,
+ tSocket: bootstrapXdsCluster.TransportSocket,
+ endpointType: EndpointTypeDNS,
+ healthCheck: &ir.HealthCheck{
+ PanicThreshold: ptr.To[uint32](66),
+ },
+ loadBalancer: tt.loadBalancerCfg,
+ settings: []*ir.DestinationSetting{ds},
+ }
+ clusterResult, err := buildXdsCluster(args)
+ dynamicXdsCluster := clusterResult.cluster
+ require.NoError(t, err)
+
+ if tt.zoneRouting == nil {
+ require.Nil(t, dynamicXdsCluster.LoadBalancingPolicy)
+ require.Equal(t, &clusterv3.Cluster_CommonLbConfig_LocalityWeightedLbConfig_{LocalityWeightedLbConfig: &clusterv3.Cluster_CommonLbConfig_LocalityWeightedLbConfig{}}, dynamicXdsCluster.CommonLbConfig.LocalityConfigSpecifier)
+ } else {
+ require.Nil(t, dynamicXdsCluster.CommonLbConfig.LocalityConfigSpecifier)
+ expectedLoadBalancingPolicy := getExpectedClusterLbPolicies(tt.zoneRouting, dynamicXdsCluster.LbPolicy, args.loadBalancer)
+ require.Equal(t, expectedLoadBalancingPolicy.Policies[0].TypedExtensionConfig.Name, dynamicXdsCluster.LoadBalancingPolicy.Policies[0].TypedExtensionConfig.Name)
+ require.Equal(t, expectedLoadBalancingPolicy.Policies[0].GetTypedExtensionConfig().GetTypedConfig().String(), dynamicXdsCluster.LoadBalancingPolicy.Policies[0].GetTypedExtensionConfig().GetTypedConfig().String())
+ }
+ })
+ }
+}
+
+func getExpectedClusterLbPolicies(zoneRouting *ir.ZoneAwareRouting, policy clusterv3.Cluster_LbPolicy, lb *ir.LoadBalancer) *clusterv3.LoadBalancingPolicy {
+ localityLbConfig := &commonv3.LocalityLbConfig{
+ LocalityConfigSpecifier: &commonv3.LocalityLbConfig_ZoneAwareLbConfig_{
+ ZoneAwareLbConfig: &commonv3.LocalityLbConfig_ZoneAwareLbConfig{
+ MinClusterSize: wrapperspb.UInt64(1),
+ ForceLocalZone: &commonv3.LocalityLbConfig_ZoneAwareLbConfig_ForceLocalZone{
+ MinSize: wrapperspb.UInt32(uint32(zoneRouting.MinSize)),
+ },
+ },
+ },
+ }
+ leastRequest := &least_requestv3.LeastRequest{
+ LocalityLbConfig: localityLbConfig,
+ }
+ typedLeastRequest, _ := anypb.New(leastRequest)
+ loadBalancingPolicy := &clusterv3.LoadBalancingPolicy{
+ Policies: []*clusterv3.LoadBalancingPolicy_Policy{{
+ TypedExtensionConfig: &corev3.TypedExtensionConfig{
+ Name: "envoy.load_balancing_policies.least_request",
+ TypedConfig: typedLeastRequest,
+ },
+ }},
+ }
+
+ if lb == nil {
+ return loadBalancingPolicy
+ }
+ switch policy {
+ case clusterv3.Cluster_LEAST_REQUEST:
+ if lb.LeastRequest != nil && lb.LeastRequest.SlowStart != nil && lb.LeastRequest.SlowStart.Window != nil {
+ leastRequest.SlowStartConfig = &commonv3.SlowStartConfig{
+ SlowStartWindow: durationpb.New(lb.LeastRequest.SlowStart.Window.Duration),
+ }
+ }
+ loadBalancingPolicy.Policies[0].TypedExtensionConfig.TypedConfig, _ = anypb.New(leastRequest)
+ return loadBalancingPolicy
+ case clusterv3.Cluster_ROUND_ROBIN:
+ roundRobin := &round_robinv3.RoundRobin{
+ LocalityLbConfig: localityLbConfig,
+ }
+ if lb.RoundRobin.SlowStart != nil && lb.RoundRobin.SlowStart.Window != nil {
+ roundRobin.SlowStartConfig = &commonv3.SlowStartConfig{
+ SlowStartWindow: durationpb.New(lb.RoundRobin.SlowStart.Window.Duration),
+ }
+ }
+ typedRoundRobin, _ := anypb.New(roundRobin)
+ return &clusterv3.LoadBalancingPolicy{
+ Policies: []*clusterv3.LoadBalancingPolicy_Policy{{
+ TypedExtensionConfig: &corev3.TypedExtensionConfig{
+ Name: "envoy.load_balancing_policies.round_robin",
+ TypedConfig: typedRoundRobin,
+ },
+ }},
+ }
+ case clusterv3.Cluster_RANDOM:
+ random := &randomv3.Random{
+ LocalityLbConfig: localityLbConfig,
+ }
+ typeRandom, _ := anypb.New(random)
+ return &clusterv3.LoadBalancingPolicy{
+ Policies: []*clusterv3.LoadBalancingPolicy_Policy{{
+ TypedExtensionConfig: &corev3.TypedExtensionConfig{
+ Name: "envoy.load_balancing_policies.random",
+ TypedConfig: typeRandom,
+ },
+ }},
+ }
+ case clusterv3.Cluster_MAGLEV:
+ consistentHash := &maglevv3.Maglev{}
+ if lb.ConsistentHash.TableSize != nil {
+ consistentHash.TableSize = wrapperspb.UInt64(*lb.ConsistentHash.TableSize)
+ }
+ typedConsistentHash, _ := anypb.New(consistentHash)
+
+ return &clusterv3.LoadBalancingPolicy{
+ Policies: []*clusterv3.LoadBalancingPolicy_Policy{{
+ TypedExtensionConfig: &corev3.TypedExtensionConfig{
+ Name: "envoy.load_balancing_policies.maglev",
+ TypedConfig: typedConsistentHash,
+ },
+ }},
+ }
+
+ }
+ return nil
+}
+
+func TestBuildXdsClusterOriginalDestination(t *testing.T) {
+ tests := []struct {
+ name string
+ settings []*ir.DestinationSetting
+ expected *clusterv3.Cluster_OriginalDstLbConfig_
+ }{
+ {
+ name: "original destination with header",
+ settings: []*ir.DestinationSetting{
+ {
+ IsOriginalDestination: true,
+ OriginalDestinationSettings: &ir.OriginalDestinationSettings{
+ Header: ptr.To("target-host"),
+ },
+ },
+ },
+ expected: &clusterv3.Cluster_OriginalDstLbConfig_{
+ OriginalDstLbConfig: &clusterv3.Cluster_OriginalDstLbConfig{
+ UseHttpHeader: true,
+ HttpHeaderName: "target-host",
+ },
+ },
+ },
+ {
+ name: "original destination with custom header",
+ settings: []*ir.DestinationSetting{
+ {
+ IsOriginalDestination: true,
+ OriginalDestinationSettings: &ir.OriginalDestinationSettings{
+ Header: ptr.To("custom-target-header"),
+ AllowedDestinations: []string{"10.0.0.0/8"},
+ },
+ },
+ },
+ expected: &clusterv3.Cluster_OriginalDstLbConfig_{
+ OriginalDstLbConfig: &clusterv3.Cluster_OriginalDstLbConfig{
+ UseHttpHeader: true,
+ HttpHeaderName: "custom-target-header",
+ },
+ },
+ },
+ {
+ name: "normal destination",
+ settings: []*ir.DestinationSetting{
+ {
+ IsOriginalDestination: false,
+ Endpoints: []*ir.DestinationEndpoint{
+ {Host: "example.com", Port: 80},
+ },
+ },
+ },
+ expected: nil,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ args := &xdsClusterArgs{
+ name: "test-cluster",
+ settings: tt.settings,
+ endpointType: EndpointTypeOriginalDestination,
+ }
+
+ if !tt.settings[0].IsOriginalDestination {
+ args.endpointType = EndpointTypeStatic
+ }
+
+ result, err := buildXdsCluster(args)
+ require.NoError(t, err)
+ cluster := result.cluster
+
+ switch {
+ case tt.expected != nil:
+ // Check cluster type and load balancing policy
+ assert.Equal(t, clusterv3.Cluster_ORIGINAL_DST, cluster.ClusterDiscoveryType.(*clusterv3.Cluster_Type).Type)
+ assert.Equal(t, clusterv3.Cluster_CLUSTER_PROVIDED, cluster.LbPolicy)
+ assert.Equal(t, tt.expected, cluster.LbConfig)
+ case tt.settings[0].IsOriginalDestination:
+ // Original destination without header should still be ORIGINAL_DST type
+ assert.Equal(t, clusterv3.Cluster_ORIGINAL_DST, cluster.ClusterDiscoveryType.(*clusterv3.Cluster_Type).Type)
+ assert.Equal(t, clusterv3.Cluster_CLUSTER_PROVIDED, cluster.LbPolicy)
+ assert.Nil(t, cluster.LbConfig)
+ default:
+ // Normal destination should not be ORIGINAL_DST
+ assert.NotEqual(t, clusterv3.Cluster_ORIGINAL_DST, cluster.ClusterDiscoveryType.(*clusterv3.Cluster_Type).Type)
+ }
+ })
+ }
+}
+
func TestBuildXdsClusterLoadAssignment(t *testing.T) {
bootstrapXdsCluster := getXdsClusterObjFromBootstrap(t)
ds := &ir.DestinationSetting{
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 95ed18572f3..9214ddb6eee 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -352,7 +352,6 @@ BackendEndpoint describes a backend endpoint, which can be either a fully-qualif
corresponding to Envoy's Address: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/address.proto#config-core-v3-address
_Appears in:_
-- [BackendSpec](#backendspec)
- [ExtensionService](#extensionservice)
| Field | Type | Required | Default | Description |
@@ -403,10 +402,15 @@ _Appears in:_
| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `type` | _[BackendType](#backendtype)_ | false | Endpoints | Type defines the type of the backend. Defaults to "Endpoints" |
-| `endpoints` | _[BackendEndpoint](#backendendpoint) array_ | true | | Endpoints defines the endpoints to be used when connecting to the backend. |
| `appProtocols` | _[AppProtocolType](#appprotocoltype) array_ | false | | AppProtocols defines the application protocols to be supported when connecting to the backend. |
+| `fqdn` | _string_ | false | | FQDN defines the FQDN used to contact the backend. |
+| `fallback` | _boolean_ | false | | Fallback indicates whether the backend is designated as a fallback.
It is highly recommended to configure active or passive health checks to ensure that failover can be detected
when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%. |
+| `appProtocols` | _[AppProtocolType](#appprotocoltype) array_ | false | | TLS defines the TLS configuration for the backend. // |
+| `fallback` | _boolean_ | false | | Fallback indicates whether the backend is designated as a fallback.
It is highly recommended to configure active or passive health checks to ensure that failover can be detected
when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%. |
+| `appProtocols` | _[AppProtocolType](#appprotocoltype) array_ | false | | |
+| `fqdn` | _string_ | false | | FQDN defines the FQDN used to contact the backend. |
| `fallback` | _boolean_ | false | | Fallback indicates whether the backend is designated as a fallback.
It is highly recommended to configure active or passive health checks to ensure that failover can be detected
when the active backends become unhealthy and to automatically readjust once the primary backends are healthy again.
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%. |
-| `tls` | _[BackendTLSSettings](#backendtlssettings)_ | false | | TLS defines the TLS settings for the backend.
TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
TLS.InsecureSkipVerify can be specified for any Backends |
+| `tls` | _[BackendTLSSettings](#backendtlssettings)_ | false | | TLS defines the TLS configuration for the backend. // |
#### BackendStatus
diff --git a/test/cel-validation/backend_test.go b/test/cel-validation/backend_test.go
index 3ff5dca52e5..8ce737bd801 100644
--- a/test/cel-validation/backend_test.go
+++ b/test/cel-validation/backend_test.go
@@ -89,12 +89,6 @@ func TestBackend(t *testing.T) {
Port: 443,
},
},
- {
- FQDN: &egv1a1.FQDNEndpoint{
- Hostname: "sub.s.example.com",
- Port: 443,
- },
- },
},
}
},
@@ -255,7 +249,7 @@ func TestBackend(t *testing.T) {
mutate: func(backend *egv1a1.Backend) {
backend.Spec = egv1a1.BackendSpec{Type: ptr.To[egv1a1.BackendType]("FOO")}
},
- wantErrors: []string{`spec.type: Unsupported value: "FOO": supported values: "Endpoints", "DynamicResolver"`},
+ wantErrors: []string{`spec.type: Unsupported value: "FOO": supported values: "Endpoints", "DynamicResolver", "OriginalDestination"`},
},
{
desc: "dynamic resolver ok",
diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml
index 14f90f39a40..71eb84d5730 100644
--- a/test/helm/gateway-crds-helm/all.out.yaml
+++ b/test/helm/gateway-crds-helm/all.out.yaml
@@ -17452,7 +17452,7 @@ spec:
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
- maxItems: 64
+ maxItems: 4
minItems: 1
type: array
x-kubernetes-validations:
@@ -17466,11 +17466,41 @@ spec:
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%.
type: boolean
- tls:
+ fqdn:
+ description: FQDN defines the FQDN used to contact the backend.
+ maxLength: 253
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ originalDestinationSettings:
description: |-
- TLS defines the TLS settings for the backend.
- TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
- TLS.InsecureSkipVerify can be specified for any Backends
+ OriginalDestinationSettings defines settings for Original Destination backend type.
+ This field is only valid when Type is "OriginalDestination".
+ properties:
+ allowedDestinations:
+ description: |-
+ AllowedDestinations specifies CIDR blocks or hostnames that are permitted
+ as routing destinations. If empty, all destinations are allowed.
+ Use this for security to prevent routing to unintended endpoints.
+
+ Examples:
+ - "10.0.0.0/8" (private networks)
+ - "backend.example.com" (specific hostname)
+ - "*.example.com" (wildcard hostname)
+ items:
+ type: string
+ maxItems: 20
+ type: array
+ header:
+ default: x-envoy-original-dst-host
+ description: |-
+ Header specifies the header name containing the destination address.
+ The header value must be in "host:port" format (e.g., "backend.example.com:8080").
+ If not specified, defaults to "x-envoy-original-dst-host".
+ pattern: ^[a-zA-Z0-9]([a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])?$
+ type: string
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for the backend.
properties:
caCertificateRefs:
description: |-
@@ -17560,11 +17590,16 @@ spec:
enum:
- Endpoints
- DynamicResolver
+ - OriginalDestination
type: string
type: object
x-kubernetes-validations:
- message: DynamicResolver type cannot have endpoints specified
rule: self.type != 'DynamicResolver' || !has(self.endpoints)
+ - message: OriginalDestination type cannot have endpoints specified
+ rule: self.type != 'OriginalDestination' || !has(self.endpoints)
+ - message: OriginalDestination type must specify originalDestinationSettings
+ rule: self.type != 'OriginalDestination' || has(self.originalDestinationSettings)
status:
description: Status defines the current status of Backend.
properties:
diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
index 089a2574d62..fa4615901bd 100644
--- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
+++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
@@ -140,7 +140,7 @@ spec:
rule: ((has(self.fqdn) && !(has(self.ip) || has(self.unix))) ||
(has(self.ip) && !(has(self.fqdn) || has(self.unix))) || (has(self.unix)
&& !(has(self.ip) || has(self.fqdn))))
- maxItems: 64
+ maxItems: 4
minItems: 1
type: array
x-kubernetes-validations:
@@ -154,11 +154,41 @@ spec:
The overprovisioning factor is set to 1.4, meaning the fallback backends will only start receiving traffic when
the health of the active backends falls below 72%.
type: boolean
- tls:
+ fqdn:
+ description: FQDN defines the FQDN used to contact the backend.
+ maxLength: 253
+ pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
+ type: string
+ originalDestinationSettings:
description: |-
- TLS defines the TLS settings for the backend.
- TLS.CACertificateRefs and TLS.WellKnownCACertificates can only be specified for DynamicResolver backends.
- TLS.InsecureSkipVerify can be specified for any Backends
+ OriginalDestinationSettings defines settings for Original Destination backend type.
+ This field is only valid when Type is "OriginalDestination".
+ properties:
+ allowedDestinations:
+ description: |-
+ AllowedDestinations specifies CIDR blocks or hostnames that are permitted
+ as routing destinations. If empty, all destinations are allowed.
+ Use this for security to prevent routing to unintended endpoints.
+
+ Examples:
+ - "10.0.0.0/8" (private networks)
+ - "backend.example.com" (specific hostname)
+ - "*.example.com" (wildcard hostname)
+ items:
+ type: string
+ maxItems: 20
+ type: array
+ header:
+ default: x-envoy-original-dst-host
+ description: |-
+ Header specifies the header name containing the destination address.
+ The header value must be in "host:port" format (e.g., "backend.example.com:8080").
+ If not specified, defaults to "x-envoy-original-dst-host".
+ pattern: ^[a-zA-Z0-9]([a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9])?$
+ type: string
+ type: object
+ tls:
+ description: TLS defines the TLS configuration for the backend.
properties:
caCertificateRefs:
description: |-
@@ -248,11 +278,16 @@ spec:
enum:
- Endpoints
- DynamicResolver
+ - OriginalDestination
type: string
type: object
x-kubernetes-validations:
- message: DynamicResolver type cannot have endpoints specified
rule: self.type != 'DynamicResolver' || !has(self.endpoints)
+ - message: OriginalDestination type cannot have endpoints specified
+ rule: self.type != 'OriginalDestination' || !has(self.endpoints)
+ - message: OriginalDestination type must specify originalDestinationSettings
+ rule: self.type != 'OriginalDestination' || has(self.originalDestinationSettings)
status:
description: Status defines the current status of Backend.
properties: