Repository: envoyproxy/gateway
Pull request #5741 (2025-04-16 01:55:09)

feat(helm): Add management of extensionApis
**What this PR does / why we need it**:
Adds the ability to enable extension APIs with the helm chart




Patch:
diff --git a/api/v1alpha1/backendtrafficpolicy_types.go b/api/v1alpha1/backendtrafficpolicy_types.go
index b30b16a4c..5fd1ae7b1 100644
--- a/api/v1alpha1/backendtrafficpolicy_types.go
+++ b/api/v1alpha1/backendtrafficpolicy_types.go
@@ -47,6 +47,14 @@ type BackendTrafficPolicySpec struct {
 	PolicyTargetReferences `json:",inline"`
 	ClusterSettings        `json:",inline"`
 
+	// MergeType determines how this configuration is merged with existing BackendTrafficPolicy
+	// configurations targeting a parent resource. When set, this configuration will be merged
+	// into a parent BackendTrafficPolicy (i.e. the one targeting a Gateway or Listener).
+	// This field cannot be set when targeting a parent resource (Gateway).
+	// If unset, no merging occurs, and only the most specific configuration takes effect.
+	// +optional
+	MergeType *MergeType `json:"mergeType,omitempty"`
+
 	// RateLimit allows the user to limit the number of incoming requests
 	// to a predefined value based on attributes within the traffic flow.
 	// +optional
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index 17060cdf5..30558721a 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -594,6 +594,11 @@ func (in *BackendTrafficPolicySpec) DeepCopyInto(out *BackendTrafficPolicySpec)
 	*out = *in
 	in.PolicyTargetReferences.DeepCopyInto(&out.PolicyTargetReferences)
 	in.ClusterSettings.DeepCopyInto(&out.ClusterSettings)
+	if in.MergeType != nil {
+		in, out := &in.MergeType, &out.MergeType
+		*out = new(MergeType)
+		**out = **in
+	}
 	if in.RateLimit != nil {
 		in, out := &in.RateLimit, &out.RateLimit
 		*out = new(RateLimitSpec)
diff --git a/charts/gateway-helm/README.md b/charts/gateway-helm/README.md
index 64cf772ec..d6e89907e 100644
--- a/charts/gateway-helm/README.md
+++ b/charts/gateway-helm/README.md
@@ -60,7 +60,7 @@ To uninstall the chart:
 | Key | Type | Default | Description |
 |-----|------|---------|-------------|
 | certgen | object | `{"job":{"affinity":{},"annotations":{},"args":[],"nodeSelector":{},"resources":{},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"privileged":false,"readOnlyRootFilesystem":true,"runAsGroup":65534,"runAsNonRoot":true,"runAsUser":65534,"seccompProfile":{"type":"RuntimeDefault"}},"tolerations":[],"ttlSecondsAfterFinished":30},"rbac":{"annotations":{},"labels":{}}}` | Certgen is used to generate the certificates required by EnvoyGateway. If you want to construct a custom certificate, you can generate a custom certificate through Cert-Manager before installing EnvoyGateway. Certgen will not overwrite the custom certificate. Please do not manually modify `values.yaml` to disable certgen, it may cause EnvoyGateway OIDC,OAuth2,etc. to not work as expected. |
-| config.envoyGateway | object | `{"gateway":{"controllerName":"gateway.envoyproxy.io/gatewayclass-controller"},"logging":{"level":{"default":"info"}},"provider":{"type":"Kubernetes"}}` | EnvoyGateway configuration. Visit https://gateway.envoyproxy.io/docs/api/extension_types/#envoygateway to view all options. |
+| config.envoyGateway | object | `{"extensionApis":{},"gateway":{"controllerName":"gateway.envoyproxy.io/gatewayclass-controller"},"logging":{"level":{"default":"info"}},"provider":{"type":"Kubernetes"}}` | EnvoyGateway configuration. Visit https://gateway.envoyproxy.io/docs/api/extension_types/#envoygateway to view all options. |
 | createNamespace | bool | `false` |  |
 | deployment.envoyGateway.image.repository | string | `""` |  |
 | deployment.envoyGateway.image.tag | string | `""` |  |
@@ -97,6 +97,8 @@ To uninstall the chart:
 | deployment.ports[3].targetPort | int | `19001` |  |
 | deployment.priorityClassName | string | `nil` |  |
 | deployment.replicas | int | `1` |  |
+| global.imagePullSecrets | list | `[]` | Global override for image pull secrets |
+| global.imageRegistry | string | `""` | Global override for image registry |
 | global.images.envoyGateway.image | string | `nil` |  |
 | global.images.envoyGateway.pullPolicy | string | `nil` |  |
 | global.images.envoyGateway.pullSecrets | list | `[]` |  |
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 3dce65f2b..0a14c5008 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
@@ -678,6 +678,14 @@ spec:
                     LeastRequest load balancers.
                   rule: 'self.type in [''Random'', ''ConsistentHash''] ? !has(self.slowStart)
                     : true '
+              mergeType:
+                description: |-
+                  MergeType determines how this configuration is merged with existing BackendTrafficPolicy
+                  configurations targeting a parent resource. When set, this configuration will be merged
+                  into a parent BackendTrafficPolicy (i.e. the one targeting a Gateway or Listener).
+                  This field cannot be set when targeting a parent resource (Gateway).
+                  If unset, no merging occurs, and only the most specific configuration takes effect.
+                type: string
               proxyProtocol:
                 description: ProxyProtocol enables the Proxy Protocol when communicating
                   with the backend.
diff --git a/charts/gateway-helm/templates/_helpers.tpl b/charts/gateway-helm/templates/_helpers.tpl
index d9aefc2a8..a5d6c1857 100755
--- a/charts/gateway-helm/templates/_helpers.tpl
+++ b/charts/gateway-helm/templates/_helpers.tpl
@@ -65,37 +65,90 @@ Create the name of the service account to use
 The name of the Envoy Gateway image.
 */}}
 {{- define "eg.image" -}}
-{{- if .Values.deployment.envoyGateway.image.repository }}
-{{- .Values.deployment.envoyGateway.image.repository }}:{{ .Values.deployment.envoyGateway.image.tag | default .Values.global.images.envoyGateway.tag | default .Chart.AppVersion }}
-{{- else if .Values.global.images.envoyGateway.image }}
-{{- .Values.global.images.envoyGateway.image }}
-{{- else }}
+{{/* if deployment-specific repository is defined, it takes precedence */}}
+{{- if .Values.deployment.envoyGateway.image.repository -}}
+{{/*  if global.imageRegistry is defined, it takes precedence always */}}
+{{-   if .Values.global.imageRegistry -}}
+{{-     $repositoryParts := splitn "/" 2 .Values.deployment.envoyGateway.image.repository -}}
+{{-     $registryName := .Values.global.imageRegistry -}}
+{{-     $repositoryName := $repositoryParts._1 -}}
+{{-     $imageTag := default .Chart.AppVersion .Values.deployment.envoyGateway.image.tag -}}
+{{-     printf "%s/%s:%s" $registryName $repositoryName $imageTag -}}
+{{/*  if global.imageRegistry is undefined, take repository as is */}}
+{{-   else -}}
+{{-     $imageTag := default .Chart.AppVersion .Values.deployment.envoyGateway.image.tag -}}
+{{-     printf "%s:%s" .Values.deployment.envoyGateway.image.repository $imageTag -}}
+{{-   end -}}
+{{/* else, global image is used if defined */}}
+{{- else if .Values.global.images.envoyGateway.image -}}
+{{-   $imageParts := splitn "/" 2 .Values.global.images.envoyGateway.image -}}
+{{/*    if global.imageRegistry is defined, it takes precedence always */}}
+{{-   $registryName := default $imageParts._0 .Values.global.imageRegistry -}}
+{{-   $repositoryTag := $imageParts._1 -}}
+{{-   $repositoryParts := splitn ":" 2 $repositoryTag -}}
+{{-   $repositoryName := $repositoryParts._0 -}}
+{{-   $imageTag := $repositoryParts._1 -}}
+{{-   printf "%s/%s:%s" $registryName $repositoryName $imageTag -}}
+{{- else -}}
 docker.io/envoyproxy/gateway:{{ .Chart.Version }}
-{{- end }}
-{{- end }}
+{{- end -}}
+{{- end -}}
 
 {{/*
 Pull policy for the Envoy Gateway image.
 */}}
 {{- define "eg.image.pullPolicy" -}}
-{{ .Values.deployment.envoyGateway.imagePullPolicy | default .Values.global.images.envoyGateway.pullPolicy | default "IfNotPresent" }}
+{{- default .Values.deployment.envoyGateway.imagePullPolicy .Values.global.images.envoyGateway.pullPolicy -}}
 {{- end }}
 
 {{/*
 Pull secrets for the Envoy Gateway image.
 */}}
 {{- define "eg.image.pullSecrets" -}}
-{{- if .Values.deployment.envoyGateway.imagePullSecrets -}}
+{{- if .Values.global.imagePullSecrets -}}
+imagePullSecrets:
+{{ toYaml .Values.global.imagePullSecrets }}
+{{- else if .Values.deployment.envoyGateway.imagePullSecrets -}}
 imagePullSecrets:
 {{ toYaml .Values.deployment.envoyGateway.imagePullSecrets }}
 {{- else if .Values.global.images.envoyGateway.pullSecrets -}}
 imagePullSecrets:
 {{ toYaml .Values.global.images.envoyGateway.pullSecrets }}
 {{- else -}}
-imagePullSecrets: []
+imagePullSecrets: {{ toYaml list }}
+{{- end }}
+{{- end }}
+
+{{/*
+The name of the Envoy Ratelimit image.
+*/}}
+{{- define "eg.ratelimit.image" -}}
+{{-   $imageParts := splitn "/" 2 .Values.global.images.ratelimit.image -}}
+{{/*    if global.imageRegistry is defined, it takes precedence always */}}
+{{-   $registryName := default $imageParts._0 .Values.global.imageRegistry -}}
+{{-   $repositoryTag := $imageParts._1 -}}
+{{-   $repositoryParts := splitn ":" 2 $repositoryTag -}}
+{{-   $repositoryName := $repositoryParts._0 -}}
+{{-   $imageTag := default "master" $repositoryParts._1 -}}
+{{-   printf "%s/%s:%s" $registryName $repositoryName $imageTag -}}
+{{- end -}}
+
+{{/*
+Pull secrets for the Envoy Ratelimit image.
+*/}}
+{{- define "eg.ratelimit.image.pullSecrets" -}}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{ toYaml .Values.global.imagePullSecrets }}
+{{- else if .Values.global.images.ratelimit.pullSecrets -}}
+imagePullSecrets:
+{{ toYaml .Values.global.images.ratelimit.pullSecrets }}
+{{- else }}
+imagePullSecrets: {{ toYaml list }}
 {{- end }}
 {{- end }}
 
+
 {{/*
 The default Envoy Gateway configuration.
 */}}
@@ -105,15 +158,10 @@ provider:
   kubernetes:
     rateLimitDeployment:
       container:
-        {{- if .Values.global.images.ratelimit.image }}
-        image: {{ .Values.global.images.ratelimit.image }}
-        {{- else }}
-        image: "docker.io/envoyproxy/ratelimit:master"
-        {{- end }}
-      {{- with .Values.global.images.ratelimit.pullSecrets }}
+        image: {{ include "eg.ratelimit.image" . }}
+      {{- if (or .Values.global.imagePullSecrets .Values.global.images.ratelimit.pullSecrets) }}
       pod:
-        imagePullSecrets:
-        {{- toYaml . | nindent 10 }}
+        {{- include "eg.ratelimit.image.pullSecrets" . | nindent 8 }}
       {{- end }}
       {{- with .Values.global.images.ratelimit.pullPolicy }}
       patch:
@@ -128,4 +176,8 @@ provider:
       {{- end }}
     shutdownManager:
       image: {{ include "eg.image" . }}
+{{- with .Values.config.envoyGateway.extensionApis }}
+extensionApis:
+  {{- toYaml . | nindent 2 }}
+{{- end }}
 {{- end }}
diff --git a/charts/gateway-helm/values.tmpl.yaml b/charts/gateway-helm/values.tmpl.yaml
index 0c166ad82..a0da618d4 100644
--- a/charts/gateway-helm/values.tmpl.yaml
+++ b/charts/gateway-helm/values.tmpl.yaml
@@ -1,6 +1,13 @@
-# The global settings for the Envoy Gateway Helm chart.
-# These values will be used if the values are not overridden in the other sections.
+# Global settings
 global:
+  # If set, these take highest precedence and change both envoyGateway and ratelimit's container registry and pull secrets.
+  # -- Global override for image registry
+  imageRegistry: ""
+  # -- Global override for image pull secrets
+  imagePullSecrets: []
+
+  # If set, these override image-specific values: useful when installing the chart in a private registry environment.
+  # Override image-specific values directly if a global override is not desired.
   images:
     envoyGateway:
       # This is the full image name including the hub, repo, and tag.
@@ -18,6 +25,7 @@ global:
       pullPolicy: IfNotPresent
       # List of secrets in the same namespace of the component that can be used to pull images from private repositories.
       pullSecrets: []
+
 podDisruptionBudget:
   minAvailable: 0
   # maxUnavailable: 1
@@ -25,6 +33,7 @@ podDisruptionBudget:
 deployment:
   envoyGateway:
     image:
+      # if both this and global.imageRegistry are specified, this has to include both registry and repository explicitly, eg docker.io/envoyproxy/gateway
       repository: ""
       tag: ""
     imagePullPolicy: ""
@@ -93,6 +102,7 @@ config:
     logging:
       level:
         default: info
+    extensionApis: {}
 
 createNamespace: false
 
diff --git a/internal/gatewayapi/resource/load.go b/internal/gatewayapi/resource/load.go
index 4cbec0765..a17684939 100644
--- a/internal/gatewayapi/resource/load.go
+++ b/internal/gatewayapi/resource/load.go
@@ -123,8 +123,8 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 					Kind: KindGatewayClass,
 				},
 				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
+					Name: name,
+					// It's weird for non-namespaced resource to have namespace.
 				},
 				Spec: typedSpec.(gwapiv1.GatewayClassSpec),
 			}
@@ -376,6 +376,10 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 		return nil, err
 	}
 
