Repository: envoyproxy/gateway

Issue:
Support serving binary data from ConfigMap
Hi and thank you for looking into this.

*Description*:
>Describe the desired behavior, what scenario it enables and how it
would be used.

At the moment, Envoy Gateway only supports text data as custom responses as defined in https://gateway.envoyproxy.io/docs/api/extension_types/#customresponsebody. However, there are clear use cases where it is necessary to support sending binary data. 

Our use case is to serve a static favicon.ico from binary data injected into the `binaryData` section of a ConfigMap, in the same way as it supports text data in the `data` section. The `binaryData` could serve simple binary canned responses that it would load from base64-encoded `binaryData` sections of a ConfigMap.

At the moment, the `binaryData` section of ConfigMaps are ignored by Envoy Gateway, and base64 encoded strings are served as-is (as would be expected) as text from `data` sections

[optional *Relevant Links*:]
>Any extra documentation required to understand the issue.

https://gateway.envoyproxy.io/docs/api/extension_types/#customresponsebody
https://gateway.envoyproxy.io/docs/tasks/traffic/direct-response/

Link to Slack discussion:
https://envoyproxy.slack.com/archives/C03E6NHLESV/p1749135140143769


Hints from issue comments:
@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@cnvergence: I will take a look :)@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@reinvantveer: @cnvergence did you see anything of your liking? 😉 @cnvergence: @reinvantveer was too optimistic, I will send PR next week@github-actions: This issue has been automatically marked as stale because it has not had activity in the last 30 days.@reinvantveer: Looks like this is nearly done?@cnvergence: Yes, had some time to take a look into it, binaryData comes from the configmap properly.
Need to just check out few things on the xDS side

Solution patch:
diff --git a/api/v1alpha1/healthcheck_types.go b/api/v1alpha1/healthcheck_types.go
index e5477c2be..7fd1cd6a1 100644
--- a/api/v1alpha1/healthcheck_types.go
+++ b/api/v1alpha1/healthcheck_types.go
@@ -52,7 +52,6 @@ type PassiveHealthCheck struct {
 
 	// ConsecutiveGatewayErrors sets the number of consecutive gateway errors triggering ejection.
 	//
-	// +kubebuilder:default=0
 	// +optional
 	ConsecutiveGatewayErrors *uint32 `json:"consecutiveGatewayErrors,omitempty"`
 
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
index 3328819ad..767dfd67d 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
@@ -526,7 +526,6 @@ spec:
                         format: int32
                         type: integer
                       consecutiveGatewayErrors:
-                        default: 0
                         description: ConsecutiveGatewayErrors sets the number of consecutive
                           gateway errors triggering ejection.
                         format: int32
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
index d21a88167..2d057a35f 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
@@ -594,7 +594,6 @@ spec:
                                   format: int32
                                   type: integer
                                 consecutiveGatewayErrors:
-                                  default: 0
                                   description: ConsecutiveGatewayErrors sets the number
                                     of consecutive gateway errors triggering ejection.
                                   format: int32
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml
index a5ead902f..e177a4e41 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml
@@ -11559,7 +11559,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -12690,7 +12689,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -13917,7 +13915,6 @@ spec:
                                               format: int32
                                               type: integer
                                             consecutiveGatewayErrors:
-                                              default: 0
                                               description: ConsecutiveGatewayErrors
                                                 sets the number of consecutive gateway
                                                 errors triggering ejection.
@@ -15051,7 +15048,6 @@ spec:
                                         format: int32
                                         type: integer
                                       consecutiveGatewayErrors:
-                                        default: 0
                                         description: ConsecutiveGatewayErrors sets
                                           the number of consecutive gateway errors
                                           triggering ejection.
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
index e6580fe45..c91bef867 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml
@@ -1110,7 +1110,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -2135,7 +2134,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -3371,7 +3369,6 @@ spec:
                                           format: int32
                                           type: integer
                                         consecutiveGatewayErrors:
-                                          default: 0
                                           description: ConsecutiveGatewayErrors sets
                                             the number of consecutive gateway errors
                                             triggering ejection.
@@ -4664,7 +4661,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
index 9d1adddb9..5df1439aa 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
@@ -525,7 +525,6 @@ spec:
                         format: int32
                         type: integer
                       consecutiveGatewayErrors:
-                        default: 0
                         description: ConsecutiveGatewayErrors sets the number of consecutive
                           gateway errors triggering ejection.
                         format: int32
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 49025b85a..d11914c0a 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyextensionpolicies.yaml
@@ -593,7 +593,6 @@ spec:
                                   format: int32
                                   type: integer
                                 consecutiveGatewayErrors:
-                                  default: 0
                                   description: ConsecutiveGatewayErrors sets the number
                                     of consecutive gateway errors triggering ejection.
                                   format: int32
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
index d484010ca..9df7e75ef 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml
@@ -11558,7 +11558,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -12689,7 +12688,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -13916,7 +13914,6 @@ spec:
                                               format: int32
                                               type: integer
                                             consecutiveGatewayErrors:
-                                              default: 0
                                               description: ConsecutiveGatewayErrors
                                                 sets the number of consecutive gateway
                                                 errors triggering ejection.
@@ -15050,7 +15047,6 @@ spec:
                                         format: int32
                                         type: integer
                                       consecutiveGatewayErrors:
-                                        default: 0
                                         description: ConsecutiveGatewayErrors sets
                                           the number of consecutive gateway errors
                                           triggering ejection.
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
index c9b472819..18d6a561a 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml
@@ -1109,7 +1109,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -2134,7 +2133,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -3370,7 +3368,6 @@ spec:
                                           format: int32
                                           type: integer
                                         consecutiveGatewayErrors:
-                                          default: 0
                                           description: ConsecutiveGatewayErrors sets
                                             the number of consecutive gateway errors
                                             triggering ejection.
@@ -4663,7 +4660,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go
index 7e514b76a..dbd54f4d9 100644
--- a/internal/gatewayapi/backendtrafficpolicy.go
+++ b/internal/gatewayapi/backendtrafficpolicy.go
@@ -1138,11 +1138,11 @@ func buildResponseOverride(policy *egv1a1.BackendTrafficPolicy, resources *resou
 	}, nil
 }
 
