Repository: envoyproxy/gateway

Issue:
CI Benchmark Test Failure
*Description*:
>What issue is being seen? Describe what should be happening instead of
the bug, for example: The expected value isn't returned, etc.

benchmark test is failing on main branch 

https://github.com/envoyproxy/gateway/actions/runs/13780732274/job/38538406932

*Repro steps*:
> Include sample requests, environment, etc. All data and inputs
required to reproduce the bug.

>**Note**: If there are privacy concerns, sanitize the data prior to
sharing.

*Environment*:
>Include the environment like gateway version, envoy version and so on.

*Logs*:
>Include the access logs and the Envoy logs.


Hints from issue comments:
@Chever-John: Hello! I'm looking to solve this issue and would appreciate your help. 

Could you please advise me on the essential development environment requirements and prerequisites that I need to set up to address this problem effectively?@Chever-John: Update: I've discovered that on macOS (Apple Silicon), I cannot run `make benchmark` because the `envoyproxy/nighthawk-dev:latest` image doesn't support the darwin/arm64 architecture.

I'm considering finding a server to run this later. Are there any resources or alternative solutions that might help with this issue?

@Xunzhuo Tks before~@zhaohuabing: This is caused by https://github.com/envoyproxy/nighthawk/issues/1312
Introduced in https://github.com/envoyproxy/nighthawk/pull/1309@zirain: this's fixed now.

Solution patch:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index d30fb84fe..624a822db 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -36,14 +36,14 @@ jobs:
     - uses: ./tools/github-actions/setup-deps
 
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d  # v3.28.10
+      uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5  # v3.28.11
       with:
         languages: ${{ matrix.language }}
 
     - name: Autobuild
-      uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d  # v3.28.10
+      uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5  # v3.28.11
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d  # v3.28.10
+      uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5  # v3.28.11
       with:
         category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index 0ac023033..0d97a6fc8 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -40,6 +40,6 @@ jobs:
         retention-days: 5
 
     - name: "Upload to code-scanning"
-      uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d  # v3.28.10
+      uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5  # v3.28.11
       with:
         sarif_file: results.sarif
diff --git a/api/v1alpha1/authorization_types.go b/api/v1alpha1/authorization_types.go
index 26a4fb8fe..41b1c3890 100644
--- a/api/v1alpha1/authorization_types.go
+++ b/api/v1alpha1/authorization_types.go
@@ -56,7 +56,6 @@ type AuthorizationRule struct {
 }
 
 // Operation specifies the operation of a request.