+	// The namespace will not be treated as the missing resources in order to improve the user experience
+	// when using the file provider, since namespaces are crucial but easily overlooked.
+
+	// Add user provided and resource required namespaces.
 	if useDefaultNamespace {
 		if !providedNamespaceMap.Has(config.DefaultNamespace) {
 			namespace := &corev1.Namespace{
@@ -387,22 +391,21 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 			providedNamespaceMap.Insert(config.DefaultNamespace)
 		}
 	}
-
-	if addMissingResources {
-		// Sort the required namespace in order to keep the consistency for test.
-		sortedRequiredNamespace := requiredNamespaceMap.UnsortedList()
-		sort.Strings(sortedRequiredNamespace)
-		for _, ns := range sortedRequiredNamespace {
-			if !providedNamespaceMap.Has(ns) {
-				namespace := &corev1.Namespace{
-					ObjectMeta: metav1.ObjectMeta{
-						Name: ns,
-					},
-				}
-				resources.Namespaces = append(resources.Namespaces, namespace)
+	// Sort the required namespace in order to keep the consistency for test.
+	sortedRequiredNamespace := requiredNamespaceMap.UnsortedList()
+	sort.Strings(sortedRequiredNamespace)
+	for _, ns := range sortedRequiredNamespace {
+		if !providedNamespaceMap.Has(ns) {
+			namespace := &corev1.Namespace{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: ns,
+				},
 			}
+			resources.Namespaces = append(resources.Namespaces, namespace)
 		}
+	}
 
+	if addMissingResources {
 		requiredServiceMap := map[string]*corev1.Service{}
 		for _, route := range resources.TCPRoutes {
 			addMissingServices(requiredServiceMap, route)
@@ -458,7 +461,7 @@ func loadKubernetesYAMLToResources(input []byte, addMissingResources bool) (*Res
 
 		// Add EnvoyProxy if it does not exist.
 		if resources.EnvoyProxyForGatewayClass == nil {
-			if err := addDefaultEnvoyProxy(resources); err != nil {
+			if err := addDefaultEnvoyProxy(resources, config.DefaultNamespace); err != nil {
 				return nil, err
 			}
 		}
@@ -552,13 +555,12 @@ func addMissingServices(requiredServices map[string]*corev1.Service, obj interfa
 	}
 }
 
-func addDefaultEnvoyProxy(resources *Resources) error {
+func addDefaultEnvoyProxy(resources *Resources, namespace string) error {
 	if resources.GatewayClass == nil {
 		return fmt.Errorf("the GatewayClass resource is required")
 	}
 
 	defaultEnvoyProxyName := "default-envoy-proxy"
-	namespace := resources.GatewayClass.Namespace
 	defaultBootstrapStr, err := bootstrap.GetRenderedBootstrapConfig(nil)
 	if err != nil {
 		return err
diff --git a/internal/infrastructure/kubernetes/infra.go b/internal/infrastructure/kubernetes/infra.go
index 82d51d066..2b9916f25 100644
--- a/internal/infrastructure/kubernetes/infra.go
+++ b/internal/infrastructure/kubernetes/infra.go
@@ -36,13 +36,9 @@ type ResourceRender interface {
 	Service() (*corev1.Service, error)
 	ConfigMap() (*corev1.ConfigMap, error)
 	Deployment() (*appsv1.Deployment, error)
-	DeploymentSpec() (*egv1a1.KubernetesDeploymentSpec, error)
 	DaemonSet() (*appsv1.DaemonSet, error)
-	DaemonSetSpec() (*egv1a1.KubernetesDaemonSetSpec, error)
 	HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPodAutoscaler, error)
-	HorizontalPodAutoscalerSpec() (*egv1a1.KubernetesHorizontalPodAutoscalerSpec, error)
 	PodDisruptionBudget() (*policyv1.PodDisruptionBudget, error)
-	PodDisruptionBudgetSpec() (*egv1a1.KubernetesPodDisruptionBudgetSpec, error)
 }
 
 // Infra manages the creation and deletion of Kubernetes infrastructure
diff --git a/internal/infrastructure/kubernetes/infra_resource.go b/internal/infrastructure/kubernetes/infra_resource.go
index 6c2cacc2b..37c5d35fd 100644
--- a/internal/infrastructure/kubernetes/infra_resource.go
+++ b/internal/infrastructure/kubernetes/infra_resource.go
@@ -91,11 +91,6 @@ func (i *Infra) createOrUpdateConfigMap(ctx context.Context, r ResourceRender) (
 // createOrUpdateDeployment creates a Deployment in the kube api server based on the provided
 // ResourceRender, if it doesn't exist and updates it if it does.
 func (i *Infra) createOrUpdateDeployment(ctx context.Context, r ResourceRender) (err error) {
-	// If deployment config is nil,ignore Deployment.
-	if deploymentConfig, er := r.DeploymentSpec(); deploymentConfig == nil {
-		return er
-	}
-
 	var (
 		deployment *appsv1.Deployment
 		startTime  = time.Now()
@@ -183,11 +178,6 @@ func (i *Infra) createOrUpdateDeployment(ctx context.Context, r ResourceRender)
 // createOrUpdateDaemonSet creates a DaemonSet in the kube api server based on the provided
 // ResourceRender, if it doesn't exist and updates it if it does.
 func (i *Infra) createOrUpdateDaemonSet(ctx context.Context, r ResourceRender) (err error) {
-	// If daemonset config is nil, ignore DaemonSet.
-	if daemonSetConfig, er := r.DaemonSetSpec(); daemonSetConfig == nil {
-		return er
-	}
-
 	var (
 		daemonSet *appsv1.DaemonSet
 		startTime = time.Now()
@@ -281,11 +271,6 @@ func isSelectorMatch(labelselector *metav1.LabelSelector, l map[string]string) (
 }
 
 func (i *Infra) createOrUpdatePodDisruptionBudget(ctx context.Context, r ResourceRender) (err error) {
-	// If podDisruptionBudget config is nil or MinAvailable is nil, ignore PodDisruptionBudget.
-	if podDisruptionBudget, er := r.PodDisruptionBudgetSpec(); podDisruptionBudget == nil {
-		return er
-	}
-
 	var (
 		pdb       *policyv1.PodDisruptionBudget
 		startTime = time.Now()
@@ -323,11 +308,6 @@ func (i *Infra) createOrUpdatePodDisruptionBudget(ctx context.Context, r Resourc
 // the provided ResourceRender, if it doesn't exist and updates it if it does,
 // and delete hpa if not set.
 func (i *Infra) createOrUpdateHPA(ctx context.Context, r ResourceRender) (err error) {
-	// If hpa config is nil, ignore HorizontalPodAutoscaler.
-	if hpaConfig, er := r.HorizontalPodAutoscalerSpec(); hpaConfig == nil {
-		return er
-	}
-
 	var (
 		hpa       *autoscalingv2.HorizontalPodAutoscaler
 		startTime = time.Now()
@@ -439,11 +419,6 @@ func (i *Infra) deleteServiceAccount(ctx context.Context, r ResourceRender) (err
 
 // deleteDeployment deletes the Envoy Deployment in the kube api server, if it exists.
 func (i *Infra) deleteDeployment(ctx context.Context, r ResourceRender) (err error) {
-	// If deployment config is nil,ignore Deployment.
-	if deploymentConfig, er := r.DeploymentSpec(); deploymentConfig == nil {
-		return er
-	}
-
 	var (
 		name, ns   = r.Name(), i.Namespace
 		deployment = &appsv1.Deployment{
@@ -479,11 +454,6 @@ func (i *Infra) deleteDeployment(ctx context.Context, r ResourceRender) (err err
 
 // deleteDaemonSet deletes the Envoy DaemonSet in the kube api server, if it exists.
 func (i *Infra) deleteDaemonSet(ctx context.Context, r ResourceRender) (err error) {
-	// If daemonset config is nil, ignore DaemonSet.
-	if daemonSetConfig, er := r.DaemonSetSpec(); daemonSetConfig == nil {
-		return er
-	}
-
 	var (
 		name, ns  = r.Name(), i.Namespace
 		daemonSet = &appsv1.DaemonSet{
@@ -589,11 +559,6 @@ func (i *Infra) deleteService(ctx context.Context, r ResourceRender) (err error)
 
 // deleteHpa deletes the Horizontal Pod Autoscaler associated to its renderer, if it exists.
 func (i *Infra) deleteHPA(ctx context.Context, r ResourceRender) (err error) {
-	// If hpa config is nil, ignore HorizontalPodAutoscaler.
-	if hpaConfig, er := r.HorizontalPodAutoscalerSpec(); hpaConfig == nil {
-		return er
-	}
-
 	var (
 		name, ns = r.Name(), i.Namespace
 		hpa      = &autoscalingv2.HorizontalPodAutoscaler{
@@ -629,11 +594,6 @@ func (i *Infra) deleteHPA(ctx context.Context, r ResourceRender) (err error) {
 
 // deletePDB deletes the PodDistribution budget associated to its renderer, if it exists.
 func (i *Infra) deletePDB(ctx context.Context, r ResourceRender) (err error) {
-	// If podDisruptionBudget config is nil or MinAvailable is nil, ignore PodDisruptionBudget.
-	if podDisruptionBudget, er := r.PodDisruptionBudgetSpec(); podDisruptionBudget == nil {
-		return er
-	}
-
 	var (
 		name, ns = r.Name(), i.Namespace
 		pdb      = &policyv1.PodDisruptionBudget{
diff --git a/internal/infrastructure/kubernetes/proxy/resource_provider.go b/internal/infrastructure/kubernetes/proxy/resource_provider.go
index daa318c2f..6c895c75c 100644
--- a/internal/infrastructure/kubernetes/proxy/resource_provider.go
+++ b/internal/infrastructure/kubernetes/proxy/resource_provider.go
@@ -251,8 +251,8 @@ func (r *ResourceRender) stableSelector() *metav1.LabelSelector {
 	return resource.GetSelector(envoyLabels(labels))
 }
 
-// DeploymentSpec returns the `Deployment` sets spec.
-func (r *ResourceRender) DeploymentSpec() (*egv1a1.KubernetesDeploymentSpec, error) {
+// Deployment returns the expected Deployment based on the provided infra.
+func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) {
 	proxyConfig := r.infra.GetProxyConfig()
 
 	// Get the EnvoyProxy config to configure the deployment.
@@ -260,21 +260,13 @@ func (r *ResourceRender) DeploymentSpec() (*egv1a1.KubernetesDeploymentSpec, err
 	if provider.Type != egv1a1.ProviderTypeKubernetes {
 		return nil, fmt.Errorf("invalid provider type %v for Kubernetes infra manager", provider.Type)
 	}
-
 	deploymentConfig := provider.GetEnvoyProxyKubeProvider().EnvoyDeployment
 
-	return deploymentConfig, nil
-}
-
-// Deployment returns the expected Deployment based on the provided infra.
-func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) {
-	deploymentConfig, er := r.DeploymentSpec()
-	// If deployment config is nil,ignore Deployment.
+	// If deployment config is nil, it's not Deployment installation.
 	if deploymentConfig == nil {
-		return nil, er
+		return nil, nil
 	}
 
-	proxyConfig := r.infra.GetProxyConfig()
 	// Get expected bootstrap configurations rendered ProxyContainers
 	containers, err := expectedProxyContainers(r.infra, deploymentConfig.Container, proxyConfig.Spec.Shutdown, r.ShutdownManager, r.Namespace, r.DNSDomain)
 	if err != nil {
@@ -348,8 +340,7 @@ func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) {
 	return deployment, nil
 }
 
-// DaemonSetSpec returns the `DaemonSet` sets spec.
-func (r *ResourceRender) DaemonSetSpec() (*egv1a1.KubernetesDaemonSetSpec, error) {
+func (r *ResourceRender) DaemonSet() (*appsv1.DaemonSet, error) {
 	proxyConfig := r.infra.GetProxyConfig()
 
 	// Get the EnvoyProxy config to configure the daemonset.
@@ -358,18 +349,13 @@ func (r *ResourceRender) DaemonSetSpec() (*egv1a1.KubernetesDaemonSetSpec, error
 		return nil, fmt.Errorf("invalid provider type %v for Kubernetes infra manager", provider.Type)
 	}
 
-	return provider.GetEnvoyProxyKubeProvider().EnvoyDaemonSet, nil
-}
+	daemonSetConfig := provider.GetEnvoyProxyKubeProvider().EnvoyDaemonSet
 
-func (r *ResourceRender) DaemonSet() (*appsv1.DaemonSet, error) {
-	daemonSetConfig, err := r.DaemonSetSpec()
-	// If daemonset config is nil, ignore DaemonSet.
+	// If daemonset config is nil, it's not DaemonSet installation.
 	if daemonSetConfig == nil {
-		return nil, err
+		return nil, nil
 	}
 
-	proxyConfig := r.infra.GetProxyConfig()
-
 	// Get expected bootstrap configurations rendered ProxyContainers
 	containers, err := expectedProxyContainers(r.infra, daemonSetConfig.Container, proxyConfig.Spec.Shutdown, r.ShutdownManager, r.Namespace, r.DNSDomain)
 	if err != nil {
@@ -424,8 +410,7 @@ func (r *ResourceRender) DaemonSet() (*appsv1.DaemonSet, error) {
 	return daemonSet, nil
 }
 
-// PodDisruptionBudgetSpec returns the `PodDisruptionBudget` sets spec.
-func (r *ResourceRender) PodDisruptionBudgetSpec() (*egv1a1.KubernetesPodDisruptionBudgetSpec, error) {
+func (r *ResourceRender) pdbConfig() (*egv1a1.KubernetesPodDisruptionBudgetSpec, error) {
 	provider := r.infra.GetProxyConfig().GetEnvoyProxyProvider()
 	if provider.Type != egv1a1.ProviderTypeKubernetes {
 		return nil, fmt.Errorf("invalid provider type %v for Kubernetes infra manager", provider.Type)
@@ -440,9 +425,9 @@ func (r *ResourceRender) PodDisruptionBudgetSpec() (*egv1a1.KubernetesPodDisrupt
 }
 
 func (r *ResourceRender) PodDisruptionBudget() (*policyv1.PodDisruptionBudget, error) {
-	podDisruptionBudgetConfig, err := r.PodDisruptionBudgetSpec()
+	pdb, err := r.pdbConfig()
 	// If podDisruptionBudget config is nil, ignore PodDisruptionBudget.
-	if podDisruptionBudgetConfig == nil {
+	if pdb == nil {
 		return nil, err
 	}
 
@@ -450,10 +435,10 @@ func (r *ResourceRender) PodDisruptionBudget() (*policyv1.PodDisruptionBudget, e
 		Selector: r.stableSelector(),
 	}
 	switch {
-	case podDisruptionBudgetConfig.MinAvailable != nil:
-		pdbSpec.MinAvailable = podDisruptionBudgetConfig.MinAvailable
-	case podDisruptionBudgetConfig.MaxUnavailable != nil:
-		pdbSpec.MaxUnavailable = podDisruptionBudgetConfig.MaxUnavailable
+	case pdb.MinAvailable != nil:
+		pdbSpec.MinAvailable = pdb.MinAvailable
+	case pdb.MaxUnavailable != nil:
+		pdbSpec.MaxUnavailable = pdb.MaxUnavailable
 	default:
 		pdbSpec.MinAvailable = &intstr.IntOrString{Type: intstr.Int, IntVal: 0}
 	}
@@ -471,29 +456,22 @@ func (r *ResourceRender) PodDisruptionBudget() (*policyv1.PodDisruptionBudget, e
 	}
 
 	// apply merge patch to PodDisruptionBudget
-	if podDisruptionBudget, err = podDisruptionBudgetConfig.ApplyMergePatch(podDisruptionBudget); err != nil {
+	if podDisruptionBudget, err = pdb.ApplyMergePatch(podDisruptionBudget); err != nil {
 		return nil, err
 	}
 
 	return podDisruptionBudget, nil
 }
 
-// HorizontalPodAutoscalerSpec returns the `HorizontalPodAutoscaler` sets spec.
-func (r *ResourceRender) HorizontalPodAutoscalerSpec() (*egv1a1.KubernetesHorizontalPodAutoscalerSpec, error) {
+func (r *ResourceRender) HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPodAutoscaler, error) {
 	provider := r.infra.GetProxyConfig().GetEnvoyProxyProvider()
 	if provider.Type != egv1a1.ProviderTypeKubernetes {
 		return nil, fmt.Errorf("invalid provider type %v for Kubernetes infra manager", provider.Type)
 	}
 
 	hpaConfig := provider.GetEnvoyProxyKubeProvider().EnvoyHpa
-	return hpaConfig, nil
-}
-
-func (r *ResourceRender) HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPodAutoscaler, error) {
-	hpaConfig, err := r.HorizontalPodAutoscalerSpec()
-	// If hpa config is nil, ignore HorizontalPodAutoscaler.
 	if hpaConfig == nil {
-		return nil, err
+		return nil, nil
 	}
 
 	hpa := &autoscalingv2.HorizontalPodAutoscaler{
@@ -519,8 +497,6 @@ func (r *ResourceRender) HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPod
 		},
 	}
 
-	provider := r.infra.GetProxyConfig().GetEnvoyProxyProvider()
-
 	// set deployment target ref name
 	deploymentConfig := provider.GetEnvoyProxyKubeProvider().EnvoyDeployment
 	if deploymentConfig.Name != nil {
@@ -529,7 +505,8 @@ func (r *ResourceRender) HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPod
 		hpa.Spec.ScaleTargetRef.Name = r.Name()
 	}
 
-	if hpa, err = hpaConfig.ApplyMergePatch(hpa); err != nil {
+	hpa, err := hpaConfig.ApplyMergePatch(hpa)
+	if err != nil {
 		return nil, err
 	}
 
diff --git a/internal/infrastructure/kubernetes/ratelimit/resource_provider.go b/internal/infrastructure/kubernetes/ratelimit/resource_provider.go
index ff183e459..53e3c8d5a 100644
--- a/internal/infrastructure/kubernetes/ratelimit/resource_provider.go
+++ b/internal/infrastructure/kubernetes/ratelimit/resource_provider.go
@@ -191,18 +191,8 @@ func (r *ResourceRender) ServiceAccount() (*corev1.ServiceAccount, error) {
 	return sa, nil
 }
 
-// DeploymentSpec returns the `Deployment` sets spec.
-func (r *ResourceRender) DeploymentSpec() (*egv1a1.KubernetesDeploymentSpec, error) {
-	return r.rateLimitDeployment, nil
-}
-
 // Deployment returns the expected rate limit Deployment based on the provided infra.
 func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) {
-	// If deployment config is nil,ignore Deployment.
-	if deploymentConfig, er := r.DeploymentSpec(); deploymentConfig == nil {
-		return nil, er
-	}
-
 	containers := expectedRateLimitContainers(r.rateLimit, r.rateLimitDeployment, r.Namespace)
 	selector := resource.GetSelector(rateLimitLabels())
 
@@ -299,11 +289,6 @@ func (r *ResourceRender) Deployment() (*appsv1.Deployment, error) {
 	return deployment, nil
 }
 
-// DaemonSetSpec returns the `DaemonSet` sets spec.
-func (r *ResourceRender) DaemonSetSpec() (*egv1a1.KubernetesDaemonSetSpec, error) {
-	return nil, nil
-}
-
 // TODO: implement this method
 func (r *ResourceRender) DaemonSet() (*appsv1.DaemonSet, error) {
 	return nil, nil
@@ -357,11 +342,6 @@ func (r *ResourceRender) HorizontalPodAutoscaler() (*autoscalingv2.HorizontalPod
 	return hpa, nil
 }
 
-// PodDisruptionBudgetSpec returns the `PodDisruptionBudget` sets spec.
-func (r *ResourceRender) PodDisruptionBudgetSpec() (*egv1a1.KubernetesPodDisruptionBudgetSpec, error) {
-	return nil, nil
-}
-
 func (r *ResourceRender) PodDisruptionBudget() (*policyv1.PodDisruptionBudget, error) {
 	return nil, nil
 }
diff --git a/internal/provider/file/file.go b/internal/provider/file/file.go
index c7b28ccec..1cacb8e60 100644
--- a/internal/provider/file/file.go
+++ b/internal/provider/file/file.go
@@ -29,10 +29,11 @@ import (
 )
 
 type Provider struct {
-	paths          []string
-	logger         logr.Logger
-	watcher        filewatcher.FileWatcher
-	resourcesStore *resourcesStore
+	paths                   []string
+	logger                  logr.Logger
+	watcher                 filewatcher.FileWatcher
+	resourcesStore          *resourcesStore
+	extensionManagerEnabled bool
 
 	// ready indicates whether the provider can start watching filesystem events.
 	ready atomic.Bool
@@ -46,10 +47,11 @@ func New(svr *config.Server, resources *message.ProviderResources) (*Provider, e
 	}
 
 	return &Provider{
-		paths:          paths.UnsortedList(),
-		logger:         logger,
-		watcher:        filewatcher.NewWatcher(),
-		resourcesStore: newResourcesStore(svr.EnvoyGateway.Gateway.ControllerName, resources, logger),
+		paths:                   paths.UnsortedList(),
+		logger:                  logger,
+		watcher:                 filewatcher.NewWatcher(),
+		resourcesStore:          newResourcesStore(svr.EnvoyGateway.Gateway.ControllerName, resources, logger),
+		extensionManagerEnabled: svr.EnvoyGateway.EnvoyGatewaySpec.ExtensionManager != nil,
 	}, nil
 }
 
@@ -71,6 +73,9 @@ func (p *Provider) Start(ctx context.Context) error {
 	}
 	go p.startHealthProbeServer(ctx, readyzChecker)
 
+	// Subscribe resources status.
+	p.subscribeAndUpdateStatus(ctx)
+
 	initDirs, initFiles := path.ListDirsAndFiles(p.paths)
 	// Initially load resources from paths on host.
 	if err := p.resourcesStore.LoadAndStore(initFiles.UnsortedList(), initDirs.UnsortedList()); err != nil {
diff --git a/internal/provider/file/status.go b/internal/provider/file/status.go
new file mode 100644
index 000000000..83d86086b
--- /dev/null
+++ b/internal/provider/file/status.go
@@ -0,0 +1,294 @@
+// 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 file
+
+import (
+	"context"
+	"fmt"
+
+	"k8s.io/apimachinery/pkg/types"
+	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+	"sigs.k8s.io/yaml"
+
+	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
+	"github.com/envoyproxy/gateway/internal/message"
+)
+
+func (p *Provider) subscribeAndUpdateStatus(ctx context.Context) {
+	// TODO: trigger gatewayclass status update in file-provider
+	// GatewayClass object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "gatewayclass-status"},
+			p.resourcesStore.resources.GatewayClassStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1.GatewayClassStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindGateway)
+			},
+		)
+		p.logger.Info("gatewayClass status subscriber shutting down")
+	}()
+
+	// Gateway object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "gateway-status"},
+			p.resourcesStore.resources.GatewayStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1.GatewayStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				// Update Gateway conditions, ignore addresses
+				gtw := new(gwapiv1.Gateway)
+				gtw.Status = *update.Value
+				status.UpdateGatewayStatusAccepted(gtw)
+
+				p.logStatus(gtw.Status, resource.KindGateway)
+			},
+		)
+		p.logger.Info("gateway status subscriber shutting down")
+	}()
+
+	// HTTPRoute object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "httproute-status"},
+			p.resourcesStore.resources.HTTPRouteStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1.HTTPRouteStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindHTTPRoute)
+			},
+		)
+		p.logger.Info("httpRoute status subscriber shutting down")
+	}()
+
+	// GRPCRoute object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "grpcroute-status"},
+			p.resourcesStore.resources.GRPCRouteStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1.GRPCRouteStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindGRPCRoute)
+			},
+		)
+		p.logger.Info("grpcRoute status subscriber shutting down")
+	}()
+
+	// TLSRoute object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "tlsroute-status"},
+			p.resourcesStore.resources.TLSRouteStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.TLSRouteStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindTLSRoute)
+			},
+		)
+		p.logger.Info("tlsRoute status subscriber shutting down")
+	}()
+
+	// TCPRoute object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "tcproute-status"},
+			p.resourcesStore.resources.TCPRouteStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.TCPRouteStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindTCPRoute)
+			},
+		)
+		p.logger.Info("tcpRoute status subscriber shutting down")
+	}()
+
+	// UDPRoute object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "udproute-status"},
+			p.resourcesStore.resources.UDPRouteStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.UDPRouteStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindUDPRoute)
+			},
+		)
+		p.logger.Info("udpRoute status subscriber shutting down")
+	}()
+
+	// EnvoyPatchPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "envoypatchpolicy-status"},
+			p.resourcesStore.resources.EnvoyPatchPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindEnvoyPatchPolicy)
+			},
+		)
+		p.logger.Info("envoyPatchPolicy status subscriber shutting down")
+	}()
+
+	// ClientTrafficPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "clienttrafficpolicy-status"},
+			p.resourcesStore.resources.ClientTrafficPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindClientTrafficPolicy)
+			},
+		)
+		p.logger.Info("clientTrafficPolicy status subscriber shutting down")
+	}()
+
+	// BackendTrafficPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "backendtrafficpolicy-status"},
+			p.resourcesStore.resources.BackendTrafficPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindBackendTrafficPolicy)
+			},
+		)
+		p.logger.Info("backendTrafficPolicy status subscriber shutting down")
+	}()
+
+	// SecurityPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "securitypolicy-status"},
+			p.resourcesStore.resources.SecurityPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindSecurityPolicy)
+			},
+		)
+		p.logger.Info("securityPolicy status subscriber shutting down")
+	}()
+
+	// BackendTLSPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "backendtlspolicy-status"},
+			p.resourcesStore.resources.BackendTLSPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindBackendTLSPolicy)
+			},
+		)
+		p.logger.Info("backendTLSPolicy status subscriber shutting down")
+	}()
+
+	// EnvoyExtensionPolicy object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "envoyextensionpolicy-status"},
+			p.resourcesStore.resources.EnvoyExtensionPolicyStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *gwapiv1a2.PolicyStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindEnvoyExtensionPolicy)
+			},
+		)
+		p.logger.Info("envoyExtensionPolicy status subscriber shutting down")
+	}()
+
+	// Backend object status updater
+	go func() {
+		message.HandleSubscription(
+			message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "backend-status"},
+			p.resourcesStore.resources.BackendStatuses.Subscribe(ctx),
+			func(update message.Update[types.NamespacedName, *egv1a1.BackendStatus], errChan chan error) {
+				// skip delete updates.
+				if update.Delete {
+					return
+				}
+
+				p.logStatus(*update.Value, resource.KindBackend)
+			},
+		)
+		p.logger.Info("backend status subscriber shutting down")
+	}()
+
+	if p.extensionManagerEnabled {
+		// ExtensionServerPolicy object status updater
+		go func() {
+			message.HandleSubscription(
+				message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "extensionserverpolicies-status"},
+				p.resourcesStore.resources.ExtensionPolicyStatuses.Subscribe(ctx),
+				func(update message.Update[message.NamespacedNameAndGVK, *gwapiv1a2.PolicyStatus], errChan chan error) {
+					// skip delete updates.
+					if update.Delete {
+						return
+					}
+
+					p.logStatus(*update.Value, "ExtensionServerPolicy")
+				},
+			)
+			p.logger.Info("extensionServerPolicies status subscriber shutting down")
+		}()
+	}
+}
+
+func (p *Provider) logStatus(obj interface{}, statusType string) {
+	if status, err := yaml.Marshal(obj); err == nil {
+		p.logger.Info(fmt.Sprintf("Got new status for %s \n%s", statusType, string(status)))
+	} else {
+		p.logger.Error(err, "failed to log status", "type", statusType)
+	}
+}
diff --git a/internal/provider/kubernetes/status.go b/internal/provider/kubernetes/status.go
index 03ff8f112..5712f9aa7 100644
--- a/internal/provider/kubernetes/status.go
+++ b/internal/provider/kubernetes/status.go
@@ -462,7 +462,7 @@ func (r *gatewayAPIReconciler) subscribeAndUpdateStatus(ctx context.Context, ext
 	}()
 
 	if extensionManagerEnabled {
-		// EnvoyExtensionPolicy object status updater
+		// ExtensionServerPolicy object status updater
 		go func() {
 			message.HandleSubscription(
 				message.Metadata{Runner: string(egv1a1.LogComponentProviderRunner), Message: "extensionserverpolicies-status"},
diff --git a/internal/xds/translator/ratelimit.go b/internal/xds/translator/ratelimit.go
index 1494d9c0b..03b01298d 100644
--- a/internal/xds/translator/ratelimit.go
+++ b/internal/xds/translator/ratelimit.go
@@ -187,8 +187,12 @@ func patchRouteWithRateLimit(route *routev3.Route, irRoute *ir.HTTPRoute) error
 	if !routeContainsGlobalRateLimit(irRoute) || xdsRouteAction == nil {
 		return nil
 	}
-	rateLimits := buildRouteRateLimits(irRoute)
-	return patchRouteWithRateLimitOnTypedFilterConfig(route, rateLimits, irRoute)
+	rateLimits, costSpecified := buildRouteRateLimits(irRoute)
+	if costSpecified {
+		return patchRouteWithRateLimitOnTypedFilterConfig(route, rateLimits, irRoute)
+	}
+	xdsRouteAction.RateLimits = rateLimits
+	return nil
 }
 
 // patchRouteWithRateLimitOnTypedFilterConfig builds rate limit actions and appends to the route via
@@ -218,11 +222,11 @@ func patchRouteWithRateLimitOnTypedFilterConfig(route *routev3.Route, rateLimits
 }
 
 // buildRouteRateLimits constructs rate limit actions for a given route based on the global rate limit configuration.
-func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit) {
+func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit, costSpecified bool) {
 	descriptorPrefix := route.Name
 	// Ensure route has rate limit config
 	if !routeContainsGlobalRateLimit(route) {
-		return nil
+		return nil, false
 	}
 
 	// Determine if the rate limit is shared across multiple routes.
@@ -367,6 +371,7 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit)
 		if c := rule.RequestCost; c != nil {
 			// Set the hits addend for the request cost if specified.
 			rateLimit.HitsAddend = rateLimitCostToHitsAddend(c)
+			costSpecified = true
 		}
 		// Add the rate limit to the list of rate limits.
 		rateLimits = append(rateLimits, rateLimit)
@@ -376,6 +381,7 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit)
 			responseRule := &routev3.RateLimit{Actions: rlActions, ApplyOnStreamDone: true}
 			responseRule.HitsAddend = rateLimitCostToHitsAddend(c)
 			rateLimits = append(rateLimits, responseRule)