-func checkResponseBodySize(b *string) error {
+func checkResponseBodySize(b []byte) error {
 	// Make this configurable in the future
 	// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route.proto.html#max_direct_response_body_size_bytes
 	maxDirectResponseSize := 4096
-	lenB := len(*b)
+	lenB := len(b)
 	if lenB > maxDirectResponseSize {
 		return fmt.Errorf("response.body size %d greater than the max size %d", lenB, maxDirectResponseSize)
 	}
@@ -1150,38 +1150,45 @@ func checkResponseBodySize(b *string) error {
 	return nil
 }
 
-func getCustomResponseBody(body *egv1a1.CustomResponseBody, resources *resource.Resources, policyNs string) (*string, error) {
+func getCustomResponseBody(body *egv1a1.CustomResponseBody, resources *resource.Resources, policyNs string) ([]byte, error) {
 	if body != nil && body.Type != nil && *body.Type == egv1a1.ResponseValueTypeValueRef {
 		cm := resources.GetConfigMap(policyNs, string(body.ValueRef.Name))
 		if cm != nil {
 			b, dataOk := cm.Data["response.body"]
 			switch {
 			case dataOk:
-				if err := checkResponseBodySize(&b); err != nil {
+				body := []byte(b)
+				if err := checkResponseBodySize(body); err != nil {
 					return nil, err
 				}
-				return &b, nil
+				return body, nil
 			case len(cm.Data) > 0: // Fallback to the first key if response.body is not found
 				for _, value := range cm.Data {
-					b = value
-					break
+					body := []byte(value)
+					if err := checkResponseBodySize(body); err != nil {
+						return nil, err
+					}
+					return body, nil
 				}
-				if err := checkResponseBodySize(&b); err != nil {
-					return nil, err
+			case len(cm.BinaryData) > 0:
+				for _, binData := range cm.BinaryData {
+					if err := checkResponseBodySize(binData); err != nil {
+						return nil, err
+					}
+					return binData, nil
 				}
-				return &b, nil
 			default:
 				return nil, fmt.Errorf("can't find the key response.body in the referenced configmap %s", body.ValueRef.Name)
 			}
-
 		} else {
 			return nil, fmt.Errorf("can't find the referenced configmap %s", body.ValueRef.Name)
 		}
 	} else if body != nil && body.Inline != nil {
-		if err := checkResponseBodySize(body.Inline); err != nil {
+		inlineValue := []byte(*body.Inline)
+		if err := checkResponseBodySize(inlineValue); err != nil {
 			return nil, err
 		}
-		return body.Inline, nil
+		return inlineValue, nil
 	}
 
 	return nil, nil
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 0f34c3f17..0a21c08cf 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -625,7 +625,7 @@ type CustomResponse struct {
 	ContentType *string `json:"contentType,omitempty"`
 
 	// Body of the Custom Response
-	Body *string `json:"body,omitempty"`
+	Body []byte `json:"body,omitempty"`
 
 	// StatusCode will be used for the response's status code.
 	StatusCode *uint32 `json:"statusCode,omitempty"`
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index dd166963f..1c1a29f0f 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -784,8 +784,8 @@ func (in *CustomResponse) DeepCopyInto(out *CustomResponse) {
 	}
 	if in.Body != nil {
 		in, out := &in.Body, &out.Body
-		*out = new(string)
-		**out = **in
+		*out = make([]byte, len(*in))
+		copy(*out, *in)
 	}
 	if in.StatusCode != nil {
 		in, out := &in.StatusCode, &out.StatusCode
diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go
index bc2fe23cf..7b16dce31 100644
--- a/internal/provider/kubernetes/predicates.go
+++ b/internal/provider/kubernetes/predicates.go
@@ -181,6 +181,28 @@ func (r *gatewayAPIReconciler) validateSecretForReconcile(secret *corev1.Secret)
 		}
 	}
 
+	if !r.backendAPIDisabled() {
+		if r.isBackendReferencingSecret(&nsName) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (r *gatewayAPIReconciler) isBackendReferencingSecret(nsName *types.NamespacedName) bool {
+	backendList := &egv1a1.BackendList{}
+	if err := r.client.List(context.Background(), backendList, &client.ListOptions{
+		FieldSelector: fields.OneTermEqualSelector(secretBackendIndex, nsName.String()),
+	}); err != nil {
+		r.log.Error(err, "unable to find associated Backend")
+		return false
+	}
+
+	if len(backendList.Items) > 0 {
+		return true
+	}
+
 	return false
 }
 
@@ -881,6 +903,20 @@ func (r *gatewayAPIReconciler) validateConfigMapForReconcile(obj client.Object)
 		}
 	}
 
+	if !r.backendAPIDisabled() {
+		backendList := &egv1a1.BackendList{}
+		if err := r.client.List(context.Background(), backendList, &client.ListOptions{
+			FieldSelector: fields.OneTermEqualSelector(configMapBackendIndex, utils.NamespacedName(configMap).String()),
+		}); err != nil {
+			r.log.Error(err, "unable to find associated Backend")
+			return false
+		}
+
+		if len(backendList.Items) > 0 {
+			return true
+		}
+	}
+
 	return false
 }
 
diff --git a/internal/xds/translator/cluster.go b/internal/xds/translator/cluster.go
index 72cc142da..8ce566714 100644
--- a/internal/xds/translator/cluster.go
+++ b/internal/xds/translator/cluster.go
@@ -604,6 +604,7 @@ func buildXdsOutlierDetection(outlierDetection *ir.OutlierDetection) *clusterv3.
 	}
 
 	if outlierDetection.ConsecutiveGatewayErrors != nil {
+		od.EnforcingConsecutiveGatewayFailure = wrapperspb.UInt32(100)
 		od.ConsecutiveGatewayFailure = wrapperspb.UInt32(*outlierDetection.ConsecutiveGatewayErrors)
 	}
 
diff --git a/internal/xds/translator/custom_response.go b/internal/xds/translator/custom_response.go
index 2d6eedaaf..64a4c2fd7 100644
--- a/internal/xds/translator/custom_response.go
+++ b/internal/xds/translator/custom_response.go
@@ -422,10 +422,10 @@ func (c *customResponse) buildRedirectAction(r ir.ResponseOverrideRule) (*anypb.
 func (c *customResponse) buildResponseAction(r ir.ResponseOverrideRule) (*anypb.Any, error) {
 	response := &policyv3.LocalResponsePolicy{}
 
-	if r.Response.Body != nil && *r.Response.Body != "" {
+	if len(r.Response.Body) > 0 {
 		response.BodyFormat = &corev3.SubstitutionFormatString{
 			Format: &corev3.SubstitutionFormatString_TextFormat{
-				TextFormat: *r.Response.Body,
+				TextFormat: string(r.Response.Body),
 			},
 		}
 	}
diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go
index 6100369fd..32754c822 100644
--- a/internal/xds/translator/route.go
+++ b/internal/xds/translator/route.go
@@ -524,10 +524,10 @@ func buildXdsDirectResponseAction(res *ir.CustomResponse) *routev3.DirectRespons
 		routeAction.Status = *res.StatusCode
 	}
 
-	if res.Body != nil && *res.Body != "" {
+	if len(res.Body) > 0 {
 		routeAction.Body = &corev3.DataSource{
-			Specifier: &corev3.DataSource_InlineString{
-				InlineString: *res.Body,
+			Specifier: &corev3.DataSource_InlineBytes{
+				InlineBytes: res.Body,
 			},
 		}
 	}
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index b95ceb04e..c9245da64 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -7,6 +7,7 @@ breaking changes: |
   When a Backend resource specifies TLS settings and SNI is not specified or a BackendTLSPolicy is not attached to it, the upstream certificate is validated for DNS SAN matching the SNI value sent.
   When a MirrorPolicy is used, the shadow host suffix is not appended to the mirrored cluster name.
   When running `egctl experimental collect`, SDS will not be dumped, you can enable it by adding `--sds true`.
+  When setting the 'consecutiveGatewayFailure' will 'enforcingConsecutiveGatewayFailure set to 100.
 
 # Updates addressing vulnerabilities, security flaws, or compliance requirements.
 security updates: |
@@ -23,6 +24,7 @@ new features: |
   Added support for OCSP stapling in the listener TLS certificates.
   Added support for returning 503 responses when no valid backend endpoints exist.
   Added support for CSRFTokenTTL in OIDC authn to configure the lifetime of the CSRF token used during the OAuth2 authorization code flow.
+  Added support for binaryData in ConfigMap referenced by HTTPRouteFilter for direct response.
 
 
 bug fixes: |



Test patch:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
index ce3cafb9e..7de0e69d3 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
@@ -524,7 +524,7 @@ xdsIR:
                   name: X-Set-Header
                   value:
                   - set-404
-                body: gateway-1 Not Found
+                body: Z2F0ZXdheS0xIE5vdCBGb3VuZA==
                 contentType: text/plain
             - match:
                 statusCodes:
@@ -534,10 +534,7 @@ xdsIR:
                     start: 501
               name: backendtrafficpolicy/default/policy-for-gateway/responseoverride/rule/1
               response:
-                body: |
-                  {
-                    "error": "Internal Server Error"
-                  }
+                body: ewogICJlcnJvciI6ICJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3IiCn0K
                 contentType: application/json
     readyListener:
       address: 0.0.0.0
@@ -622,7 +619,7 @@ xdsIR:
                 - value: 404
               name: backendtrafficpolicy/default/policy-for-route-1/responseoverride/rule/0
               response:
-                body: httproute-1 Not Found
+                body: aHR0cHJvdXRlLTEgTm90IEZvdW5k
                 contentType: text/plain
             - match:
                 statusCodes:
@@ -632,10 +629,7 @@ xdsIR:
                     start: 501
               name: backendtrafficpolicy/default/policy-for-route-1/responseoverride/rule/1
               response:
-                body: |
-                  {
-                    "error": "Internal Server Error"
-                  }
+                body: ewogICJlcnJvciI6ICJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3IiCn0K
                 contentType: application/json
       - destination:
           metadata:
diff --git a/internal/gatewayapi/testdata/httproute-with-direct-response.in.yaml b/internal/gatewayapi/testdata/httproute-with-direct-response.in.yaml
index 64344d2e0..f481e9286 100644
--- a/internal/gatewayapi/testdata/httproute-with-direct-response.in.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-direct-response.in.yaml
@@ -88,6 +88,27 @@ httpRoutes:
           group: gateway.envoyproxy.io
           kind: HTTPRouteFilter
           name: direct-response-too-long
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    name: direct-response-binary
+    namespace: default
+  spec:
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          type: PathPrefix
+          value: /logo
+      filters:
+      - type: ExtensionRef
+        extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: direct-response-binary-logo
 configMaps:
 - apiVersion: v1
   kind: ConfigMap
@@ -96,6 +117,13 @@ configMaps:
     namespace: default
   data:
     response.body: '{"error": "Internal Server Error"}'
+- apiVersion: v1
+  kind: ConfigMap
+  metadata:
+    name: logo-binary-data
+    namespace: default
+  binaryData:
+    logo.png: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
 httpFilters:
 - apiVersion: gateway.envoyproxy.io/v1alpha1
   kind: HTTPRouteFilter
@@ -156,3 +184,18 @@ httpFilters:
       body:
         type: Inline
         inline: "-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: HTTPRouteFilter
+  metadata:
+    name: direct-response-binary-logo
+    namespace: default
+  spec:
+    directResponse:
+      contentType: image/png
+      statusCode: 502
+      body:
+        type: ValueRef
+        valueRef:
+          group: ""
+          kind: ConfigMap
+          name: logo-binary-data
diff --git a/internal/gatewayapi/testdata/httproute-with-direct-response.out.yaml b/internal/gatewayapi/testdata/httproute-with-direct-response.out.yaml
index a14145bcb..fe51435fe 100644
--- a/internal/gatewayapi/testdata/httproute-with-direct-response.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-direct-response.out.yaml
@@ -16,7 +16,7 @@ gateways:
       protocol: HTTP
   status:
     listeners:
-    - attachedRoutes: 3
+    - attachedRoutes: 4
       conditions:
       - lastTransitionTime: null
         message: Sending translated listener configuration to the data plane
@@ -168,6 +168,45 @@ httpRoutes:
         name: gateway-1
         namespace: envoy-gateway
         sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    name: direct-response-binary
+    namespace: default
+  spec:
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: direct-response-binary-logo
+        type: ExtensionRef
+      matches:
+      - path:
+          type: PathPrefix
+          value: /logo
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
 infraIR:
   envoy-gateway/gateway-1:
     proxy:
@@ -243,7 +282,7 @@ xdsIR:
           value:
           - set-502
         directResponse:
-          body: '{"error": "Internal Server Error"}'
+          body: eyJlcnJvciI6ICJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3IifQ==
           statusCode: 502
         hostname: '*.envoyproxy.io'
         isHTTP2: false
@@ -262,7 +301,7 @@ xdsIR:
           value:
           - text/plain
         directResponse:
-          body: OK
+          body: T0s=
           statusCode: 200
         hostname: '*.envoyproxy.io'
         isHTTP2: false
@@ -275,6 +314,25 @@ xdsIR:
           distinct: false
           name: ""
           prefix: /inline
+      - addResponseHeaders:
+        - append: false
+          name: Content-Type
+          value:
+          - image/png
+        directResponse:
+          body: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
+          statusCode: 502
+        hostname: '*.envoyproxy.io'
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: direct-response-binary
+          namespace: default
+        name: httproute/default/direct-response-binary/rule/0/match/0/*_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /logo
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go
index 425189f2b..be42beef7 100644
--- a/internal/provider/kubernetes/predicates_test.go
+++ b/internal/provider/kubernetes/predicates_test.go
@@ -186,6 +186,29 @@ func TestValidateConfigMapForReconcile(t *testing.T) {
 		configMap client.Object
 		expect    bool
 	}{
+		{
+			name: "references Backend TLS config map",
+			configs: []client.Object{
+				&egv1a1.Backend{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "static-backend",
+						Namespace: "default",
+					},
+					Spec: egv1a1.BackendSpec{
+						TLS: &egv1a1.BackendTLSSettings{
+							CACertificateRefs: []gwapiv1.LocalObjectReference{
+								{
+									Kind: gwapiv1.Kind(resource.KindConfigMap),
+									Name: gwapiv1.ObjectName("backend-ca"),
+								},
+							},
+						},
+					},
+				},
+			},
+			configMap: test.GetConfigMap(types.NamespacedName{Namespace: "default", Name: "backend-ca"}, make(map[string]string), make(map[string]string)),
+			expect:    true,
+		},
 		{
 			name: "references EnvoyExtensionPolicy Lua config map",
 			configs: []client.Object{
@@ -266,17 +289,24 @@ func TestValidateConfigMapForReconcile(t *testing.T) {
 	logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo)
 
 	r := gatewayAPIReconciler{
-		classController: egv1a1.GatewayControllerName,
-		log:             logger,
-		spCRDExists:     true,
-		epCRDExists:     true,
-		eepCRDExists:    true,
+		classController:  egv1a1.GatewayControllerName,
+		log:              logger,
+		backendCRDExists: true,
+		eepCRDExists:     true,
+		envoyGateway: &egv1a1.EnvoyGateway{
+			EnvoyGatewaySpec: egv1a1.EnvoyGatewaySpec{
+				ExtensionAPIs: &egv1a1.ExtensionAPISettings{
+					EnableBackend: true,
+				},
+			},
+		},
 	}
 
 	for _, tc := range testCases {
 		r.client = fakeclient.NewClientBuilder().
 			WithScheme(envoygateway.GetScheme()).
 			WithObjects(tc.configs...).
+			WithIndex(&egv1a1.Backend{}, configMapBackendIndex, configMapBackendIndexFunc).
 			WithIndex(&egv1a1.EnvoyExtensionPolicy{}, configMapEepIndex, configMapEepIndexFunc).
 			Build()
 		t.Run(tc.name, func(t *testing.T) {
@@ -346,6 +376,29 @@ func TestValidateSecretForReconcile(t *testing.T) {
 		secret  *corev1.Secret
 		expect  bool
 	}{
+		{
+			name: "backend references TLS secret",
+			configs: []client.Object{
+				&egv1a1.Backend{
+					ObjectMeta: metav1.ObjectMeta{
+						Namespace: "default",
+						Name:      "secure-backend",
+					},
+					Spec: egv1a1.BackendSpec{
+						TLS: &egv1a1.BackendTLSSettings{
+							CACertificateRefs: []gwapiv1.LocalObjectReference{
+								{
+									Kind: gwapiv1.Kind(resource.KindSecret),
+									Name: gwapiv1.ObjectName("backend-ca-secret"),
+								},
+							},
+						},
+					},
+				},
+			},
+			secret: test.GetSecret(types.NamespacedName{Namespace: "default", Name: "backend-ca-secret"}),
+			expect: true,
+		},
 		{
 			name: "envoy proxy references a secret",
 			configs: []client.Object{
@@ -535,11 +588,19 @@ func TestValidateSecretForReconcile(t *testing.T) {
 	logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo)
 
 	r := gatewayAPIReconciler{
-		classController: egv1a1.GatewayControllerName,
-		log:             logger,
-		spCRDExists:     true,
-		epCRDExists:     true,
-		eepCRDExists:    true,
+		classController:  egv1a1.GatewayControllerName,
+		log:              logger,
+		backendCRDExists: true,
+		spCRDExists:      true,
+		epCRDExists:      true,
+		eepCRDExists:     true,
+		envoyGateway: &egv1a1.EnvoyGateway{
+			EnvoyGatewaySpec: egv1a1.EnvoyGatewaySpec{
+				ExtensionAPIs: &egv1a1.ExtensionAPISettings{
+					EnableBackend: true,
+				},
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -550,6 +611,7 @@ func TestValidateSecretForReconcile(t *testing.T) {
 			WithIndex(&egv1a1.SecurityPolicy{}, secretSecurityPolicyIndex, secretSecurityPolicyIndexFunc).
 			WithIndex(&egv1a1.EnvoyProxy{}, secretEnvoyProxyIndex, secretEnvoyProxyIndexFunc).
 			WithIndex(&egv1a1.EnvoyExtensionPolicy{}, secretEnvoyExtensionPolicyIndex, secretEnvoyExtensionPolicyIndexFunc).
+			WithIndex(&egv1a1.Backend{}, secretBackendIndex, secretBackendIndexFunc).
 			Build()
 		t.Run(tc.name, func(t *testing.T) {
 			res := r.validateSecretForReconcile(tc.secret)
diff --git a/internal/xds/translator/cluster_test.go b/internal/xds/translator/cluster_test.go
index e8f444806..6127fded2 100644
--- a/internal/xds/translator/cluster_test.go
+++ b/internal/xds/translator/cluster_test.go
@@ -11,10 +11,10 @@ import (
 
 	bootstrapv3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
 	clusterv3 "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
-	"github.com/stretchr/testify/assert"
+	"github.com/google/go-cmp/cmp"
 	"github.com/stretchr/testify/require"
 	"google.golang.org/protobuf/encoding/protojson"
-	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/testing/protocmp"
 	"google.golang.org/protobuf/types/known/durationpb"
 	"google.golang.org/protobuf/types/known/wrapperspb"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -32,6 +32,7 @@ const (
 
 func TestBuildXdsCluster(t *testing.T) {
 	bootstrapXdsCluster := getXdsClusterObjFromBootstrap(t)
+	require.NotNil(t, bootstrapXdsCluster)
 
 	args := &xdsClusterArgs{
 		name:         bootstrapXdsCluster.Name,
@@ -47,19 +48,20 @@ func TestBuildXdsCluster(t *testing.T) {
 	require.Equal(t, bootstrapXdsCluster.Name, dynamicXdsCluster.Name)
 	require.Equal(t, bootstrapXdsCluster.ClusterDiscoveryType, dynamicXdsCluster.ClusterDiscoveryType)
 	require.Equal(t, bootstrapXdsCluster.TransportSocket, dynamicXdsCluster.TransportSocket)
-	assert.True(t, proto.Equal(bootstrapXdsCluster.TransportSocket, dynamicXdsCluster.TransportSocket))
-	assert.True(t, proto.Equal(bootstrapXdsCluster.ConnectTimeout, dynamicXdsCluster.ConnectTimeout))
+	requireCmpNoDiff(t, bootstrapXdsCluster.TransportSocket, dynamicXdsCluster.TransportSocket)
+	requireCmpNoDiff(t, bootstrapXdsCluster.ConnectTimeout, dynamicXdsCluster.ConnectTimeout)
 }
 
 func TestBuildXdsClusterLoadAssignment(t *testing.T) {
 	bootstrapXdsCluster := getXdsClusterObjFromBootstrap(t)
+	require.NotNil(t, bootstrapXdsCluster)
 	ds := &ir.DestinationSetting{
 		Endpoints: []*ir.DestinationEndpoint{{Host: envoyGatewayXdsServerHost, Port: bootstrap.DefaultXdsServerPort}},
 	}
 	settings := []*ir.DestinationSetting{ds}
 	dynamicXdsClusterLoadAssignment := buildXdsClusterLoadAssignment(bootstrapXdsCluster.Name, settings, nil)
 
-	assert.True(t, proto.Equal(bootstrapXdsCluster.LoadAssignment.Endpoints[0].LbEndpoints[0], dynamicXdsClusterLoadAssignment.Endpoints[0].LbEndpoints[0]))
+	requireCmpNoDiff(t, bootstrapXdsCluster.LoadAssignment.Endpoints[0].LbEndpoints[0], dynamicXdsClusterLoadAssignment.Endpoints[0].LbEndpoints[0])
 }
 
 func getXdsClusterObjFromBootstrap(t *testing.T) *clusterv3.Cluster {
@@ -132,15 +134,16 @@ func TestBuildXdsOutlierDetection(t *testing.T) {
 				FailurePercentageThreshold:     ptr.To[uint32](85),
 			},
 			expected: &clusterv3.OutlierDetection{
-				SplitExternalLocalOriginErrors: true,
-				Interval:                       durationpb.New(10 * time.Second),
-				ConsecutiveLocalOriginFailure:  wrapperspb.UInt32(3),
-				ConsecutiveGatewayFailure:      wrapperspb.UInt32(2),
-				Consecutive_5Xx:                wrapperspb.UInt32(5),
-				BaseEjectionTime:               durationpb.New(30 * time.Second),
-				MaxEjectionPercent:             wrapperspb.UInt32(10),
-				FailurePercentageThreshold:     wrapperspb.UInt32(85),
-				EnforcingFailurePercentage:     wrapperspb.UInt32(100),
+				SplitExternalLocalOriginErrors:     true,
+				Interval:                           durationpb.New(10 * time.Second),
+				ConsecutiveLocalOriginFailure:      wrapperspb.UInt32(3),
+				EnforcingConsecutiveGatewayFailure: wrapperspb.UInt32(100),
+				ConsecutiveGatewayFailure:          wrapperspb.UInt32(2),
+				Consecutive_5Xx:                    wrapperspb.UInt32(5),
+				BaseEjectionTime:                   durationpb.New(30 * time.Second),
+				MaxEjectionPercent:                 wrapperspb.UInt32(10),
+				FailurePercentageThreshold:         wrapperspb.UInt32(85),
+				EnforcingFailurePercentage:         wrapperspb.UInt32(100),
 			},
 		},
 	}
@@ -148,7 +151,11 @@ func TestBuildXdsOutlierDetection(t *testing.T) {
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			result := buildXdsOutlierDetection(tc.input)
-			assert.True(t, proto.Equal(tc.expected, result), "Expected and actual outlier detection configurations are not equal")
+			requireCmpNoDiff(t, tc.expected, result)
 		})
 	}
 }
+
+func requireCmpNoDiff(t *testing.T, expected, actual interface{}) {
+	require.Empty(t, cmp.Diff(expected, actual, protocmp.Transform()))
+}
diff --git a/internal/xds/translator/testdata/in/xds-ir/accesslog-invalid.yaml b/internal/xds/translator/testdata/in/xds-ir/accesslog-invalid.yaml
index 7749fe3c4..28ec81179 100644
--- a/internal/xds/translator/testdata/in/xds-ir/accesslog-invalid.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/accesslog-invalid.yaml
@@ -44,5 +44,5 @@ http:
           port: 50000
         name: "direct-route-dest/backend/0"
     directResponse:
-      body: "Unknown custom filter type: UnsupportedType"
+      body: VW5rbm93biBjdXN0b20gZmlsdGVyIHR5cGU6IFVuc3VwcG9ydGVkVHlwZQ==
       statusCode: 500
diff --git a/internal/xds/translator/testdata/in/xds-ir/custom-response.yaml b/internal/xds/translator/testdata/in/xds-ir/custom-response.yaml
index b13fbd3e0..a24f5605f 100644
--- a/internal/xds/translator/testdata/in/xds-ir/custom-response.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/custom-response.yaml
@@ -49,7 +49,7 @@ http:
                       name: X-Set-Header
                       value:
                         - set-404
-                  body: gateway-1 Not Found
+                  body: Z2F0ZXdheS0xIE5vdCBGb3VuZA==
                   contentType: text/plain
               - match:
                   statusCodes:
@@ -59,10 +59,7 @@ http:
                         start: 501
                 name: backendtrafficpolicy/default/policy-for-gateway/responseoverride/rule/1
                 response:
-                  body: |
-                    {
-                      "error": "Internal Server Error"
-                    }
+                  body: ewogICJlcnJvciI6ICJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3IiCn0K
                   contentType: application/json
               - match:
                   statusCodes:
diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-direct-response.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-direct-response.yaml
index 56b2f02fb..bd14eafd7 100644
--- a/internal/xds/translator/testdata/in/xds-ir/http-route-direct-response.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/http-route-direct-response.yaml
@@ -32,5 +32,5 @@ http:
           port: 50000
         name: "direct-route-dest/backend/0"
     directResponse:
-      body: "Unknown custom filter type: UnsupportedType"
+      body: VW5rbm93biBjdXN0b20gZmlsdGVyIHR5cGU6IFVuc3VwcG9ydGVkVHlwZQ==
       statusCode: 500
diff --git a/internal/xds/translator/testdata/in/xds-ir/tracing-invalid.yaml b/internal/xds/translator/testdata/in/xds-ir/tracing-invalid.yaml
index 00329fd9c..1b1e5e603 100644
--- a/internal/xds/translator/testdata/in/xds-ir/tracing-invalid.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/tracing-invalid.yaml
@@ -40,5 +40,5 @@ http:
                   port: 50000
               name: "direct-route-dest/backend/0"
         directResponse:
-          body: "Unknown custom filter type: UnsupportedType"
+          body: VW5rbm93biBjdXN0b20gZmlsdGVyIHR5cGU6IFVuc3VwcG9ydGVkVHlwZQ==
           statusCode: 500
diff --git a/internal/xds/translator/testdata/in/xds-ir/tracing-unknown-provider-type.yaml b/internal/xds/translator/testdata/in/xds-ir/tracing-unknown-provider-type.yaml
index 5d8e2e81d..13c5df586 100644
--- a/internal/xds/translator/testdata/in/xds-ir/tracing-unknown-provider-type.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/tracing-unknown-provider-type.yaml
@@ -49,5 +49,5 @@ http:
                   port: 50000
               name: "direct-route-dest/backend/0"
         directResponse:
-          body: "Unknown custom filter type: UnsupportedType"
+          body: VW5rbm93biBjdXN0b20gZmlsdGVyIHR5cGU6IFVuc3VwcG9ydGVkVHlwZQ==
           statusCode: 500
diff --git a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml
index dfc236fe0..ccbf5dc34 100755
--- a/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/accesslog-als-tcp.clusters.yaml
@@ -26,6 +26,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 4
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 5s
     maxEjectionPercent: 10
   perConnectionBufferLimitBytes: 20971520
diff --git a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.clusters.yaml
index e008f4717..c0ae4804d 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ext-proc-with-traffic-settings.clusters.yaml
@@ -75,6 +75,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 4
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 5s
     maxEjectionPercent: 10
   perConnectionBufferLimitBytes: 20971520
diff --git a/internal/xds/translator/testdata/out/xds-ir/health-check.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/health-check.clusters.yaml
index 3c797c2ff..3ccb320b4 100644
--- a/internal/xds/translator/testdata/out/xds-ir/health-check.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/health-check.clusters.yaml
@@ -40,6 +40,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 0
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 2s
     maxEjectionPercent: 100
   perConnectionBufferLimitBytes: 32768
@@ -84,6 +85,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 0
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 1s
     maxEjectionPercent: 100
   perConnectionBufferLimitBytes: 32768
@@ -125,6 +127,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 0
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 1s
     maxEjectionPercent: 100
   perConnectionBufferLimitBytes: 32768
@@ -166,6 +169,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 0
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 1s
     maxEjectionPercent: 90
     splitExternalLocalOriginErrors: true
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-direct-response.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-direct-response.routes.yaml
index f97abbfa3..718e8bdc7 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http-route-direct-response.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http-route-direct-response.routes.yaml
@@ -7,7 +7,7 @@
     routes:
     - directResponse:
         body:
-          inlineString: 'Unknown custom filter type: UnsupportedType'
+          inlineBytes: VW5rbm93biBjdXN0b20gZmlsdGVyIHR5cGU6IFVuc3VwcG9ydGVkVHlwZQ==
         status: 500
       match:
         prefix: /
diff --git a/internal/xds/translator/testdata/out/xds-ir/passive-failure-percentage.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/passive-failure-percentage.clusters.yaml
index 0387fef6e..9290f1ef5 100644
--- a/internal/xds/translator/testdata/out/xds-ir/passive-failure-percentage.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/passive-failure-percentage.clusters.yaml
@@ -25,6 +25,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 0
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     enforcingFailurePercentage: 100
     failurePercentageThreshold: 90
     interval: 5s
diff --git a/internal/xds/translator/testdata/out/xds-ir/tracing.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/tracing.clusters.yaml
index 523ecad2b..28d736bc1 100644
--- a/internal/xds/translator/testdata/out/xds-ir/tracing.clusters.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/tracing.clusters.yaml
@@ -59,6 +59,7 @@
     consecutive5xx: 5
     consecutiveGatewayFailure: 4
     consecutiveLocalOriginFailure: 5
+    enforcingConsecutiveGatewayFailure: 100
     interval: 5s
     maxEjectionPercent: 10
   perConnectionBufferLimitBytes: 20971520
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 62fb487b3..fc870f979 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -3567,7 +3567,7 @@ _Appears in:_
 | `splitExternalLocalOriginErrors` | _boolean_ |  false  | false | SplitExternalLocalOriginErrors enables splitting of errors between external and local origin. |
 | `interval` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#duration)_ |  false  | 3s | Interval defines the time between passive health checks. |
 | `consecutiveLocalOriginFailures` | _integer_ |  false  | 5 | ConsecutiveLocalOriginFailures sets the number of consecutive local origin failures triggering ejection.<br />Parameter takes effect only when split_external_local_origin_errors is set to true. |
-| `consecutiveGatewayErrors` | _integer_ |  false  | 0 | ConsecutiveGatewayErrors sets the number of consecutive gateway errors triggering ejection. |
+| `consecutiveGatewayErrors` | _integer_ |  false  |  | ConsecutiveGatewayErrors sets the number of consecutive gateway errors triggering ejection. |
 | `consecutive5XxErrors` | _integer_ |  false  | 5 | Consecutive5xxErrors sets the number of consecutive 5xx errors triggering ejection. |
 | `baseEjectionTime` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#duration)_ |  false  | 30s | BaseEjectionTime defines the base duration for which a host will be ejected on consecutive failures. |
 | `maxEjectionPercent` | _integer_ |  false  | 10 | MaxEjectionPercent sets the maximum percentage of hosts in a cluster that can be ejected. |
diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml
index 111bb67f1..4fc7a9a93 100644
--- a/test/helm/gateway-crds-helm/all.out.yaml
+++ b/test/helm/gateway-crds-helm/all.out.yaml
@@ -21527,7 +21527,6 @@ spec:
                         format: int32
                         type: integer
                       consecutiveGatewayErrors:
-                        default: 0
                         description: ConsecutiveGatewayErrors sets the number of consecutive
                           gateway errors triggering ejection.
                         format: int32
@@ -25890,7 +25889,6 @@ spec:
                                   format: int32
                                   type: integer
                                 consecutiveGatewayErrors:
-                                  default: 0
                                   description: ConsecutiveGatewayErrors sets the number
                                     of consecutive gateway errors triggering ejection.
                                   format: int32
@@ -39416,7 +39414,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -40547,7 +40544,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -41774,7 +41770,6 @@ spec:
                                               format: int32
                                               type: integer
                                             consecutiveGatewayErrors:
-                                              default: 0
                                               description: ConsecutiveGatewayErrors
                                                 sets the number of consecutive gateway
                                                 errors triggering ejection.
@@ -42908,7 +42903,6 @@ spec:
                                         format: int32
                                         type: integer
                                       consecutiveGatewayErrors:
-                                        default: 0
                                         description: ConsecutiveGatewayErrors sets
                                           the number of consecutive gateway errors
                                           triggering ejection.
@@ -45017,7 +45011,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -46042,7 +46035,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -47278,7 +47270,6 @@ spec:
                                           format: int32
                                           type: integer
                                         consecutiveGatewayErrors:
-                                          default: 0
                                           description: ConsecutiveGatewayErrors sets
                                             the number of consecutive gateway errors
                                             triggering ejection.
@@ -48571,7 +48562,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
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 6c3d83e33..894b3589c 100644
--- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
+++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
@@ -871,7 +871,6 @@ spec:
                         format: int32
                         type: integer
                       consecutiveGatewayErrors:
-                        default: 0
                         description: ConsecutiveGatewayErrors sets the number of consecutive
                           gateway errors triggering ejection.
                         format: int32
@@ -5234,7 +5233,6 @@ spec:
                                   format: int32
                                   type: integer
                                 consecutiveGatewayErrors:
-                                  default: 0
                                   description: ConsecutiveGatewayErrors sets the number
                                     of consecutive gateway errors triggering ejection.
                                   format: int32
@@ -18760,7 +18758,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -19891,7 +19888,6 @@ spec:
                                                     format: int32
                                                     type: integer
                                                   consecutiveGatewayErrors:
-                                                    default: 0
                                                     description: ConsecutiveGatewayErrors
                                                       sets the number of consecutive
                                                       gateway errors triggering ejection.
@@ -21118,7 +21114,6 @@ spec:
                                               format: int32
                                               type: integer
                                             consecutiveGatewayErrors:
-                                              default: 0
                                               description: ConsecutiveGatewayErrors
                                                 sets the number of consecutive gateway
                                                 errors triggering ejection.
@@ -22252,7 +22247,6 @@ spec:
                                         format: int32
                                         type: integer
                                       consecutiveGatewayErrors:
-                                        default: 0
                                         description: ConsecutiveGatewayErrors sets
                                           the number of consecutive gateway errors
                                           triggering ejection.
@@ -24361,7 +24355,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -25386,7 +25379,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.
@@ -26622,7 +26614,6 @@ spec:
                                           format: int32
                                           type: integer
                                         consecutiveGatewayErrors:
-                                          default: 0
                                           description: ConsecutiveGatewayErrors sets
                                             the number of consecutive gateway errors
                                             triggering ejection.
@@ -27915,7 +27906,6 @@ spec:
                                     format: int32
                                     type: integer
                                   consecutiveGatewayErrors:
-                                    default: 0
                                     description: ConsecutiveGatewayErrors sets the
                                       number of consecutive gateway errors triggering
                                       ejection.