-// +notImplementedHide
 type Operation struct {
 	// Methods are the HTTP methods of the request.
 	// If multiple methods are specified, all specified methods are allowed or denied, based on the action of the rule.
@@ -102,7 +101,6 @@ type Principal struct {
 	// +optional
 	// +kubebuilder:validation:MinItems=1
 	// +kubebuilder:validation:MaxItems=256
-	// +notImplementedHide
 	Headers []AuthorizationHeaderMatch `json:"headers,omitempty"`
 }
 
diff --git a/api/v1alpha1/envoygateway_types.go b/api/v1alpha1/envoygateway_types.go
index 33893c856..ead575969 100644
--- a/api/v1alpha1/envoygateway_types.go
+++ b/api/v1alpha1/envoygateway_types.go
@@ -560,13 +560,12 @@ type ExtensionService struct {
 	TLS *ExtensionTLS `json:"tls,omitempty"`
 }
 
-// ExtensionTLS defines the TLS configuration when connecting to an extension service
+// ExtensionTLS defines the TLS configuration when connecting to an extension service.
 type ExtensionTLS struct {
-	// CertificateRef contains a references to objects (Kubernetes objects or otherwise) that
-	// contains a TLS certificate and private keys. These certificates are used to
-	// establish a TLS handshake to the extension server.
+	// CertificateRef is a reference to a Kubernetes Secret with a CA certificate in a key named "tls.crt".
 	//
-	// CertificateRef can only reference a Kubernetes Secret at this time.
+	// The CA certificate is used by Envoy Gateway the verify the server certificate presented by the extension server.
+	// At this time, Envoy Gateway does not support Client Certificate authentication of Envoy Gateway towards the extension server (mTLS).
 	//
 	// +kubebuilder:validation:Required
 	CertificateRef gwapiv1.SecretObjectReference `json:"certificateRef"`
diff --git a/go.mod b/go.mod
index 71299e14c..a46401598 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.24.0
 require (
 	fortio.org/fortio v1.68.0
 	fortio.org/log v1.17.1
+	github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24
 	github.com/Masterminds/semver/v3 v3.3.1
 	github.com/andybalholm/brotli v1.1.1
 	github.com/avast/retry-go v3.0.0+incompatible
@@ -107,7 +108,6 @@ require (
 	fortio.org/version v1.0.4 // indirect
 	github.com/4meepo/tagalign v1.4.1 // indirect
 	github.com/Abirdcfly/dupword v0.1.3 // indirect
-	github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
 	github.com/Antonboom/errname v1.0.0 // indirect
 	github.com/Antonboom/nilnil v1.0.1 // indirect
 	github.com/Antonboom/testifylint v1.5.2 // indirect
diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go
index 08a592ed0..1500c1ac1 100644
--- a/internal/cmd/egctl/translate.go
+++ b/internal/cmd/egctl/translate.go
@@ -246,7 +246,7 @@ func translate(w io.Writer, inFile, inType string, outTypes []string, output, re
 				result.Xds = res
 			}
 			if outType == irType {
-				res, err := translateGatewayAPIToIR(resources)
+				res, err := TranslateGatewayAPIToIR(resources)
 				if err != nil {
 					return err
 				}
@@ -265,7 +265,7 @@ func translate(w io.Writer, inFile, inType string, outTypes []string, output, re
 	return fmt.Errorf("unable to find translate from input type %s to output type %s", inType, outTypes)
 }
 
-func translateGatewayAPIToIR(resources *resource.Resources) (*gatewayapi.TranslateResult, error) {
+func TranslateGatewayAPIToIR(resources *resource.Resources) (*gatewayapi.TranslateResult, error) {
 	if resources.GatewayClass == nil {
 		return nil, fmt.Errorf("the GatewayClass resource is required")
 	}
diff --git a/internal/gatewayapi/resource/load.go b/internal/gatewayapi/resource/load.go
index b3d1a523a..23f64c96a 100644
--- a/internal/gatewayapi/resource/load.go
+++ b/internal/gatewayapi/resource/load.go
@@ -46,9 +46,7 @@ func LoadResourcesFromYAMLBytes(yamlBytes []byte, addMissingResources bool) (*Re
 
 // loadKubernetesYAMLToResources converts a Kubernetes YAML string into GatewayAPI Resources.
 // TODO: add support for kind:
-//   - EnvoyExtensionPolicy (gateway.envoyproxy.io/v1alpha1)
 //   - BackendLPPolicy (gateway.networking.k8s.io/v1alpha2)
-//   - BackendTLSPolicy (gateway.networking.k8s.io/v1alpha3)
 //   - ReferenceGrant (gateway.networking.k8s.io/v1alpha2)
 func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Resources, error) {
 	resources := NewResources()
@@ -355,6 +353,19 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 				Spec: typedSpec.(gwapiv1a3.BackendTLSPolicySpec),
 			}
 			resources.BackendTLSPolicies = append(resources.BackendTLSPolicies, backendTLSPolicy)
+		case KindEnvoyExtensionPolicy:
+			typedSpec := spec.Interface()
+			envoyExtensionPolicy := &egv1a1.EnvoyExtensionPolicy{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindEnvoyExtensionPolicy,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(egv1a1.EnvoyExtensionPolicySpec),
+			}
+			resources.EnvoyExtensionPolicies = append(resources.EnvoyExtensionPolicies, envoyExtensionPolicy)
 		}
 
 		return nil
diff --git a/internal/gatewayapi/runner/runner.go b/internal/gatewayapi/runner/runner.go
index 9c2bf9c5d..f182f10ed 100644
--- a/internal/gatewayapi/runner/runner.go
+++ b/internal/gatewayapi/runner/runner.go
@@ -11,7 +11,9 @@ import (
 	"encoding/json"
 	"fmt"
 	"os"
+	"path"
 	"reflect"
+	"runtime"
 
 	"github.com/docker/docker/pkg/fileutils"
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
@@ -36,8 +38,6 @@ import (
 )
 
 const (
-	wasmCacheDir = "/var/lib/eg/wasm"
-
 	// Default certificates path for envoy-gateway with Kubernetes provider.
 	serveTLSCertFilepath = "/certs/tls.crt"
 	serveTLSKeyFilepath  = "/certs/tls.key"
@@ -96,9 +96,17 @@ func (r *Runner) startWasmCache(ctx context.Context) {
 		r.Logger.Error(err, "failed to start wasm cache")
 		return
 	}
-
+	cacheOption := wasm.CacheOptions{}
+	switch runtime.GOOS {
+	case "darwin":
+		// On darwin, /var/lib/eg/wasm is not writable by non-root users.
+		h, _ := os.UserHomeDir() // Assume we always get the home directory.
+		cacheOption.CacheDir = path.Join(h, ".eg", "wasm")
+	default:
+		cacheOption.CacheDir = "/var/lib/eg/wasm"
+	}
 	// Create the file directory if it does not exist.
-	if err = fileutils.CreateIfNotExists(wasmCacheDir, true); err != nil {
+	if err = fileutils.CreateIfNotExists(cacheOption.CacheDir, true); err != nil {
 		r.Logger.Error(err, "Failed to create Wasm cache directory")
 		return
 	}
@@ -108,10 +116,7 @@ func (r *Runner) startWasmCache(ctx context.Context) {
 			Salt:      salt,
 			TLSConfig: tlsConfig,
 		},
-		// Wasm cache options
-		wasm.CacheOptions{
-			CacheDir: wasmCacheDir,
-		}, r.Logger)
+		cacheOption, r.Logger)
 	r.wasmCache.Start(ctx)
 }
 
diff --git a/internal/provider/file/file.go b/internal/provider/file/file.go
index 22452772f..c7b28ccec 100644
--- a/internal/provider/file/file.go
+++ b/internal/provider/file/file.go
@@ -7,6 +7,7 @@ package file
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"net/http"
 	"os"
@@ -201,7 +202,7 @@ func (p *Provider) startHealthProbeServer(ctx context.Context, readyzChecker hea
 	}()
 
 	p.logger.Info("starting health probe server", "address", srv.Addr)
-	if err := srv.ListenAndServe(); err != nil {
+	if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
 		p.logger.Error(err, "failed to start health probe server")
 	}
 }
diff --git a/internal/wasm/httpserver.go b/internal/wasm/httpserver.go
index 14e70a8c6..8f25a32c5 100644
--- a/internal/wasm/httpserver.go
+++ b/internal/wasm/httpserver.go
@@ -10,6 +10,7 @@ import (
 	"crypto/sha256"
 	"crypto/tls"
 	"encoding/base64"
+	"errors"
 	"fmt"
 	"net/http"
 	"strings"
@@ -126,7 +127,7 @@ func (s *HTTPServer) Start(ctx context.Context) {
 		} else {
 			err = s.server.ListenAndServe()
 		}
-		if err != nil {
+		if err != nil && !errors.Is(err, http.ErrServerClosed) {
 			s.logger.Error(err, "Failed to start Wasm HTTP server")
 			return
 		}
diff --git a/internal/xds/translator/translator.go b/internal/xds/translator/translator.go
index f9cd6d90b..5672cc6e7 100644
--- a/internal/xds/translator/translator.go
+++ b/internal/xds/translator/translator.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"runtime"
 	"strings"
 	"time"
 
@@ -1031,6 +1032,31 @@ const (
 	EDS
 )
 
+// defaultCertificateName is the default location of the system trust store, initialized at runtime once.
+//
+// This assumes the Envoy running in a very specific environment. For example, the default location of the system
+// trust store on Debian derivatives like the envoy-proxy image being used by the infrastructure controller.
+//
+// TODO: this might be configurable by an env var or EnvoyGateway configuration.
+var defaultCertificateName = func() string {
+	switch runtime.GOOS {
+	case "darwin":
+		// TODO: maybe automatically get the keychain cert? That might be macOS version dependent.
+		// For now, we'll just use the root cert installed by Homebrew: brew install ca-certificates.
+		//
+		// See:
+		// * https://apple.stackexchange.com/questions/226375/where-are-the-root-cas-stored-on-os-x
+		// * https://superuser.com/questions/992167/where-are-digital-certificates-physically-stored-on-a-mac-os-x-machine
+		return "/opt/homebrew/etc/ca-certificates/cert.pem"
+	default:
+		// This is the default location for the system trust store
+		// on Debian derivatives like the envoy-proxy image being used by the infrastructure
+		// controller.
+		// See https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ssl
+		return "/etc/ssl/certs/ca-certificates.crt"
+	}
+}()
+
 func buildXdsUpstreamTLSCASecret(tlsConfig *ir.TLSUpstreamConfig) *tlsv3.Secret {
 	// Build the tls secret
 	if tlsConfig.UseSystemTrustStore {
@@ -1039,15 +1065,7 @@ func buildXdsUpstreamTLSCASecret(tlsConfig *ir.TLSUpstreamConfig) *tlsv3.Secret
 			Type: &tlsv3.Secret_ValidationContext{
 				ValidationContext: &tlsv3.CertificateValidationContext{
 					TrustedCa: &corev3.DataSource{
-						Specifier: &corev3.DataSource_Filename{
-							// This is the default location for the system trust store
-							// on Debian derivatives like the envoy-proxy image being used by the infrastructure
-							// controller.
-							// See https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ssl
-							// TODO: allow customizing this value via EnvoyGateway so that if a non-standard
-							// envoy image is being used, this can be modified to match
-							Filename: "/etc/ssl/certs/ca-certificates.crt",
-						},
+						Specifier: &corev3.DataSource_Filename{Filename: defaultCertificateName},
 					},
 				},
 			},
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index b404cfffc..5a42fb7da 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -29,7 +29,7 @@ bug fixes: |
   Bypass overload manager for stats and ready listeners
   Fix translating backendSettings for extAuth
   Fix an issue that stats compressor was not working.
-  Added support for BackendTLSPolicy parsing in Standalone mode.
+  Added support for BackendTLSPolicy and EnvoyExtensionPolicy parsing in Standalone mode.
 
 # Enhancements that improve performance.
 performance improvements: |
diff --git a/site/content/en/contributions/design/backend-traffic-policy.md b/site/content/en/contributions/design/backend-traffic-policy.md
index 9411ef209..67ceebf16 100644
--- a/site/content/en/contributions/design/backend-traffic-policy.md
+++ b/site/content/en/contributions/design/backend-traffic-policy.md
@@ -104,7 +104,6 @@ spec:
     group: gateway.networking.k8s.io
     kind: Gateway
     name: eg
-    namespace: default
 ---
 apiVersion: gateway.envoyproxy.io/v1alpha1
 kind: BackendTrafficPolicy
@@ -118,7 +117,6 @@ spec:
     group: gateway.networking.k8s.io
     kind: HTTPRoute
     name: ipv6-route
-    namespace: default
 ```
 
 ## Features / API Fields
diff --git a/site/data/adopters.yaml b/site/data/adopters.yaml
index ae8bd50dc..e47a7cdb8 100644
--- a/site/data/adopters.yaml
+++ b/site/data/adopters.yaml
@@ -47,3 +47,7 @@ adopters:
     logo: "/logos/kubermatic.svg"
     url: "https://www.kubermatic.com/"
     description: "Kubermatic is using Envoy Gateway in KubeLB to provide L7 Load Balancing for multiple Kubernetes clusters using GatewayAPI."
+  - name: "Docker"
+    logo: "/logos/docker.png"
+    url: "https://www.docker.com/"
+    description: "Docker is using Envoy Gateway to route all internal traffic for Docker Hub."
diff --git a/site/static/logos/docker.png b/site/static/logos/docker.png
new file mode 100644
index 000000000..52d305a2c
Binary files /dev/null and b/site/static/logos/docker.png differ
diff --git a/tools/make/env.mk b/tools/make/env.mk
index 4f60768eb..1e3d53325 100644
--- a/tools/make/env.mk
+++ b/tools/make/env.mk
@@ -15,3 +15,8 @@ IMAGE_NAME ?= gateway-dev
 IMAGE ?= ${REGISTRY}/${IMAGE_NAME}
 # Tag is the tag to use for build and push image targets.
 TAG ?= $(REV)
+
+# Fuzzing variables
+
+# FUZZ_TIME is the time to run the fuzzer for
+FUZZ_TIME ?= 5s
\ No newline at end of file
diff --git a/tools/make/golang.mk b/tools/make/golang.mk
index 9d7d568ff..62d096b15 100644
--- a/tools/make/golang.mk
+++ b/tools/make/golang.mk
@@ -39,6 +39,15 @@ go.build: $(addprefix go.build., $(addprefix $(PLATFORM)., $(BINS)))
 .PHONY: go.build.multiarch
 go.build.multiarch: $(foreach p,$(PLATFORMS),$(addprefix go.build., $(addprefix $(p)., $(BINS))))
 
+.PHONY: go.test.fuzz
+go.test.fuzz: ## Run all fuzzers in the test/fuzz folder one by one
+	@$(LOG_TARGET)
+	@for dir in $$(go list -f '{{.Dir}}' ./test/fuzz/...); do \
+		for test in $$(go test -list=Fuzz.* $$dir | grep ^Fuzz); do \
+			echo "go test -fuzz=$$test -fuzztime=$(FUZZ_TIME)"; \
+			(cd $$dir && go test -fuzz=$$test -fuzztime=$(FUZZ_TIME)) || exit 1; \
+		done; \
+	done
 
 .PHONY: go.test.unit
 go.test.unit: ## Run go unit tests



Test patch:
diff --git a/internal/cmd/egctl/testdata/translate/in/backend-endpoint.yaml b/internal/cmd/egctl/testdata/translate/in/backend-endpoint.yaml
index 0f1f3ab69..f845c0941 100644
--- a/internal/cmd/egctl/testdata/translate/in/backend-endpoint.yaml
+++ b/internal/cmd/egctl/testdata/translate/in/backend-endpoint.yaml
@@ -57,3 +57,21 @@ spec:
   validation:
     wellKnownCACertificates: "System"
     hostname: www.example.com
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: EnvoyExtensionPolicy
+metadata:
+  name: ext-proc-example
+spec:
+  targetRefs:
+    - group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: backend
+  extProc:
+    - backendRefs:
+        - name: grpc-ext-proc
+          port: 9002
+      processingMode:
+        request: {}
+        response:
+          body: Streamed
diff --git a/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml b/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml
index 41a84b3d8..1085a7aa2 100644
--- a/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml
@@ -43,6 +43,43 @@ backends:
       reason: Accepted
       status: "True"
       type: Accepted
+envoyExtensionPolicies:
+- kind: EnvoyExtensionPolicy
+  metadata:
+    creationTimestamp: null
+    name: ext-proc-example
+    namespace: envoy-gateway-system
+  spec:
+    extProc:
+    - backendRefs:
+      - group: ""
+        kind: Service
+        name: grpc-ext-proc
+        port: 9002
+      processingMode:
+        request: {}
+        response:
+          body: Streamed
+    targetRefs:
+    - group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: backend
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: eg
+        namespace: envoy-gateway-system
+      conditions:
+      - lastTransitionTime: null
+        message: |-
+          Wasm: wasm cache is not initialized
+          ExtProc: service envoy-gateway-system/grpc-ext-proc not found.
+        reason: Invalid
+        status: "False"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
 gatewayClass:
   kind: GatewayClass
   metadata:
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 3483a8e01..e5889126e 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -1721,14 +1721,14 @@ _Appears in:_
 
 
 
-ExtensionTLS defines the TLS configuration when connecting to an extension service
+ExtensionTLS defines the TLS configuration when connecting to an extension service.
 
 _Appears in:_
 - [ExtensionService](#extensionservice)
 
 | Field | Type | Required | Default | Description |
 | ---   | ---  | ---      | ---     | ---         |
-| `certificateRef` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.SecretObjectReference)_ |  true  |  | CertificateRef contains a references to objects (Kubernetes objects or otherwise) that<br />contains a TLS certificate and private keys. These certificates are used to<br />establish a TLS handshake to the extension server.<br />CertificateRef can only reference a Kubernetes Secret at this time. |
+| `certificateRef` | _[SecretObjectReference](https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.SecretObjectReference)_ |  true  |  | CertificateRef is a reference to a Kubernetes Secret with a CA certificate in a key named "tls.crt".<br />The CA certificate is used by Envoy Gateway the verify the server certificate presented by the extension server.<br />At this time, Envoy Gateway does not support Client Certificate authentication of Envoy Gateway towards the extension server (mTLS). |
 
 
 #### ExtractFrom
@@ -3190,6 +3190,7 @@ _Appears in:_
 | ---   | ---  | ---      | ---     | ---         |
 | `clientCIDRs` | _[CIDR](#cidr) array_ |  false  |  | ClientCIDRs are the IP CIDR ranges of the client.<br />Valid examples are "192.168.1.0/24" or "2001:db8::/64"<br />If multiple CIDR ranges are specified, one of the CIDR ranges must match<br />the client IP for the rule to match.<br />The client IP is inferred from the X-Forwarded-For header, a custom header,<br />or the proxy protocol.<br />You can use the `ClientIPDetection` or the `EnableProxyProtocol` field in<br />the `ClientTrafficPolicy` to configure how the client IP is detected. |
 | `jwt` | _[JWTPrincipal](#jwtprincipal)_ |  false  |  | JWT authorize the request based on the JWT claims and scopes.<br />Note: in order to use JWT claims for authorization, you must configure the<br />JWT authentication in the same `SecurityPolicy`. |
+| `headers` | _[AuthorizationHeaderMatch](#authorizationheadermatch) array_ |  false  |  | Headers authorize the request based on user identity extracted from custom headers.<br />If multiple headers are specified, all headers must match for the rule to match. |
 
 
 #### ProcessingModeOptions
diff --git a/test/fuzz/ir_fuzz_test.go b/test/fuzz/ir_fuzz_test.go
new file mode 100644
index 000000000..3107dd02f
--- /dev/null
+++ b/test/fuzz/ir_fuzz_test.go
@@ -0,0 +1,42 @@
+// Copyright Envoy Gateway Authors
+// SPDX-License-Identifier: Apache-2.0
+// The full text of the Apache license is available in the LICENSE file at
+// the root of the repo.
+
+package fuzz
+
+import (
+	"testing"
+
+	fuzz "github.com/AdaLogics/go-fuzz-headers"
+	"sigs.k8s.io/yaml"
+
+	"github.com/envoyproxy/gateway/internal/cmd/egctl"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
+)
+
+func FuzzGatewayAPIToIR(f *testing.F) {
+	f.Fuzz(func(t *testing.T, data []byte) {
+		fc := fuzz.NewConsumer(data)
+		resources := &resource.Resources{}
+		if err := fc.GenerateStruct(resources); err != nil {
+			return
+		}
+		addMissingResources, err := fc.GetBool()
+		if err != nil {
+			return
+		}
+
+		// Populate default values
+		yamlBytes, err := yaml.Marshal(resources)
+		if err != nil {
+			return
+		}
+		rs, err := resource.LoadResourcesFromYAMLBytes(yamlBytes, addMissingResources)
+		if err != nil {
+			return
+		}
+
+		_, _ = egctl.TranslateGatewayAPIToIR(rs)
+	})
+}