+			costSpecified = true
 		}
 	}
 	return
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index abefd245b..8f7c090e0 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -29,7 +29,10 @@ new features: |
   Added support for egctl Websocket in addation to SPDY
   Added a configuration option in the Helm chart to set the TrafficDistribution field in the Envoy Gateway Service
   Added support for setting the log level to trace for the Envoy Proxy
+  Added support for global imageRegistry and imagePullSecrets to the Helm chart
   Added support for using a local JWKS in an inline string or in a ConfigMap to validate JWT tokens in SecurityPolicy
+  Added support for logging the status of resources in standalone mode.
+
 
 bug fixes: |
   Fix traffic splitting when filters are attached to the backendRef.
@@ -43,6 +46,7 @@ bug fixes: |
   Fix allowing empty text field for opentelemetry sink when using JSON format.
   Fix an issue that SamplingFraction was not working.
   Fix kubernetes resources not being deleted when the customized name used.
+  Do not treat essential resource like namespace as the missing resource while loading from file.
 
 # Enhancements that improve performance.
 performance improvements: |
diff --git a/site/content/en/contributions/DEVELOP.md b/site/content/en/contributions/DEVELOP.md
index 4f557fdb0..d608c33e2 100644
--- a/site/content/en/contributions/DEVELOP.md
+++ b/site/content/en/contributions/DEVELOP.md
@@ -123,27 +123,6 @@ workarounds to run conformance tests:
 __Note:__  Preface commands with `IMAGE` or replace `TAG` to use a different Envoy Gateway image or tag. If `TAG`
 is unspecified, the short SHA of your current branch is used.
 
-### Debugging the Envoy Config
-
-An easy way to view the envoy config that Envoy Gateway is using is to port-forward to the admin interface port
-(currently `19000`) on the Envoy deployment that corresponds to a Gateway so that it can be accessed locally.
-
-Get the name of the Envoy deployment. The following example is for Gateway `eg` in the `default` namespace:
-
-```shell
-export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
-```
-
-Port forward the admin interface port:
-
-```shell
-kubectl port-forward deploy/${ENVOY_DEPLOYMENT} -n envoy-gateway-system 19000:19000
-```
-
-Now you are able to view the running Envoy configuration by navigating to `127.0.0.1:19000/config_dump`.
-
-There are many other endpoints on the [Envoy admin interface][] that may be helpful when debugging.
-
 ### JWT Testing
 
 An example [JSON Web Token (JWT)][jwt] and [JSON Web Key Set (JWKS)][jwks] are used for the [request authentication][]
@@ -183,7 +162,6 @@ Here are some brief benchmark reports about Envoy Gateway:
 [Kubernetes support]: https://docs.docker.com/desktop/kubernetes/
 [gateway-dev]: https://hub.docker.com/r/envoyproxy/gateway-dev/tags
 [mac_connect]: https://github.com/chipmk/docker-mac-net-connect
-[Envoy admin interface]: https://www.envoyproxy.io/docs/envoy/latest/operations/admin#operations-admin-interface
 [jwt]: https://tools.ietf.org/html/rfc7519
 [jwks]: https://tools.ietf.org/html/rfc7517
 [request authentication]: ../latest/tasks/security/jwt-authentication
diff --git a/site/content/en/v1.3/tasks/traffic/http-redirect.md b/site/content/en/v1.3/tasks/traffic/http-redirect.md
index 49ccd59ee..4b6585ec4 100644
--- a/site/content/en/v1.3/tasks/traffic/http-redirect.md
+++ b/site/content/en/v1.3/tasks/traffic/http-redirect.md
@@ -308,6 +308,217 @@ curl -v -H 'Host:www.example.com' --resolve "www.example.com:443:$GATEWAY_HOST"
 ```
 
 
+## Force HTTP --> HTTPS redirect
+
+All HTTP requests are forcibly redirected to HTTPS. Application Developers can't override this in their HTTPRoute resources.
+
+Assume Cluster Operators use the `eg` namespace to deploy the Gateway resource:
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: eg
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resource to your cluster:
+
+```yaml
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: eg
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Define the gateway with both http and https listeners, but configure http listener to only accept routes from the same namespace:
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg
+  namespace: eg
+spec:
+  gatewayClassName: eg
+  listeners:
+  - name: http
+    port: 80
+    protocol: HTTP
+    allowedRouters:
+      namespaces:
+        from: Same
+  - name: https
+    port: 443
+    protocol: HTTPS
+    # hostname: "*.example.com"
+    tls:
+      mode: Terminate
+      certificateRefs:
+      - kind: Secret
+        name: example-com
+    allowedRouters:
+      namespaces:
+        from: All
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resource to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg
+  namespace: eg
+spec:
+  gatewayClassName: eg
+  listeners:
+  - name: http
+    port: 80
+    protocol: HTTP
+    allowedRouters:
+      namespaces:
+        from: Same
+  - name: https
+    port: 443
+    protocol: HTTPS
+    # hostname: "*.example.com"
+    tls:
+      mode: Terminate
+      certificateRefs:
+      - kind: Secret
+        name: example-com
+    allowedRouters:
+      namespaces:
+        from: All
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Create the HTTPRoute to reirect requests to HTTPS and attach it to the HTTP listener using the [sectionName][] field. The HTTPRoute has to be in the same namespace as the Gateway to be accepted.
+Do not set hostnames field in the HTTPRoute - it will accept any http request to any hostname and redirect it to the same hostname over https.
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: tls-redirect
+  namespace: eg
+spec:
+  parentRefs:
+    - name: eg
+      sectionName: http
+  rules:
+    - filters:
+        - type: RequestRedirect
+          requestRedirect:
+            scheme: https
+            statusCode: 301
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resources to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: tls-redirect
+  namespace: eg
+spec:
+  parentRefs:
+    - name: eg
+      sectionName: http
+  rules:
+    - filters:
+        - type: RequestRedirect
+          requestRedirect:
+            scheme: https
+            statusCode: 301
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Any other HTTPRoute resources deployed by Application Developers in any other namespace will automatically attach to the https section only, no need to set sectionName for them.
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: backend
+  namespace: default
+spec:
+  parentRefs:
+    - name: eg
+      namespace: eg
+  hostnames:
+    - "www.example.com"
+  rules:
+    - backendRefs:
+        - name: backend
+          port: 3000
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resources to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: backend
+  namespace: default
+spec:
+  parentRefs:
+    - name: eg
+      namespace: default
+  hostnames:
+    - "www.example.com"
+  rules:
+    - backendRefs:
+        - name: backend
+          port: 3000
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+
+
 ## Path Redirects
 
 Path redirects use an HTTP Path Modifier to replace either entire paths or path prefixes. For example, the HTTPRoute
diff --git a/site/content/en/v1.3/troubleshooting/envoy-proxy-admin-interface.md b/site/content/en/v1.3/troubleshooting/envoy-proxy-admin-interface.md
new file mode 100644
index 000000000..7c3e7a4d9
--- /dev/null
+++ b/site/content/en/v1.3/troubleshooting/envoy-proxy-admin-interface.md
@@ -0,0 +1,42 @@
++++
+title = "Advanced: Envoy Proxy Admin Interface"
++++
+
+## Overview
+Platform admins looking to troubleshoot low level aspects of the data plane such as xDS config and heap dump, can directly connect to the Envoy Proxy Admin Interface.
+
+**Note**: Application Developers may not have access to the namespace where the Envoy Proxy fleet is running and should rely on [exported telemetry](https://gateway.envoyproxy.io/docs/tasks/observability/) instead for troubleshooting.
+
+## Prerequisites
+
+{{< boilerplate prerequisites >}}
+
+### Access
+
+You will need to port-forward to the admin interface port (currently 19000) on the Envoy deployment that corresponds to a Gateway, since it only listens on the `localhost`
+address for security reasons.
+
+Get the name of the Envoy deployment. In this example its for Gateway `eg` in the `default` namespace:
+
+```shell
+export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
+```
+
+Port forward to it.
+
+```shell
+kubectl port-forward deploy/${ENVOY_DEPLOYMENT} -n envoy-gateway-system 19000:19000 &
+```
+
+If you enter http://localhost:19000 in a browser, you should be able to access the admin interface.
+
+
+Here's another example of accessing the [/config_dump](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#get--config_dump) endpoint to get access of the loaded xDS configuration.
+
+```shell
+curl http://127.0.0.1:19000/config_dump
+```
+
+### Next Steps
+
+There are many other endpoints in the [Envoy Proxy Admin interface](https://www.envoyproxy.io/docs/envoy/latest/operations/admin) that may be helpful when debugging.


Test patch:
diff --git a/internal/cmd/egctl/testdata/translate/in/default-namespace.yaml b/internal/cmd/egctl/testdata/translate/in/default-namespace.yaml
new file mode 100644
index 000000000..018a253d1
--- /dev/null
+++ b/internal/cmd/egctl/testdata/translate/in/default-namespace.yaml
@@ -0,0 +1,50 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: GatewayClass
+metadata:
+  name: eg
+spec:
+  controllerName: gateway.envoyproxy.io/gatewayclass-controller
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg
+  namespace: default
+spec:
+  gatewayClassName: eg
+  listeners:
+    - name: http
+      protocol: HTTP
+      port: 80
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: Backend
+metadata:
+  name: backend
+  namespace: default
+spec:
+  endpoints:
+    - fqdn:
+        hostname: www.foobar.com
+        port: 443
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: backend
+  namespace: default
+spec:
+  parentRefs:
+    - name: eg
+      namespace: default
+  hostnames:
+    - "www.example.com"
+  rules:
+    - backendRefs:
+        - group: gateway.envoyproxy.io
+          kind: Backend
+          name: backend
+      matches:
+        - path:
+            type: PathPrefix
+            value: /
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 6f516a481..a4a50d9e8 100644
--- a/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/backend-endpoint.all.yaml
@@ -86,7 +86,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
   status:
diff --git a/internal/cmd/egctl/testdata/translate/out/default-namespace.all.yaml b/internal/cmd/egctl/testdata/translate/out/default-namespace.all.yaml
new file mode 100644
index 000000000..be03058a5
--- /dev/null
+++ b/internal/cmd/egctl/testdata/translate/out/default-namespace.all.yaml
@@ -0,0 +1,116 @@
+backends:
+- kind: Backend
+  metadata:
+    creationTimestamp: null
+    name: backend
+    namespace: default
+  spec:
+    endpoints:
+    - fqdn:
+        hostname: www.foobar.com
+        port: 443
+    type: Endpoints
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: The Backend was accepted
+      reason: Accepted
+      status: "True"
+      type: Accepted
+gatewayClass:
+  kind: GatewayClass
+  metadata:
+    creationTimestamp: null
+    name: eg
+  spec:
+    controllerName: gateway.envoyproxy.io/gatewayclass-controller
+  status:
+    conditions:
+    - lastTransitionTime: null
+      message: Valid GatewayClass
+      reason: Accepted
+      status: "True"
+      type: Accepted
+gateways:
+- kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: eg
+    namespace: default
+  spec:
+    gatewayClassName: eg
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: Same
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 1
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: backend
+    namespace: default
+  spec:
+    hostnames:
+    - www.example.com
+    parentRefs:
+    - group: gateway.networking.k8s.io
+      kind: Gateway
+      name: eg
+      namespace: default
+    rules:
+    - backendRefs:
+      - group: gateway.envoyproxy.io
+        kind: Backend
+        name: backend
+        weight: 1
+      matches:
+      - path:
+          type: PathPrefix
+          value: /
+  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:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: eg
+        namespace: default
diff --git a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
index 6cca89f18..ae9d9a5f5 100644
--- a/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/default-resources.all.yaml
@@ -180,7 +180,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
     parametersRef:
diff --git a/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.cluster.yaml b/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.cluster.yaml
index 8d819d612..f7ee04780 100644
--- a/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.cluster.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.cluster.yaml
@@ -3,7 +3,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
   status:
diff --git a/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.route.json b/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.route.json
index cb22c731e..dc69ded7b 100644
--- a/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.route.json
+++ b/internal/cmd/egctl/testdata/translate/out/echo-gateway-api.route.json
@@ -3,7 +3,6 @@
     "kind": "GatewayClass",
     "metadata": {
       "name": "eg",
-      "namespace": "envoy-gateway-system",
       "creationTimestamp": null
     },
     "spec": {
diff --git a/internal/cmd/egctl/testdata/translate/out/invalid-envoyproxy.all.yaml b/internal/cmd/egctl/testdata/translate/out/invalid-envoyproxy.all.yaml
index b51220df3..513131355 100644
--- a/internal/cmd/egctl/testdata/translate/out/invalid-envoyproxy.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/invalid-envoyproxy.all.yaml
@@ -27,7 +27,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
     parametersRef:
diff --git a/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml b/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml
index cff3a5f33..c46b85e13 100644
--- a/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml
@@ -3,7 +3,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
   status:
diff --git a/internal/cmd/egctl/testdata/translate/out/valid-envoyproxy.all.yaml b/internal/cmd/egctl/testdata/translate/out/valid-envoyproxy.all.yaml
index 7ba42aa75..182d48f30 100644
--- a/internal/cmd/egctl/testdata/translate/out/valid-envoyproxy.all.yaml
+++ b/internal/cmd/egctl/testdata/translate/out/valid-envoyproxy.all.yaml
@@ -22,7 +22,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
     parametersRef:
diff --git a/internal/cmd/egctl/translate_test.go b/internal/cmd/egctl/translate_test.go
index e87167ce3..be802ef2d 100644
--- a/internal/cmd/egctl/translate_test.go
+++ b/internal/cmd/egctl/translate_test.go
@@ -294,6 +294,12 @@ func TestTranslate(t *testing.T) {
 			to:     "gateway-api",
 			expect: true,
 		},
+		{
+			name:   "default-namespace",
+			from:   "gateway-api",
+			to:     "gateway-api",
+			expect: true,
+		},
 	}
 
 	flag.Parse()
diff --git a/internal/gatewayapi/resource/testdata/all-resources.out.yaml b/internal/gatewayapi/resource/testdata/all-resources.out.yaml
index 55e2fadb4..5210fa05c 100644
--- a/internal/gatewayapi/resource/testdata/all-resources.out.yaml
+++ b/internal/gatewayapi/resource/testdata/all-resources.out.yaml
@@ -139,7 +139,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
   status: {}
diff --git a/internal/provider/file/testdata/resources.all.yaml b/internal/provider/file/testdata/resources.all.yaml
index d03e36261..00b695657 100644
--- a/internal/provider/file/testdata/resources.all.yaml
+++ b/internal/provider/file/testdata/resources.all.yaml
@@ -16,7 +16,6 @@ gatewayClass:
   metadata:
     creationTimestamp: null
     name: eg
-    namespace: envoy-gateway-system
   spec:
     controllerName: gateway.envoyproxy.io/gatewayclass-controller
   status: {}
diff --git a/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml
index 164206c14..0e312fd92 100644
--- a/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/jwt-ratelimit.routes.yaml
@@ -10,60 +10,52 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
       typedPerFilterConfig:
         envoy.filters.http.jwt_authn:
           '@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.PerRouteConfig
           requirementName: first-route
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-custom-domain.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-custom-domain.routes.yaml
index 953b6b0ae..479c2cd14 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-custom-domain.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-custom-domain.routes.yaml
@@ -10,57 +10,48 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-disable-headers.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-disable-headers.routes.yaml
index 953b6b0ae..479c2cd14 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-disable-headers.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-disable-headers.routes.yaml
@@ -10,57 +10,48 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml
index 953b6b0ae..479c2cd14 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-endpoint-stats.routes.yaml
@@ -10,57 +10,48 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
index 4116f56ed..6eeb9bee6 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
@@ -10,90 +10,78 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-policy-1/test-namespace
+              descriptorValue: test-policy-1/test-namespace
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit/test-policy-1/test-namespace:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: test-policy-1/test-namespace
-                descriptorValue: test-policy-1/test-namespace
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: foo/baz
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-policy-1/test-namespace
+              descriptorValue: test-policy-1/test-namespace
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit/test-policy-1/test-namespace:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: test-policy-1/test-namespace
-                descriptorValue: test-policy-1/test-namespace
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-policy-2/test-namespace
+              descriptorValue: test-policy-2/test-namespace
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: two
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit/test-policy-2/test-namespace:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: test-policy-2/test-namespace
-                descriptorValue: test-policy-2/test-namespace
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: two
     - match:
         path: foo/bar
       name: fourth-route
       route:
         cluster: fourth-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: fourth-route
+              descriptorValue: fourth-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: two
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: fourth-route
-                descriptorValue: fourth-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: two
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-headers-and-cidr.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-headers-and-cidr.routes.yaml
index 58e4ce674..459d975a9 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-headers-and-cidr.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-headers-and-cidr.routes.yaml
@@ -10,88 +10,79 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
+          - requestHeaders:
+              descriptorKey: rule-0-match-1
+              headerName: foobar
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
-            - requestHeaders:
-                descriptorKey: rule-0-match-1
-                headerName: foobar
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
     - match:
         prefix: /
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - headerValueMatch:
+              descriptorKey: rule-1-match-0
+              descriptorValue: rule-1-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: two
+          - requestHeaders:
+              descriptorKey: rule-1-match-1
+              headerName: foobar
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - headerValueMatch:
-                descriptorKey: rule-1-match-0
-                descriptorValue: rule-1-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: two
-            - requestHeaders:
-                descriptorKey: rule-1-match-1
-                headerName: foobar
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-sourceip.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-sourceip.routes.yaml
index 506fa819a..a82f9d5c4 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-sourceip.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-sourceip.routes.yaml
@@ -10,68 +10,56 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 24
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 24
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
     - match:
         path: distinct
       name: fourth-route
       route:
         cluster: fourth-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: fourth-route
+              descriptorValue: fourth-route
+          - maskedRemoteAddress:
+              v4PrefixMaskLen: 16
+          - remoteAddress: {}
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: fourth-route
-                descriptorValue: fourth-route
-            - maskedRemoteAddress:
-                v4PrefixMaskLen: 16
-            - remoteAddress: {}
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml
index 5208104e9..ee127d999 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit.routes.yaml
@@ -10,83 +10,71 @@
       name: first-route
       route:
         cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: first-route
+              descriptorValue: first-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: first-route
-                descriptorValue: first-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: true
-                headers:
-                - name: x-user-id
-                  stringMatch:
-                    exact: one
     - match:
         path: example
       name: second-route
       route:
         cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: second-route
+              descriptorValue: second-route
+          - requestHeaders:
+              descriptorKey: rule-0-match-0
+              headerName: x-user-id
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: second-route
-                descriptorValue: second-route
-            - requestHeaders:
-                descriptorKey: rule-0-match-0
-                headerName: x-user-id
     - match:
         path: test
       name: third-route
       route:
         cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: third-route
+              descriptorValue: third-route
+          - genericKey:
+              descriptorKey: rule-0-match--1
+              descriptorValue: rule-0-match--1
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: third-route
-                descriptorValue: third-route
-            - genericKey:
-                descriptorKey: rule-0-match--1
-                descriptorValue: rule-0-match--1
     - match:
         path: foo/bar/login
       name: fourth-route
       route:
         cluster: fourth-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: fourth-route
+              descriptorValue: fourth-route
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: false
+              headers:
+              - name: x-org-id
+                stringMatch:
+                  exact: admin
         upgradeConfigs:
         - upgradeType: websocket
-      typedPerFilterConfig:
-        envoy.filters.http.ratelimit:
-          '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimitPerRoute
-          rateLimits:
-          - actions:
-            - genericKey:
-                descriptorKey: fourth-route
-                descriptorValue: fourth-route
-            - headerValueMatch:
-                descriptorKey: rule-0-match-0
-                descriptorValue: rule-0-match-0
-                expectMatch: false
-                headers:
-                - name: x-org-id
-                  stringMatch:
-                    exact: admin
     - match:
         path: foo/bar
       name: req-and-resp-cost
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 20a7fd92a..897638a38 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -483,6 +483,7 @@ _Appears in:_
 | `connection` | _[BackendConnection](#backendconnection)_ |  false  |  | Connection includes backend connection settings. |
 | `dns` | _[DNS](#dns)_ |  false  |  | DNS includes dns resolution settings. |
 | `http2` | _[HTTP2Settings](#http2settings)_ |  false  |  | HTTP2 provides HTTP/2 configuration for backend connections. |
+| `mergeType` | _[MergeType](#mergetype)_ |  false  |  | MergeType determines how this configuration is merged with existing BackendTrafficPolicy<br />configurations targeting a parent resource. When set, this configuration will be merged<br />into a parent BackendTrafficPolicy (i.e. the one targeting a Gateway or Listener).<br />This field cannot be set when targeting a parent resource (Gateway).<br />If unset, no merging occurs, and only the most specific configuration takes effect. |
 | `rateLimit` | _[RateLimitSpec](#ratelimitspec)_ |  false  |  | RateLimit allows the user to limit the number of incoming requests<br />to a predefined value based on attributes within the traffic flow. |
 | `faultInjection` | _[FaultInjection](#faultinjection)_ |  false  |  | FaultInjection defines the fault injection policy to be applied. This configuration can be used to<br />inject delays and abort requests to mimic failure scenarios such as service failures and overloads |
 | `useClientProtocol` | _boolean_ |  false  |  | UseClientProtocol configures Envoy to prefer sending requests to backends using<br />the same HTTP protocol that the incoming request used. Defaults to false, which means<br />that Envoy will use the protocol indicated by the attached BackendRef. |
@@ -2999,6 +3000,7 @@ _Underlying type:_ _string_
 MergeType defines the type of merge operation
 
 _Appears in:_
+- [BackendTrafficPolicySpec](#backendtrafficpolicyspec)
 - [KubernetesPatchSpec](#kubernetespatchspec)
 
 | Value | Description |
diff --git a/site/content/en/latest/install/gateway-helm-api.md b/site/content/en/latest/install/gateway-helm-api.md
index 7e44697a6..7ba5e5140 100644
--- a/site/content/en/latest/install/gateway-helm-api.md
+++ b/site/content/en/latest/install/gateway-helm-api.md
@@ -24,7 +24,7 @@ The Helm chart for Envoy Gateway
 | Key | Type | Default | Description |
 |-----|------|---------|-------------|
 | certgen | object | `{"job":{"affinity":{},"annotations":{},"args":[],"nodeSelector":{},"resources":{},"securityContext":{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"privileged":false,"readOnlyRootFilesystem":true,"runAsGroup":65534,"runAsNonRoot":true,"runAsUser":65534,"seccompProfile":{"type":"RuntimeDefault"}},"tolerations":[],"ttlSecondsAfterFinished":30},"rbac":{"annotations":{},"labels":{}}}` | Certgen is used to generate the certificates required by EnvoyGateway. If you want to construct a custom certificate, you can generate a custom certificate through Cert-Manager before installing EnvoyGateway. Certgen will not overwrite the custom certificate. Please do not manually modify `values.yaml` to disable certgen, it may cause EnvoyGateway OIDC,OAuth2,etc. to not work as expected. |
-| config.envoyGateway | object | `{"gateway":{"controllerName":"gateway.envoyproxy.io/gatewayclass-controller"},"logging":{"level":{"default":"info"}},"provider":{"type":"Kubernetes"}}` | EnvoyGateway configuration. Visit https://gateway.envoyproxy.io/docs/api/extension_types/#envoygateway to view all options. |
+| config.envoyGateway | object | `{"extensionApis":{},"gateway":{"controllerName":"gateway.envoyproxy.io/gatewayclass-controller"},"logging":{"level":{"default":"info"}},"provider":{"type":"Kubernetes"}}` | EnvoyGateway configuration. Visit https://gateway.envoyproxy.io/docs/api/extension_types/#envoygateway to view all options. |
 | createNamespace | bool | `false` |  |
 | deployment.envoyGateway.image.repository | string | `""` |  |
 | deployment.envoyGateway.image.tag | string | `""` |  |
@@ -61,6 +61,8 @@ The Helm chart for Envoy Gateway
 | deployment.ports[3].targetPort | int | `19001` |  |
 | deployment.priorityClassName | string | `nil` |  |
 | deployment.replicas | int | `1` |  |
+| global.imagePullSecrets | list | `[]` | Global override for image pull secrets |
+| global.imageRegistry | string | `""` | Global override for image registry |
 | global.images.envoyGateway.image | string | `nil` |  |
 | global.images.envoyGateway.pullPolicy | string | `nil` |  |
 | global.images.envoyGateway.pullSecrets | list | `[]` |  |
diff --git a/site/content/en/latest/tasks/traffic/http-redirect.md b/site/content/en/latest/tasks/traffic/http-redirect.md
index 49ccd59ee..4b6585ec4 100644
--- a/site/content/en/latest/tasks/traffic/http-redirect.md
+++ b/site/content/en/latest/tasks/traffic/http-redirect.md
@@ -308,6 +308,217 @@ curl -v -H 'Host:www.example.com' --resolve "www.example.com:443:$GATEWAY_HOST"
 ```
 
 
+## Force HTTP --> HTTPS redirect
+
+All HTTP requests are forcibly redirected to HTTPS. Application Developers can't override this in their HTTPRoute resources.
+
+Assume Cluster Operators use the `eg` namespace to deploy the Gateway resource:
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: eg
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resource to your cluster:
+
+```yaml
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: eg
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Define the gateway with both http and https listeners, but configure http listener to only accept routes from the same namespace:
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg
+  namespace: eg
+spec:
+  gatewayClassName: eg
+  listeners:
+  - name: http
+    port: 80
+    protocol: HTTP
+    allowedRouters:
+      namespaces:
+        from: Same
+  - name: https
+    port: 443
+    protocol: HTTPS
+    # hostname: "*.example.com"
+    tls:
+      mode: Terminate
+      certificateRefs:
+      - kind: Secret
+        name: example-com
+    allowedRouters:
+      namespaces:
+        from: All
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resource to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg
+  namespace: eg
+spec:
+  gatewayClassName: eg
+  listeners:
+  - name: http
+    port: 80
+    protocol: HTTP
+    allowedRouters:
+      namespaces:
+        from: Same
+  - name: https
+    port: 443
+    protocol: HTTPS
+    # hostname: "*.example.com"
+    tls:
+      mode: Terminate
+      certificateRefs:
+      - kind: Secret
+        name: example-com
+    allowedRouters:
+      namespaces:
+        from: All
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Create the HTTPRoute to reirect requests to HTTPS and attach it to the HTTP listener using the [sectionName][] field. The HTTPRoute has to be in the same namespace as the Gateway to be accepted.
+Do not set hostnames field in the HTTPRoute - it will accept any http request to any hostname and redirect it to the same hostname over https.
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: tls-redirect
+  namespace: eg
+spec:
+  parentRefs:
+    - name: eg
+      sectionName: http
+  rules:
+    - filters:
+        - type: RequestRedirect
+          requestRedirect:
+            scheme: https
+            statusCode: 301
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resources to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: tls-redirect
+  namespace: eg
+spec:
+  parentRefs:
+    - name: eg
+      sectionName: http
+  rules:
+    - filters:
+        - type: RequestRedirect
+          requestRedirect:
+            scheme: https
+            statusCode: 301
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+Any other HTTPRoute resources deployed by Application Developers in any other namespace will automatically attach to the https section only, no need to set sectionName for them.
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: backend
+  namespace: default
+spec:
+  parentRefs:
+    - name: eg
+      namespace: eg
+  hostnames:
+    - "www.example.com"
+  rules:
+    - backendRefs:
+        - name: backend
+          port: 3000
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resources to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: backend
+  namespace: default
+spec:
+  parentRefs:
+    - name: eg
+      namespace: default
+  hostnames:
+    - "www.example.com"
+  rules:
+    - backendRefs:
+        - name: backend
+          port: 3000
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+
+
 ## Path Redirects
 
 Path redirects use an HTTP Path Modifier to replace either entire paths or path prefixes. For example, the HTTPRoute
diff --git a/site/content/en/latest/troubleshooting/envoy-proxy-admin-interface.md b/site/content/en/latest/troubleshooting/envoy-proxy-admin-interface.md
new file mode 100644
index 000000000..7c3e7a4d9
--- /dev/null
+++ b/site/content/en/latest/troubleshooting/envoy-proxy-admin-interface.md
@@ -0,0 +1,42 @@
++++
+title = "Advanced: Envoy Proxy Admin Interface"
++++
+
+## Overview
+Platform admins looking to troubleshoot low level aspects of the data plane such as xDS config and heap dump, can directly connect to the Envoy Proxy Admin Interface.
+
+**Note**: Application Developers may not have access to the namespace where the Envoy Proxy fleet is running and should rely on [exported telemetry](https://gateway.envoyproxy.io/docs/tasks/observability/) instead for troubleshooting.
+
+## Prerequisites
+
+{{< boilerplate prerequisites >}}
+
+### Access
+
+You will need to port-forward to the admin interface port (currently 19000) on the Envoy deployment that corresponds to a Gateway, since it only listens on the `localhost`
+address for security reasons.
+
+Get the name of the Envoy deployment. In this example its for Gateway `eg` in the `default` namespace:
+
+```shell
+export ENVOY_DEPLOYMENT=$(kubectl get deploy -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=eg -o jsonpath='{.items[0].metadata.name}')
+```
+
+Port forward to it.
+
+```shell
+kubectl port-forward deploy/${ENVOY_DEPLOYMENT} -n envoy-gateway-system 19000:19000 &
+```
+
+If you enter http://localhost:19000 in a browser, you should be able to access the admin interface.
+
+
+Here's another example of accessing the [/config_dump](https://www.envoyproxy.io/docs/envoy/latest/operations/admin#get--config_dump) endpoint to get access of the loaded xDS configuration.
+
+```shell
+curl http://127.0.0.1:19000/config_dump
+```
+
+### Next Steps
+
+There are many other endpoints in the [Envoy Proxy Admin interface](https://www.envoyproxy.io/docs/envoy/latest/operations/admin) that may be helpful when debugging.
diff --git a/test/e2e/testdata/envoyproxy-hpa.yaml b/test/e2e/testdata/envoyproxy-hpa.yaml
new file mode 100644
index 000000000..2fbd0ffbe
--- /dev/null
+++ b/test/e2e/testdata/envoyproxy-hpa.yaml
@@ -0,0 +1,50 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg-hpa
+  namespace: gateway-conformance-infra
+spec:
+  gatewayClassName: "{GATEWAY_CLASS_NAME}"
+  listeners:
+    - name: http
+      port: 80
+      protocol: HTTP
+      allowedRoutes:
+        namespaces:
+          from: All
+  infrastructure:
+    parametersRef:
+      group: gateway.envoyproxy.io
+      kind: EnvoyProxy
+      name: eg-hpa
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: EnvoyProxy
+metadata:
+  name: eg-hpa
+  namespace: gateway-conformance-infra
+spec:
+  ipFamily: IPv4
+  provider:
+    type: Kubernetes
+    kubernetes:
+      envoyHpa:
+        minReplicas: 1
+        maxReplicas: 2
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: foo-route
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: eg-hpa
+  rules:
+    - backendRefs:
+        - name: infra-backend-v1
+          port: 8080
+      matches:
+        - path:
+            type: PathPrefix
+            value: /foo
diff --git a/test/e2e/tests/envoyproxy_hpa.go b/test/e2e/tests/envoyproxy_hpa.go
new file mode 100644
index 000000000..4e4a830e0
--- /dev/null
+++ b/test/e2e/tests/envoyproxy_hpa.go
@@ -0,0 +1,68 @@
+// 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.
+
+//go:build e2e
+
+package tests
+
+import (
+	"context"
+	"testing"
+
+	"k8s.io/apimachinery/pkg/types"
+	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"sigs.k8s.io/gateway-api/conformance/utils/http"
+	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
+	"sigs.k8s.io/gateway-api/conformance/utils/suite"
+)
+
+func init() {
+	ConformanceTests = append(ConformanceTests, EnvoyProxyHPATest)
+}
+
+var EnvoyProxyHPATest = suite.ConformanceTest{
+	ShortName:   "EnvoyProxyHPA",
+	Description: "Test running Envoy with HPA",
+	Manifests:   []string{"testdata/envoyproxy-hpa.yaml"},
+	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
+		t.Run("RunAndDelete", func(t *testing.T) {
+			ns := "gateway-conformance-infra"
+			routeNN := types.NamespacedName{Name: "foo-route", Namespace: ns}
+			gwNN := types.NamespacedName{Name: "eg-hpa", Namespace: ns}
+			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+			OkResp := http.ExpectedResponse{
+				Request: http.Request{
+					Path: "/foo",
+				},
+				Response: http.Response{
+					StatusCode: 200,
+				},
+				Namespace: ns,
+			}
+
+			// Make sure there's a deployment/HPA for the gateway
+			ExpectEnvoyProxyDeploymentCount(t, suite, gwNN, 1)
+			ExpectEnvoyProxyHPACount(t, suite, gwNN, 1)
+
+			// Send a request to a valid path and expect a successful response
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, OkResp)
+
+			// Update the Gateway to without HPA
+			gw := &gwapiv1.Gateway{}
+			err := suite.Client.Get(context.Background(), gwNN, gw)
+			if err != nil {
+				t.Fatalf("Failed to get Gateway: %v", err)
+			}
+			gw.Spec.Infrastructure = nil
+			err = suite.Client.Update(context.Background(), gw)
+			if err != nil {
+				t.Fatalf("Failed to update Gateway: %v", err)
+			}
+
+			ExpectEnvoyProxyDeploymentCount(t, suite, gwNN, 1)
+			ExpectEnvoyProxyHPACount(t, suite, gwNN, 0)
+		})
+	},
+}
diff --git a/test/e2e/tests/utils.go b/test/e2e/tests/utils.go
index f5545df82..123640277 100644
--- a/test/e2e/tests/utils.go
+++ b/test/e2e/tests/utils.go
@@ -28,6 +28,8 @@ import (
 	dto "github.com/prometheus/client_model/go"
 	"github.com/prometheus/common/expfmt"
 	"github.com/stretchr/testify/require"
+	appsv1 "k8s.io/api/apps/v1"
+	autoscalingv2 "k8s.io/api/autoscaling/v2"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
@@ -726,3 +728,47 @@ func ContentEncoding(compressorType egv1a1.CompressorType) string {
 
 	return encoding
 }
+
+func ExpectEnvoyProxyDeploymentCount(t *testing.T, suite *suite.ConformanceTestSuite, gwNN types.NamespacedName, expectedCount int) {
+	err := wait.PollUntilContextTimeout(context.TODO(), time.Second, suite.TimeoutConfig.DeleteTimeout, true, func(ctx context.Context) (bool, error) {
+		deploys := &appsv1.DeploymentList{}
+		err := suite.Client.List(ctx, deploys, &client.ListOptions{
+			Namespace: "envoy-gateway-system",
+			LabelSelector: labels.SelectorFromSet(map[string]string{
+				"app.kubernetes.io/managed-by":                   "envoy-gateway",
+				"app.kubernetes.io/name":                         "envoy",
+				"gateway.envoyproxy.io/owning-gateway-name":      gwNN.Name,
+				"gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace,
+			}),
+		})
+		if err != nil {
+			return false, err
+		}
+
+		return len(deploys.Items) == expectedCount, err
+	})
+	if err != nil {
+		t.Fatalf("Failed to check Deployment count(%d) for the Gateway: %v", expectedCount, err)
+	}
+}
+
+func ExpectEnvoyProxyHPACount(t *testing.T, suite *suite.ConformanceTestSuite, gwNN types.NamespacedName, expectedCount int) {
+	err := wait.PollUntilContextTimeout(context.TODO(), time.Second, suite.TimeoutConfig.DeleteTimeout, true, func(ctx context.Context) (bool, error) {
+		hpa := &autoscalingv2.HorizontalPodAutoscalerList{}
+		err := suite.Client.List(ctx, hpa, &client.ListOptions{
+			Namespace: "envoy-gateway-system",
+			LabelSelector: labels.SelectorFromSet(map[string]string{
+				"gateway.envoyproxy.io/owning-gateway-name":      gwNN.Name,
+				"gateway.envoyproxy.io/owning-gateway-namespace": gwNN.Namespace,
+			}),
+		})
+		if err != nil {
+			return false, err
+		}
+
+		return len(hpa.Items) == 1, err
+	})
+	if err != nil {
+		t.Fatalf("Failed to check HPA count(%d) for the Gateway: %v", expectedCount, err)
+	}
+}
diff --git a/test/helm/gateway-helm/certgen-args.in.yaml b/test/helm/gateway-helm/certgen-args.in.yaml
index ca8864e6a..9f027b898 100644
--- a/test/helm/gateway-helm/certgen-args.in.yaml
+++ b/test/helm/gateway-helm/certgen-args.in.yaml
@@ -3,7 +3,8 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 certgen:
   job:
     args:
-    - --overwrite
\ No newline at end of file
+    - --overwrite
diff --git a/test/helm/gateway-helm/certgen-args.out.yaml b/test/helm/gateway-helm/certgen-args.out.yaml
index d52753db2..166e1b85e 100644
--- a/test/helm/gateway-helm/certgen-args.out.yaml
+++ b/test/helm/gateway-helm/certgen-args.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/certjen-custom-scheduling.in.yaml b/test/helm/gateway-helm/certjen-custom-scheduling.in.yaml
index c579310e0..dec84e688 100644
--- a/test/helm/gateway-helm/certjen-custom-scheduling.in.yaml
+++ b/test/helm/gateway-helm/certjen-custom-scheduling.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 certgen:
   job:
     affinity:
@@ -18,4 +19,4 @@ certgen:
       - effect: NoSchedule
         key: taint1
         operator: Equal
-        value: tol1
\ No newline at end of file
+        value: tol1
diff --git a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml
index 37d0212f7..7be662633 100644
--- a/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml
+++ b/test/helm/gateway-helm/certjen-custom-scheduling.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/control-plane-with-pdb.in.yaml b/test/helm/gateway-helm/control-plane-with-pdb.in.yaml
index ef71656e5..1531b798a 100644
--- a/test/helm/gateway-helm/control-plane-with-pdb.in.yaml
+++ b/test/helm/gateway-helm/control-plane-with-pdb.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 podDisruptionBudget:
   minAvailable: 1
   maxUnavailable: 1
diff --git a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml
index 69f08e1db..b59dfb5b7 100644
--- a/test/helm/gateway-helm/control-plane-with-pdb.out.yaml
+++ b/test/helm/gateway-helm/control-plane-with-pdb.out.yaml
@@ -43,6 +43,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/default-config.out.yaml b/test/helm/gateway-helm/default-config.out.yaml
index 6e1b1846b..4ebb13c56 100644
--- a/test/helm/gateway-helm/default-config.out.yaml
+++ b/test/helm/gateway-helm/default-config.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/deployment-custom-topology.in.yaml b/test/helm/gateway-helm/deployment-custom-topology.in.yaml
index fe16f64d2..ba122b4a2 100644
--- a/test/helm/gateway-helm/deployment-custom-topology.in.yaml
+++ b/test/helm/gateway-helm/deployment-custom-topology.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 deployment:
   pod:
     affinity:
diff --git a/test/helm/gateway-helm/deployment-custom-topology.out.yaml b/test/helm/gateway-helm/deployment-custom-topology.out.yaml
index 0bc580933..4d3030444 100644
--- a/test/helm/gateway-helm/deployment-custom-topology.out.yaml
+++ b/test/helm/gateway-helm/deployment-custom-topology.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/deployment-images-config.out.yaml b/test/helm/gateway-helm/deployment-images-config.out.yaml
index f99a89039..307abf9ee 100644
--- a/test/helm/gateway-helm/deployment-images-config.out.yaml
+++ b/test/helm/gateway-helm/deployment-images-config.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/deployment-priorityclass.in.yaml b/test/helm/gateway-helm/deployment-priorityclass.in.yaml
index f5dbd6afc..a3c25cbb8 100644
--- a/test/helm/gateway-helm/deployment-priorityclass.in.yaml
+++ b/test/helm/gateway-helm/deployment-priorityclass.in.yaml
@@ -3,5 +3,6 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 deployment:
   priorityClassName: system-cluster-critical
diff --git a/test/helm/gateway-helm/deployment-priorityclass.out.yaml b/test/helm/gateway-helm/deployment-priorityclass.out.yaml
index 3757e360d..389e070be 100644
--- a/test/helm/gateway-helm/deployment-priorityclass.out.yaml
+++ b/test/helm/gateway-helm/deployment-priorityclass.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/deployment-repo-no-registry.in.yaml b/test/helm/gateway-helm/deployment-repo-no-registry.in.yaml
new file mode 100644
index 000000000..3be324a67
--- /dev/null
+++ b/test/helm/gateway-helm/deployment-repo-no-registry.in.yaml
@@ -0,0 +1,5 @@
+deployment:
+  envoyGateway:
+    image:
+      repository: "envoy/gateway"
+      tag: "abcdef"
diff --git a/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml b/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml
new file mode 100644
index 000000000..3f1fc5644
--- /dev/null
+++ b/test/helm/gateway-helm/deployment-repo-no-registry.out.yaml
@@ -0,0 +1,574 @@
+---
+# Source: gateway-helm/templates/envoy-gateway-serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+---
+# Source: gateway-helm/templates/envoy-gateway-config.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: envoy-gateway-config
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+data:
+  envoy-gateway.yaml: |
+    apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: EnvoyGateway
+    gateway:
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    logging:
+      level:
+        default: info
+    provider:
+      kubernetes:
+        rateLimitDeployment:
+          container:
+            image: docker.io/envoyproxy/ratelimit:master
+          patch:
+            type: StrategicMerge
+            value:
+              spec:
+                template:
+                  spec:
+                    containers:
+                    - imagePullPolicy: IfNotPresent
+                      name: envoy-ratelimit
+        shutdownManager:
+          image: envoy/gateway:abcdef
+      type: Kubernetes
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: gateway-helm-envoy-gateway-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  - namespaces
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses/status
+  verbs:
+  - update
+- apiGroups:
+  - multicluster.x-k8s.io
+  resources:
+  - serviceimports
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - discovery.k8s.io
+  resources:
+  - endpointslices
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoyproxies
+  - envoypatchpolicies
+  - clienttrafficpolicies
+  - backendtrafficpolicies
+  - securitypolicies
+  - envoyextensionpolicies
+  - backends
+  - httproutefilters
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoypatchpolicies/status
+  - clienttrafficpolicies/status
+  - backendtrafficpolicies/status
+  - securitypolicies/status
+  - envoyextensionpolicies/status
+  - backends/status
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways
+  - grpcroutes
+  - httproutes
+  - referencegrants
+  - tcproutes
+  - tlsroutes
+  - udproutes
+  - backendtlspolicies
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways/status
+  - grpcroutes/status
+  - httproutes/status
+  - tcproutes/status
+  - tlsroutes/status
+  - udproutes/status
+  - backendtlspolicies/status
+  verbs:
+  - update
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: gateway-helm-envoy-gateway-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: gateway-helm-envoy-gateway-role
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  - services
+  - configmaps
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - autoscaling
+  - policy
+  resources:
+  - horizontalpodautoscalers
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-leader-election-role
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-infra-manager'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-leader-election-rolebinding
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-leader-election-role'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/envoy-gateway-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  selector:
+    control-plane: envoy-gateway
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+  ports:
+  - name: grpc
+    port: 18000
+    targetPort: 18000
+  - name: ratelimit
+    port: 18001
+    targetPort: 18001
+  - name: wasm
+    port: 18002
+    targetPort: 18002
+  - name: metrics
+    port: 19001
+    targetPort: 19001
+---
+# Source: gateway-helm/templates/envoy-gateway-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      control-plane: envoy-gateway
+      app.kubernetes.io/name: gateway-helm
+      app.kubernetes.io/instance: gateway-helm
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "19001"
+        prometheus.io/scrape: "true"
+      labels:
+        control-plane: envoy-gateway
+        app.kubernetes.io/name: gateway-helm
+        app.kubernetes.io/instance: gateway-helm
+    spec:
+      containers:
+      - args:
+        - server
+        - --config-path=/config/envoy-gateway.yaml
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: envoy/gateway:abcdef
+        imagePullPolicy: IfNotPresent
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        name: envoy-gateway
+        ports:
+        - containerPort: 18000
+          name: grpc
+        - containerPort: 18001
+          name: ratelimit
+        - containerPort: 18002
+          name: wasm
+        - containerPort: 19001
+          name: metrics
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        resources:
+          limits:
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 256Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          runAsGroup: 65532
+          runAsNonRoot: true
+          runAsUser: 65532
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /config
+          name: envoy-gateway-config
+          readOnly: true
+        - mountPath: /certs
+          name: certs
+          readOnly: true
+      imagePullSecrets: []
+      serviceAccountName: envoy-gateway
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: envoy-gateway-config
+        name: envoy-gateway-config
+      - name: certs
+        secret:
+          secretName: envoy-gateway
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+  - update
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-certgen'
+subjects:
+- kind: ServiceAccount
+  name: 'gateway-helm-certgen'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/certgen.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install, pre-upgrade
+spec:
+  backoffLimit: 1
+  completions: 1
+  parallelism: 1
+  template:
+    metadata:
+      labels:
+        app: certgen
+    spec:
+      containers:
+      - command:
+        - envoy-gateway
+        - certgen
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: envoy/gateway:abcdef
+        imagePullPolicy: IfNotPresent
+        name: envoy-gateway-certgen
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsGroup: 65534
+          runAsNonRoot: true
+          runAsUser: 65534
+          seccompProfile:
+            type: RuntimeDefault
+      imagePullSecrets: []
+      restartPolicy: Never
+      serviceAccountName: gateway-helm-certgen
+  ttlSecondsAfterFinished: 30
diff --git a/test/helm/gateway-helm/deployment-securitycontext.in.yaml b/test/helm/gateway-helm/deployment-securitycontext.in.yaml
index 47b8d1cec..317c10ee1 100644
--- a/test/helm/gateway-helm/deployment-securitycontext.in.yaml
+++ b/test/helm/gateway-helm/deployment-securitycontext.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 deployment:
   envoyGateway:
     securityContext:
diff --git a/test/helm/gateway-helm/deployment-securitycontext.out.yaml b/test/helm/gateway-helm/deployment-securitycontext.out.yaml
index e98bd1e97..73cf210aa 100644
--- a/test/helm/gateway-helm/deployment-securitycontext.out.yaml
+++ b/test/helm/gateway-helm/deployment-securitycontext.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/envoy-gateway-config.in.yaml b/test/helm/gateway-helm/envoy-gateway-config.in.yaml
index 936d3ddf8..cea617ef2 100644
--- a/test/helm/gateway-helm/envoy-gateway-config.in.yaml
+++ b/test/helm/gateway-helm/envoy-gateway-config.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 config:
   envoyGateway:
     gateway:
diff --git a/test/helm/gateway-helm/envoy-gateway-config.out.yaml b/test/helm/gateway-helm/envoy-gateway-config.out.yaml
index fb1e51f22..5a85a78ee 100644
--- a/test/helm/gateway-helm/envoy-gateway-config.out.yaml
+++ b/test/helm/gateway-helm/envoy-gateway-config.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/global-images-config.out.yaml b/test/helm/gateway-helm/global-images-config.out.yaml
index ebcda594b..cdbf6a72e 100644
--- a/test/helm/gateway-helm/global-images-config.out.yaml
+++ b/test/helm/gateway-helm/global-images-config.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/global-pullsecrets-override-deployment.in.yaml b/test/helm/gateway-helm/global-pullsecrets-override-deployment.in.yaml
new file mode 100644
index 000000000..c51bc53a8
--- /dev/null
+++ b/test/helm/gateway-helm/global-pullsecrets-override-deployment.in.yaml
@@ -0,0 +1,24 @@
+global:
+  imageRegistry: "private.registry"
+  imagePullSecrets:
+    - key1: "value1"
+    - key2: "value2"
+
+  images:
+    envoyGateway:
+      image: "docker.io/envoyproxy/gateway-dev:latest"
+      pullPolicy: Always
+      pullSecrets:
+        - key5: "value5"
+        - key6: "value6"
+    ratelimit:
+      image: "docker.io/envoyproxy/ratelimit:master"
+
+deployment:
+  envoyGateway:
+    image:
+      repository: "docker.io/envoy/gateway"
+      tag: "abcdef"
+    imagePullSecrets:
+      - key3: "value3"
+      - key4: "value4"
diff --git a/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml b/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml
new file mode 100644
index 000000000..0cb61e651
--- /dev/null
+++ b/test/helm/gateway-helm/global-pullsecrets-override-deployment.out.yaml
@@ -0,0 +1,582 @@
+---
+# Source: gateway-helm/templates/envoy-gateway-serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+---
+# Source: gateway-helm/templates/envoy-gateway-config.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: envoy-gateway-config
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+data:
+  envoy-gateway.yaml: |
+    apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: EnvoyGateway
+    gateway:
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    logging:
+      level:
+        default: info
+    provider:
+      kubernetes:
+        rateLimitDeployment:
+          container:
+            image: private.registry/envoyproxy/ratelimit:master
+          patch:
+            type: StrategicMerge
+            value:
+              spec:
+                template:
+                  spec:
+                    containers:
+                    - imagePullPolicy: IfNotPresent
+                      name: envoy-ratelimit
+          pod:
+            imagePullSecrets:
+            - key1: value1
+            - key2: value2
+        shutdownManager:
+          image: private.registry/envoy/gateway:abcdef
+      type: Kubernetes
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: gateway-helm-envoy-gateway-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  - namespaces
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses/status
+  verbs:
+  - update
+- apiGroups:
+  - multicluster.x-k8s.io
+  resources:
+  - serviceimports
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - discovery.k8s.io
+  resources:
+  - endpointslices
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoyproxies
+  - envoypatchpolicies
+  - clienttrafficpolicies
+  - backendtrafficpolicies
+  - securitypolicies
+  - envoyextensionpolicies
+  - backends
+  - httproutefilters
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoypatchpolicies/status
+  - clienttrafficpolicies/status
+  - backendtrafficpolicies/status
+  - securitypolicies/status
+  - envoyextensionpolicies/status
+  - backends/status
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways
+  - grpcroutes
+  - httproutes
+  - referencegrants
+  - tcproutes
+  - tlsroutes
+  - udproutes
+  - backendtlspolicies
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways/status
+  - grpcroutes/status
+  - httproutes/status
+  - tcproutes/status
+  - tlsroutes/status
+  - udproutes/status
+  - backendtlspolicies/status
+  verbs:
+  - update
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: gateway-helm-envoy-gateway-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: gateway-helm-envoy-gateway-role
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  - services
+  - configmaps
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - autoscaling
+  - policy
+  resources:
+  - horizontalpodautoscalers
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-leader-election-role
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-infra-manager'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-leader-election-rolebinding
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-leader-election-role'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/envoy-gateway-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  selector:
+    control-plane: envoy-gateway
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+  ports:
+  - name: grpc
+    port: 18000
+    targetPort: 18000
+  - name: ratelimit
+    port: 18001
+    targetPort: 18001
+  - name: wasm
+    port: 18002
+    targetPort: 18002
+  - name: metrics
+    port: 19001
+    targetPort: 19001
+---
+# Source: gateway-helm/templates/envoy-gateway-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      control-plane: envoy-gateway
+      app.kubernetes.io/name: gateway-helm
+      app.kubernetes.io/instance: gateway-helm
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "19001"
+        prometheus.io/scrape: "true"
+      labels:
+        control-plane: envoy-gateway
+        app.kubernetes.io/name: gateway-helm
+        app.kubernetes.io/instance: gateway-helm
+    spec:
+      containers:
+      - args:
+        - server
+        - --config-path=/config/envoy-gateway.yaml
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoy/gateway:abcdef
+        imagePullPolicy: Always
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        name: envoy-gateway
+        ports:
+        - containerPort: 18000
+          name: grpc
+        - containerPort: 18001
+          name: ratelimit
+        - containerPort: 18002
+          name: wasm
+        - containerPort: 19001
+          name: metrics
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        resources:
+          limits:
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 256Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          runAsGroup: 65532
+          runAsNonRoot: true
+          runAsUser: 65532
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /config
+          name: envoy-gateway-config
+          readOnly: true
+        - mountPath: /certs
+          name: certs
+          readOnly: true
+      imagePullSecrets:
+      - key1: value1
+      - key2: value2
+      serviceAccountName: envoy-gateway
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: envoy-gateway-config
+        name: envoy-gateway-config
+      - name: certs
+        secret:
+          secretName: envoy-gateway
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+  - update
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-certgen'
+subjects:
+- kind: ServiceAccount
+  name: 'gateway-helm-certgen'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/certgen.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install, pre-upgrade
+spec:
+  backoffLimit: 1
+  completions: 1
+  parallelism: 1
+  template:
+    metadata:
+      labels:
+        app: certgen
+    spec:
+      containers:
+      - command:
+        - envoy-gateway
+        - certgen
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoy/gateway:abcdef
+        imagePullPolicy: Always
+        name: envoy-gateway-certgen
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsGroup: 65534
+          runAsNonRoot: true
+          runAsUser: 65534
+          seccompProfile:
+            type: RuntimeDefault
+      imagePullSecrets:
+      - key1: value1
+      - key2: value2
+      restartPolicy: Never
+      serviceAccountName: gateway-helm-certgen
+  ttlSecondsAfterFinished: 30
diff --git a/test/helm/gateway-helm/global-pullsecrets-override-global.in.yaml b/test/helm/gateway-helm/global-pullsecrets-override-global.in.yaml
new file mode 100644
index 000000000..36b65a7dd
--- /dev/null
+++ b/test/helm/gateway-helm/global-pullsecrets-override-global.in.yaml
@@ -0,0 +1,15 @@
+global:
+  imageRegistry: "private.registry"
+  imagePullSecrets:
+    - key1: "value1"
+    - key2: "value2"
+
+  images:
+    envoyGateway:
+      image: "docker.io/envoyproxy/gateway-dev:latest"
+      pullPolicy: Always
+      pullSecrets:
+        - key5: "value5"
+        - key6: "value6"
+    ratelimit:
+      image: "docker.io/envoyproxy/ratelimit:master"
diff --git a/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml b/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml
new file mode 100644
index 000000000..afc036bcb
--- /dev/null
+++ b/test/helm/gateway-helm/global-pullsecrets-override-global.out.yaml
@@ -0,0 +1,582 @@
+---
+# Source: gateway-helm/templates/envoy-gateway-serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+---
+# Source: gateway-helm/templates/envoy-gateway-config.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: envoy-gateway-config
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+data:
+  envoy-gateway.yaml: |
+    apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: EnvoyGateway
+    gateway:
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    logging:
+      level:
+        default: info
+    provider:
+      kubernetes:
+        rateLimitDeployment:
+          container:
+            image: private.registry/envoyproxy/ratelimit:master
+          patch:
+            type: StrategicMerge
+            value:
+              spec:
+                template:
+                  spec:
+                    containers:
+                    - imagePullPolicy: IfNotPresent
+                      name: envoy-ratelimit
+          pod:
+            imagePullSecrets:
+            - key1: value1
+            - key2: value2
+        shutdownManager:
+          image: private.registry/envoyproxy/gateway-dev:latest
+      type: Kubernetes
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: gateway-helm-envoy-gateway-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  - namespaces
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses/status
+  verbs:
+  - update
+- apiGroups:
+  - multicluster.x-k8s.io
+  resources:
+  - serviceimports
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - discovery.k8s.io
+  resources:
+  - endpointslices
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoyproxies
+  - envoypatchpolicies
+  - clienttrafficpolicies
+  - backendtrafficpolicies
+  - securitypolicies
+  - envoyextensionpolicies
+  - backends
+  - httproutefilters
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoypatchpolicies/status
+  - clienttrafficpolicies/status
+  - backendtrafficpolicies/status
+  - securitypolicies/status
+  - envoyextensionpolicies/status
+  - backends/status
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways
+  - grpcroutes
+  - httproutes
+  - referencegrants
+  - tcproutes
+  - tlsroutes
+  - udproutes
+  - backendtlspolicies
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways/status
+  - grpcroutes/status
+  - httproutes/status
+  - tcproutes/status
+  - tlsroutes/status
+  - udproutes/status
+  - backendtlspolicies/status
+  verbs:
+  - update
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: gateway-helm-envoy-gateway-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: gateway-helm-envoy-gateway-role
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  - services
+  - configmaps
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - autoscaling
+  - policy
+  resources:
+  - horizontalpodautoscalers
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-leader-election-role
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-infra-manager'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-leader-election-rolebinding
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-leader-election-role'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/envoy-gateway-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  selector:
+    control-plane: envoy-gateway
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+  ports:
+  - name: grpc
+    port: 18000
+    targetPort: 18000
+  - name: ratelimit
+    port: 18001
+    targetPort: 18001
+  - name: wasm
+    port: 18002
+    targetPort: 18002
+  - name: metrics
+    port: 19001
+    targetPort: 19001
+---
+# Source: gateway-helm/templates/envoy-gateway-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      control-plane: envoy-gateway
+      app.kubernetes.io/name: gateway-helm
+      app.kubernetes.io/instance: gateway-helm
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "19001"
+        prometheus.io/scrape: "true"
+      labels:
+        control-plane: envoy-gateway
+        app.kubernetes.io/name: gateway-helm
+        app.kubernetes.io/instance: gateway-helm
+    spec:
+      containers:
+      - args:
+        - server
+        - --config-path=/config/envoy-gateway.yaml
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoyproxy/gateway-dev:latest
+        imagePullPolicy: Always
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        name: envoy-gateway
+        ports:
+        - containerPort: 18000
+          name: grpc
+        - containerPort: 18001
+          name: ratelimit
+        - containerPort: 18002
+          name: wasm
+        - containerPort: 19001
+          name: metrics
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        resources:
+          limits:
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 256Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          runAsGroup: 65532
+          runAsNonRoot: true
+          runAsUser: 65532
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /config
+          name: envoy-gateway-config
+          readOnly: true
+        - mountPath: /certs
+          name: certs
+          readOnly: true
+      imagePullSecrets:
+      - key1: value1
+      - key2: value2
+      serviceAccountName: envoy-gateway
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: envoy-gateway-config
+        name: envoy-gateway-config
+      - name: certs
+        secret:
+          secretName: envoy-gateway
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+  - update
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-certgen'
+subjects:
+- kind: ServiceAccount
+  name: 'gateway-helm-certgen'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/certgen.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install, pre-upgrade
+spec:
+  backoffLimit: 1
+  completions: 1
+  parallelism: 1
+  template:
+    metadata:
+      labels:
+        app: certgen
+    spec:
+      containers:
+      - command:
+        - envoy-gateway
+        - certgen
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoyproxy/gateway-dev:latest
+        imagePullPolicy: Always
+        name: envoy-gateway-certgen
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsGroup: 65534
+          runAsNonRoot: true
+          runAsUser: 65534
+          seccompProfile:
+            type: RuntimeDefault
+      imagePullSecrets:
+      - key1: value1
+      - key2: value2
+      restartPolicy: Never
+      serviceAccountName: gateway-helm-certgen
+  ttlSecondsAfterFinished: 30
diff --git a/test/helm/gateway-helm/global-registry-override-deployment.in.yaml b/test/helm/gateway-helm/global-registry-override-deployment.in.yaml
new file mode 100644
index 000000000..a7d7e02ed
--- /dev/null
+++ b/test/helm/gateway-helm/global-registry-override-deployment.in.yaml
@@ -0,0 +1,14 @@
+global:
+  imageRegistry: "private.registry"
+  images:
+    envoyGateway:
+      image: "docker.io/envoyproxy/gateway-dev:latest"
+      pullPolicy: Always
+    ratelimit:
+      image: "docker.io/envoyproxy/ratelimit:master"
+
+deployment:
+  envoyGateway:
+    image:
+      repository: "docker.io/envoy/gateway"
+      tag: "abcdef"
diff --git a/test/helm/gateway-helm/global-registry-override-deployment.out.yaml b/test/helm/gateway-helm/global-registry-override-deployment.out.yaml
new file mode 100644
index 000000000..6acac25c8
--- /dev/null
+++ b/test/helm/gateway-helm/global-registry-override-deployment.out.yaml
@@ -0,0 +1,574 @@
+---
+# Source: gateway-helm/templates/envoy-gateway-serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+---
+# Source: gateway-helm/templates/envoy-gateway-config.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: envoy-gateway-config
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+data:
+  envoy-gateway.yaml: |
+    apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: EnvoyGateway
+    gateway:
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    logging:
+      level:
+        default: info
+    provider:
+      kubernetes:
+        rateLimitDeployment:
+          container:
+            image: private.registry/envoyproxy/ratelimit:master
+          patch:
+            type: StrategicMerge
+            value:
+              spec:
+                template:
+                  spec:
+                    containers:
+                    - imagePullPolicy: IfNotPresent
+                      name: envoy-ratelimit
+        shutdownManager:
+          image: private.registry/envoy/gateway:abcdef
+      type: Kubernetes
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: gateway-helm-envoy-gateway-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  - namespaces
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses/status
+  verbs:
+  - update
+- apiGroups:
+  - multicluster.x-k8s.io
+  resources:
+  - serviceimports
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - discovery.k8s.io
+  resources:
+  - endpointslices
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoyproxies
+  - envoypatchpolicies
+  - clienttrafficpolicies
+  - backendtrafficpolicies
+  - securitypolicies
+  - envoyextensionpolicies
+  - backends
+  - httproutefilters
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoypatchpolicies/status
+  - clienttrafficpolicies/status
+  - backendtrafficpolicies/status
+  - securitypolicies/status
+  - envoyextensionpolicies/status
+  - backends/status
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways
+  - grpcroutes
+  - httproutes
+  - referencegrants
+  - tcproutes
+  - tlsroutes
+  - udproutes
+  - backendtlspolicies
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways/status
+  - grpcroutes/status
+  - httproutes/status
+  - tcproutes/status
+  - tlsroutes/status
+  - udproutes/status
+  - backendtlspolicies/status
+  verbs:
+  - update
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: gateway-helm-envoy-gateway-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: gateway-helm-envoy-gateway-role
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  - services
+  - configmaps
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - autoscaling
+  - policy
+  resources:
+  - horizontalpodautoscalers
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-leader-election-role
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-infra-manager'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-leader-election-rolebinding
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-leader-election-role'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/envoy-gateway-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  selector:
+    control-plane: envoy-gateway
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+  ports:
+  - name: grpc
+    port: 18000
+    targetPort: 18000
+  - name: ratelimit
+    port: 18001
+    targetPort: 18001
+  - name: wasm
+    port: 18002
+    targetPort: 18002
+  - name: metrics
+    port: 19001
+    targetPort: 19001
+---
+# Source: gateway-helm/templates/envoy-gateway-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      control-plane: envoy-gateway
+      app.kubernetes.io/name: gateway-helm
+      app.kubernetes.io/instance: gateway-helm
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "19001"
+        prometheus.io/scrape: "true"
+      labels:
+        control-plane: envoy-gateway
+        app.kubernetes.io/name: gateway-helm
+        app.kubernetes.io/instance: gateway-helm
+    spec:
+      containers:
+      - args:
+        - server
+        - --config-path=/config/envoy-gateway.yaml
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoy/gateway:abcdef
+        imagePullPolicy: Always
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        name: envoy-gateway
+        ports:
+        - containerPort: 18000
+          name: grpc
+        - containerPort: 18001
+          name: ratelimit
+        - containerPort: 18002
+          name: wasm
+        - containerPort: 19001
+          name: metrics
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        resources:
+          limits:
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 256Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          runAsGroup: 65532
+          runAsNonRoot: true
+          runAsUser: 65532
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /config
+          name: envoy-gateway-config
+          readOnly: true
+        - mountPath: /certs
+          name: certs
+          readOnly: true
+      imagePullSecrets: []
+      serviceAccountName: envoy-gateway
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: envoy-gateway-config
+        name: envoy-gateway-config
+      - name: certs
+        secret:
+          secretName: envoy-gateway
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+  - update
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-certgen'
+subjects:
+- kind: ServiceAccount
+  name: 'gateway-helm-certgen'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/certgen.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install, pre-upgrade
+spec:
+  backoffLimit: 1
+  completions: 1
+  parallelism: 1
+  template:
+    metadata:
+      labels:
+        app: certgen
+    spec:
+      containers:
+      - command:
+        - envoy-gateway
+        - certgen
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoy/gateway:abcdef
+        imagePullPolicy: Always
+        name: envoy-gateway-certgen
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsGroup: 65534
+          runAsNonRoot: true
+          runAsUser: 65534
+          seccompProfile:
+            type: RuntimeDefault
+      imagePullSecrets: []
+      restartPolicy: Never
+      serviceAccountName: gateway-helm-certgen
+  ttlSecondsAfterFinished: 30
diff --git a/test/helm/gateway-helm/global-registry-override-global.in.yaml b/test/helm/gateway-helm/global-registry-override-global.in.yaml
new file mode 100644
index 000000000..365e73275
--- /dev/null
+++ b/test/helm/gateway-helm/global-registry-override-global.in.yaml
@@ -0,0 +1,8 @@
+global:
+  imageRegistry: "private.registry"
+  images:
+    envoyGateway:
+      image: "docker.io/envoyproxy/gateway-dev:latest"
+      pullPolicy: Always
+    ratelimit:
+      image: "docker.io/envoyproxy/ratelimit:master"
diff --git a/test/helm/gateway-helm/global-registry-override-global.out.yaml b/test/helm/gateway-helm/global-registry-override-global.out.yaml
new file mode 100644
index 000000000..e70e8bd88
--- /dev/null
+++ b/test/helm/gateway-helm/global-registry-override-global.out.yaml
@@ -0,0 +1,574 @@
+---
+# Source: gateway-helm/templates/envoy-gateway-serviceaccount.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+---
+# Source: gateway-helm/templates/envoy-gateway-config.yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: envoy-gateway-config
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+data:
+  envoy-gateway.yaml: |
+    apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: EnvoyGateway
+    gateway:
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    logging:
+      level:
+        default: info
+    provider:
+      kubernetes:
+        rateLimitDeployment:
+          container:
+            image: private.registry/envoyproxy/ratelimit:master
+          patch:
+            type: StrategicMerge
+            value:
+              spec:
+                template:
+                  spec:
+                    containers:
+                    - imagePullPolicy: IfNotPresent
+                      name: envoy-ratelimit
+        shutdownManager:
+          image: private.registry/envoyproxy/gateway-dev:latest
+      type: Kubernetes
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: gateway-helm-envoy-gateway-role
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  - namespaces
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gatewayclasses/status
+  verbs:
+  - update
+- apiGroups:
+  - multicluster.x-k8s.io
+  resources:
+  - serviceimports
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  - secrets
+  - services
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - discovery.k8s.io
+  resources:
+  - endpointslices
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoyproxies
+  - envoypatchpolicies
+  - clienttrafficpolicies
+  - backendtrafficpolicies
+  - securitypolicies
+  - envoyextensionpolicies
+  - backends
+  - httproutefilters
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.envoyproxy.io
+  resources:
+  - envoypatchpolicies/status
+  - clienttrafficpolicies/status
+  - backendtrafficpolicies/status
+  - securitypolicies/status
+  - envoyextensionpolicies/status
+  - backends/status
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways
+  - grpcroutes
+  - httproutes
+  - referencegrants
+  - tcproutes
+  - tlsroutes
+  - udproutes
+  - backendtlspolicies
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - gateways/status
+  - grpcroutes/status
+  - httproutes/status
+  - tcproutes/status
+  - tlsroutes/status
+  - udproutes/status
+  - backendtlspolicies/status
+  verbs:
+  - update
+---
+# Source: gateway-helm/templates/envoy-gateway-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: gateway-helm-envoy-gateway-rolebinding
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: gateway-helm-envoy-gateway-role
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - serviceaccounts
+  - services
+  - configmaps
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+- apiGroups:
+  - autoscaling
+  - policy
+  resources:
+  - horizontalpodautoscalers
+  - poddisruptionbudgets
+  verbs:
+  - create
+  - get
+  - delete
+  - deletecollection
+  - patch
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-leader-election-role
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - configmaps
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - get
+  - list
+  - watch
+  - create
+  - update
+  - patch
+  - delete
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - patch
+---
+# Source: gateway-helm/templates/infra-manager-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-infra-manager
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-infra-manager'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/leader-election-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-leader-election-rolebinding
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-leader-election-role'
+subjects:
+- kind: ServiceAccount
+  name: 'envoy-gateway'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/envoy-gateway-service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  selector:
+    control-plane: envoy-gateway
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+  ports:
+  - name: grpc
+    port: 18000
+    targetPort: 18000
+  - name: ratelimit
+    port: 18001
+    targetPort: 18001
+  - name: wasm
+    port: 18002
+    targetPort: 18002
+  - name: metrics
+    port: 19001
+    targetPort: 19001
+---
+# Source: gateway-helm/templates/envoy-gateway-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: envoy-gateway
+  namespace: 'envoy-gateway-system'
+  labels:
+    control-plane: envoy-gateway
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      control-plane: envoy-gateway
+      app.kubernetes.io/name: gateway-helm
+      app.kubernetes.io/instance: gateway-helm
+  template:
+    metadata:
+      annotations:
+        prometheus.io/port: "19001"
+        prometheus.io/scrape: "true"
+      labels:
+        control-plane: envoy-gateway
+        app.kubernetes.io/name: gateway-helm
+        app.kubernetes.io/instance: gateway-helm
+    spec:
+      containers:
+      - args:
+        - server
+        - --config-path=/config/envoy-gateway.yaml
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoyproxy/gateway-dev:latest
+        imagePullPolicy: Always
+        livenessProbe:
+          httpGet:
+            path: /healthz
+            port: 8081
+          initialDelaySeconds: 15
+          periodSeconds: 20
+        name: envoy-gateway
+        ports:
+        - containerPort: 18000
+          name: grpc
+        - containerPort: 18001
+          name: ratelimit
+        - containerPort: 18002
+          name: wasm
+        - containerPort: 19001
+          name: metrics
+        readinessProbe:
+          httpGet:
+            path: /readyz
+            port: 8081
+          initialDelaySeconds: 5
+          periodSeconds: 10
+        resources:
+          limits:
+            memory: 1024Mi
+          requests:
+            cpu: 100m
+            memory: 256Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          runAsGroup: 65532
+          runAsNonRoot: true
+          runAsUser: 65532
+          seccompProfile:
+            type: RuntimeDefault
+        volumeMounts:
+        - mountPath: /config
+          name: envoy-gateway-config
+          readOnly: true
+        - mountPath: /certs
+          name: certs
+          readOnly: true
+      imagePullSecrets: []
+      serviceAccountName: envoy-gateway
+      terminationGracePeriodSeconds: 10
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: envoy-gateway-config
+        name: envoy-gateway-config
+      - name: certs
+        secret:
+          secretName: envoy-gateway
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - secrets
+  verbs:
+  - get
+  - create
+  - update
+---
+# Source: gateway-helm/templates/certgen-rbac.yaml
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: 'gateway-helm-certgen'
+subjects:
+- kind: ServiceAccount
+  name: 'gateway-helm-certgen'
+  namespace: 'envoy-gateway-system'
+---
+# Source: gateway-helm/templates/certgen.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: gateway-helm-certgen
+  namespace: 'envoy-gateway-system'
+  labels:
+    helm.sh/chart: gateway-helm-v0.0.0-latest
+    app.kubernetes.io/name: gateway-helm
+    app.kubernetes.io/instance: gateway-helm
+    app.kubernetes.io/version: "latest"
+    app.kubernetes.io/managed-by: Helm
+  annotations:
+    "helm.sh/hook": pre-install, pre-upgrade
+spec:
+  backoffLimit: 1
+  completions: 1
+  parallelism: 1
+  template:
+    metadata:
+      labels:
+        app: certgen
+    spec:
+      containers:
+      - command:
+        - envoy-gateway
+        - certgen
+        env:
+        - name: ENVOY_GATEWAY_NAMESPACE
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: metadata.namespace
+        - name: KUBERNETES_CLUSTER_DOMAIN
+          value: cluster.local
+        image: private.registry/envoyproxy/gateway-dev:latest
+        imagePullPolicy: Always
+        name: envoy-gateway-certgen
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          privileged: false
+          readOnlyRootFilesystem: true
+          runAsGroup: 65534
+          runAsNonRoot: true
+          runAsUser: 65534
+          seccompProfile:
+            type: RuntimeDefault
+      imagePullSecrets: []
+      restartPolicy: Never
+      serviceAccountName: gateway-helm-certgen
+  ttlSecondsAfterFinished: 30
diff --git a/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml b/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml
index fb75b1bf8..5f4a42ef0 100644
--- a/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml
+++ b/test/helm/gateway-helm/horizontal-pod-autoscaler.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging:
diff --git a/test/helm/gateway-helm/service-customization.in.yaml b/test/helm/gateway-helm/service-customization.in.yaml
index 4d80e7cd7..6c35d65f2 100644
--- a/test/helm/gateway-helm/service-customization.in.yaml
+++ b/test/helm/gateway-helm/service-customization.in.yaml
@@ -3,6 +3,7 @@ global:
     envoyGateway:
       image: "docker.io/envoyproxy/gateway-dev:latest"
       pullPolicy: Always
+
 service:
   trafficDistribution: PreferClose
   annotations:
diff --git a/test/helm/gateway-helm/service-customization.out.yaml b/test/helm/gateway-helm/service-customization.out.yaml
index f72169d4f..bec59b891 100644
--- a/test/helm/gateway-helm/service-customization.out.yaml
+++ b/test/helm/gateway-helm/service-customization.out.yaml
@@ -28,6 +28,7 @@ data:
   envoy-gateway.yaml: |
     apiVersion: gateway.envoyproxy.io/v1alpha1
     kind: EnvoyGateway
+    extensionApis: {}
     gateway:
       controllerName: gateway.envoyproxy.io/gatewayclass-controller
     logging: