Repository: envoyproxy/gateway
Pull request #4235 (2024-09-13 14:59:28)

refactor: add gatewayapi/resource pkg
**What type of PR is this?**
<!--
Your PR title should be descriptive, and generally start with type that contains a subsystem name with `()` if necessary 
and summary followed by a colon. format `chore/docs/api/feat/fix/refactor/style/test: summary`.
Examples:
* "docs: fix grammar error"
* "feat(translator): add new feature"
* "fix: fix xx bug"
* "chore: change ci & build tools etc"
* "api: add xxx fields in ClientTrafficPolicy"
-->

<!--
NOTE: If your PR contains any API changes (changes under `/api`), we recommend you to separate these API changes into
a new PR, and we will review the API part first. It will save you lots of implementation time if the API get accepted.
-->

**What this PR does / why we need it**:

- move `gatewayapi/resource.go` into `gatewayapi/resource/*`
- move `gatewayapi/translator.go's kind` into `gatewayapi/resource/*`
- move shared `kubernetesYAMLToResources` func into `gatewayapi/resource/*`

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
This is a refactor PR before implementing https://github.com/envoyproxy/gateway/issues/1295, and it's very likely to get conflicts, so should be reviewed ASAP.


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
Attention: Patch coverage is `26.16984%` with `426 lines` in your changes missing coverage. Please review.
> Project coverage is 65.65%. Comparing base [(`14f687f`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/14f687fb4fd18b98de654d22119f4e4bd10a71e2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`bb107ef`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/bb107ef4f3baa8f112ef62b82f3442462db9a419?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

| [Files with missing lines](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) | Patch % | Lines |
|---|---|---|
| [internal/gatewayapi/resource/load.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fgatewayapi%2Fresource%2Fload.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvZ2F0ZXdheWFwaS9yZXNvdXJjZS9sb2FkLmdv) | 0.00% | [333 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/controller.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Fcontroller.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9jb250cm9sbGVyLmdv) | 38.46% | [24 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/cmd/egctl/status.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fcmd%2Fegctl%2Fstatus.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvY21kL2VnY3RsL3N0YXR1cy5nbw==) | 0.00% | [13 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/routes.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Froutes.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9yb3V0ZXMuZ28=) | 0.00% | [12 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/status\_updater.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Fstatus_updater.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9zdGF0dXNfdXBkYXRlci5nbw==) | 14.28% | [12 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/gatewayapi/validate.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fgatewayapi%2Fvalidate.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvZ2F0ZXdheWFwaS92YWxpZGF0ZS5nbw==) | 72.00% | [3 Missing and 4 partials :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/file/resources.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Ffile%2Fresources.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIvZmlsZS9yZXNvdXJjZXMuZ28=) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/file/store.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Ffile%2Fstore.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIvZmlsZS9zdG9yZS5nbw==) | 0.00% | [5 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/helpers.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Fhelpers.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9oZWxwZXJzLmdv) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| [internal/provider/kubernetes/indexers.go](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&filepath=internal%2Fprovider%2Fkubernetes%2Findexers.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy#diff-aW50ZXJuYWwvcHJvdmlkZXIva3ViZXJuZXRlcy9pbmRleGVycy5nbw==) | 83.33% | [3 Missing :warning: ](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) |
| ... and [6 more](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) | |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #4235      +/-   ##
==========================================
- Coverage   66.50%   65.65%   -0.86%     
==========================================
  Files         195      196       +1     
  Lines       23732    23538     -194     
==========================================
- Hits        15783    15453     -330     
- Misses       6831     6976     +145     
+ Partials     1118     1109       -9     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/4235?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).


Patch:
diff --git a/api/v1alpha1/httproutefilter_types.go b/api/v1alpha1/httproutefilter_types.go
new file mode 100644
index 000000000..b8fe13f52
--- /dev/null
+++ b/api/v1alpha1/httproutefilter_types.go
@@ -0,0 +1,101 @@
+// 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 v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+const (
+	// KindHTTPRouteFilter is the name of the HTTPRouteFilter kind.
+	KindHTTPRouteFilter = "HTTPRouteFilter"
+)
+
+// +kubebuilder:object:root=true
+// +kubebuilder:resource:categories=envoy-gateway,shortName=hrf
+// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
+
+// HTTPRouteFilter is a custom Envoy Gateway HTTPRouteFilter which provides extended
+// traffic processing options such as path regex rewrite, direct response and more.
+type HTTPRouteFilter struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	// Spec defines the desired state of HTTPRouteFilter.
+	Spec HTTPRouteFilterSpec `json:"spec"`
+}
+
+// HTTPRouteFilterSpec defines the desired state of HTTPRouteFilter.
+// +union
+type HTTPRouteFilterSpec struct {
+	// +optional
+	URLRewrite *HTTPURLRewriteFilter `json:"urlRewrite,omitempty"`
+}
+
+// HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host
+type HTTPURLRewriteFilter struct {
+	// Path defines a path rewrite.
+	//
+	// +optional
+	Path *HTTPPathModifier `json:"path,omitempty"`
+}
+
+// HTTPPathModifierType defines the type of path redirect or rewrite.
+type HTTPPathModifierType string
+
+const (
+	// RegexHTTPPathModifier This type of modifier indicates that the portions of the path that match the specified
+	//  regex would be substituted with the specified substitution value
+	// https://www.envoyproxy.io/docs/envoy/latest/api-v3/type/matcher/v3/regex.proto#type-matcher-v3-regexmatchandsubstitute
+	RegexHTTPPathModifier HTTPPathModifierType = "ReplaceRegexMatch"
+)
+
+type ReplaceRegexMatch struct {
+	// Pattern matches a regular expression against the value of the HTTP Path.The regex string must
+	// adhere to the syntax documented in https://github.com/google/re2/wiki/Syntax.
+	Pattern string `json:"pattern"`
+	// Substitution is an expression that replaces the matched portion.The expression may include numbered
+	// capture groups that adhere to syntax documented in https://github.com/google/re2/wiki/Syntax.
+	Substitution string `json:"substitution"`
+}
+
+type HTTPPathModifier struct {
+	// +kubebuilder:validation:Enum=RegexHTTPPathModifier
+	Type HTTPPathModifierType `json:"type"`
+	// ReplaceRegexMatch defines a path regex rewrite. The path portions matched by the regex pattern are replaced by the defined substitution.
+	// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-regex-rewrite
+	// Some examples:
+	// (1) replaceRegexMatch:
+	//       pattern: ^/service/([^/]+)(/.*)$
+	//       substitution: \2/instance/\1
+	//     Would transform /service/foo/v1/api into /v1/api/instance/foo.
+	// (2) replaceRegexMatch:
+	//       pattern: one
+	//       substitution: two
+	//     Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/two/zzz.
+	// (3) replaceRegexMatch:
+	//       pattern: ^(.*?)one(.*)$
+	//       substitution: \1two\2
+	//     Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/one/zzz.
+	// (3) replaceRegexMatch:
+	//       pattern: (?i)/xxx/
+	//       substitution: /yyy/
+	//     Would transform path /aaa/XxX/bbb into /aaa/yyy/bbb (case-insensitive).
+	ReplaceRegexMatch *ReplaceRegexMatch `json:"replaceRegexMatch,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// HTTPRouteFilterList contains a list of HTTPRouteFilter resources.
+type HTTPRouteFilterList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []HTTPRouteFilter `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&HTTPRouteFilter{}, &HTTPRouteFilterList{})
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index f2c88ae0c..7ee438d5b 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -2625,6 +2625,104 @@ func (in *HTTPExtAuthService) DeepCopy() *HTTPExtAuthService {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPPathModifier) DeepCopyInto(out *HTTPPathModifier) {
+	*out = *in
+	if in.ReplaceRegexMatch != nil {
+		in, out := &in.ReplaceRegexMatch, &out.ReplaceRegexMatch
+		*out = new(ReplaceRegexMatch)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPPathModifier.
+func (in *HTTPPathModifier) DeepCopy() *HTTPPathModifier {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPPathModifier)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPRouteFilter) DeepCopyInto(out *HTTPRouteFilter) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteFilter.
+func (in *HTTPRouteFilter) DeepCopy() *HTTPRouteFilter {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPRouteFilter)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *HTTPRouteFilter) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPRouteFilterList) DeepCopyInto(out *HTTPRouteFilterList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]HTTPRouteFilter, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteFilterList.
+func (in *HTTPRouteFilterList) DeepCopy() *HTTPRouteFilterList {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPRouteFilterList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *HTTPRouteFilterList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPRouteFilterSpec) DeepCopyInto(out *HTTPRouteFilterSpec) {
+	*out = *in
+	if in.URLRewrite != nil {
+		in, out := &in.URLRewrite, &out.URLRewrite
+		*out = new(HTTPURLRewriteFilter)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPRouteFilterSpec.
+func (in *HTTPRouteFilterSpec) DeepCopy() *HTTPRouteFilterSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPRouteFilterSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HTTPTimeout) DeepCopyInto(out *HTTPTimeout) {
 	*out = *in
@@ -2650,6 +2748,26 @@ func (in *HTTPTimeout) DeepCopy() *HTTPTimeout {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPURLRewriteFilter) DeepCopyInto(out *HTTPURLRewriteFilter) {
+	*out = *in
+	if in.Path != nil {
+		in, out := &in.Path, &out.Path
+		*out = new(HTTPPathModifier)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPURLRewriteFilter.
+func (in *HTTPURLRewriteFilter) DeepCopy() *HTTPURLRewriteFilter {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPURLRewriteFilter)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HTTPWasmCodeSource) DeepCopyInto(out *HTTPWasmCodeSource) {
 	*out = *in
@@ -4476,6 +4594,21 @@ func (in *RemoteJWKS) DeepCopy() *RemoteJWKS {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ReplaceRegexMatch) DeepCopyInto(out *ReplaceRegexMatch) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplaceRegexMatch.
+func (in *ReplaceRegexMatch) DeepCopy() *ReplaceRegexMatch {
+	if in == nil {
+		return nil
+	}
+	out := new(ReplaceRegexMatch)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *RequestHeaderCustomTag) DeepCopyInto(out *RequestHeaderCustomTag) {
 	*out = *in
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml
new file mode 100644
index 000000000..2bba4d20f
--- /dev/null
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml
@@ -0,0 +1,111 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.16.1
+  name: httproutefilters.gateway.envoyproxy.io
+spec:
+  group: gateway.envoyproxy.io
+  names:
+    categories:
+    - envoy-gateway
+    kind: HTTPRouteFilter
+    listKind: HTTPRouteFilterList
+    plural: httproutefilters
+    shortNames:
+    - hrf
+    singular: httproutefilter
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: |-
+          HTTPRouteFilter is a custom Envoy Gateway HTTPRouteFilter which provides extended
+          traffic processing options such as path regex rewrite, direct response and more.
+        properties:
+          apiVersion:
+            description: |-
+              APIVersion defines the versioned schema of this representation of an object.
+              Servers should convert recognized schemas to the latest internal value, and
+              may reject unrecognized values.
+              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
+            type: string
+          kind:
+            description: |-
+              Kind is a string value representing the REST resource this object represents.
+              Servers may infer this from the endpoint the client submits requests to.
+              Cannot be updated.
+              In CamelCase.
+              More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: Spec defines the desired state of HTTPRouteFilter.
+            properties:
+              urlRewrite:
+                description: HTTPURLRewriteFilter define rewrites of HTTP URL components
+                  such as path and host
+                properties:
+                  path:
+                    description: Path defines a path rewrite.
+                    properties:
+                      replaceRegexMatch:
+                        description: |-
+                          ReplaceRegexMatch defines a path regex rewrite. The path portions matched by the regex pattern are replaced by the defined substitution.
+                          https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-regex-rewrite
+                          Some examples:
+                          (1) replaceRegexMatch:
+                                pattern: ^/service/([^/]+)(/.*)$
+                                substitution: \2/instance/\1
+                              Would transform /service/foo/v1/api into /v1/api/instance/foo.
+                          (2) replaceRegexMatch:
+                                pattern: one
+                                substitution: two
+                              Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/two/zzz.
+                          (3) replaceRegexMatch:
+                                pattern: ^(.*?)one(.*)$
+                                substitution: \1two\2
+                              Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/one/zzz.
+                          (3) replaceRegexMatch:
+                                pattern: (?i)/xxx/
+                                substitution: /yyy/
+                              Would transform path /aaa/XxX/bbb into /aaa/yyy/bbb (case-insensitive).
+                        properties:
+                          pattern:
+                            description: |-
+                              Pattern matches a regular expression against the value of the HTTP Path.The regex string must
+                              adhere to the syntax documented in https://github.com/google/re2/wiki/Syntax.
+                            type: string
+                          substitution:
+                            description: |-
+                              Substitution is an expression that replaces the matched portion.The expression may include numbered
+                              capture groups that adhere to syntax documented in https://github.com/google/re2/wiki/Syntax.
+                            type: string
+                        required:
+                        - pattern
+                        - substitution
+                        type: object
+                      type:
+                        description: HTTPPathModifierType defines the type of path
+                          redirect or rewrite.
+                        enum:
+                        - RegexHTTPPathModifier
+                        type: string
+                    required:
+                    - type
+                    type: object
+                type: object
+            type: object
+        required:
+        - spec
+        type: object
+    served: true
+    storage: true
+    subresources: {}
diff --git a/internal/cmd/egctl/status.go b/internal/cmd/egctl/status.go
index a19fdd978..814bd1593 100644
--- a/internal/cmd/egctl/status.go
+++ b/internal/cmd/egctl/status.go
@@ -23,22 +23,22 @@ import (
 	gwapiv1a3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 var (
 	supportedXRouteTypes = []string{
-		gatewayapi.KindHTTPRoute, gatewayapi.KindGRPCRoute, gatewayapi.KindTCPRoute,
-		gatewayapi.KindUDPRoute, gatewayapi.KindTLSRoute,
+		resource.KindHTTPRoute, resource.KindGRPCRoute, resource.KindTCPRoute,
+		resource.KindUDPRoute, resource.KindTLSRoute,
 	}
 
 	supportedXPolicyTypes = []string{
-		gatewayapi.KindBackendTLSPolicy, gatewayapi.KindBackendTrafficPolicy, gatewayapi.KindClientTrafficPolicy,
-		gatewayapi.KindSecurityPolicy, gatewayapi.KindEnvoyPatchPolicy, gatewayapi.KindEnvoyExtensionPolicy,
+		resource.KindBackendTLSPolicy, resource.KindBackendTrafficPolicy, resource.KindClientTrafficPolicy,
+		resource.KindSecurityPolicy, resource.KindEnvoyPatchPolicy, resource.KindEnvoyExtensionPolicy,
 	}
 
 	supportedAllTypes = []string{
-		gatewayapi.KindGatewayClass, gatewayapi.KindGateway,
+		resource.KindGatewayClass, resource.KindGateway,
 	}
 )
 
@@ -156,7 +156,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &gc
-		resourceKind = gatewayapi.KindGatewayClass
+		resourceKind = resource.KindGatewayClass
 
 	case "gtw", "gateway":
 		gtw := gwapiv1.GatewayList{}
@@ -164,7 +164,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &gtw
-		resourceKind = gatewayapi.KindGateway
+		resourceKind = resource.KindGateway
 
 	case "httproute":
 		httproute := gwapiv1.HTTPRouteList{}
@@ -172,7 +172,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &httproute
-		resourceKind = gatewayapi.KindHTTPRoute
+		resourceKind = resource.KindHTTPRoute
 
 	case "grpcroute":
 		grpcroute := gwapiv1.GRPCRouteList{}
@@ -180,7 +180,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &grpcroute
-		resourceKind = gatewayapi.KindGRPCRoute
+		resourceKind = resource.KindGRPCRoute
 
 	case "tcproute":
 		tcproute := gwapiv1a2.TCPRouteList{}
@@ -188,7 +188,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &tcproute
-		resourceKind = gatewayapi.KindTCPRoute
+		resourceKind = resource.KindTCPRoute
 
 	case "udproute":
 		udproute := gwapiv1a2.UDPRouteList{}
@@ -196,7 +196,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &udproute
-		resourceKind = gatewayapi.KindUDPRoute
+		resourceKind = resource.KindUDPRoute
 
 	case "tlsroute":
 		tlsroute := gwapiv1a2.TLSRouteList{}
@@ -204,7 +204,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &tlsroute
-		resourceKind = gatewayapi.KindTLSRoute
+		resourceKind = resource.KindTLSRoute
 
 	case "btlspolicy", "backendtlspolicy":
 		btlspolicy := gwapiv1a3.BackendTLSPolicyList{}
@@ -212,7 +212,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &btlspolicy
-		resourceKind = gatewayapi.KindBackendTLSPolicy
+		resourceKind = resource.KindBackendTLSPolicy
 
 	case "btp", "backendtrafficpolicy":
 		btp := egv1a1.BackendTrafficPolicyList{}
@@ -220,7 +220,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &btp
-		resourceKind = gatewayapi.KindBackendTrafficPolicy
+		resourceKind = resource.KindBackendTrafficPolicy
 
 	case "ctp", "clienttrafficpolicy":
 		ctp := egv1a1.ClientTrafficPolicyList{}
@@ -228,7 +228,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &ctp
-		resourceKind = gatewayapi.KindClientTrafficPolicy
+		resourceKind = resource.KindClientTrafficPolicy
 
 	case "epp", "envoypatchpolicy":
 		epp := egv1a1.EnvoyPatchPolicyList{}
@@ -236,7 +236,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &epp
-		resourceKind = gatewayapi.KindEnvoyPatchPolicy
+		resourceKind = resource.KindEnvoyPatchPolicy
 
 	case "eep", "envoyextensionpolicy":
 		eep := egv1a1.EnvoyExtensionPolicyList{}
@@ -244,7 +244,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &eep
-		resourceKind = gatewayapi.KindEnvoyExtensionPolicy
+		resourceKind = resource.KindEnvoyExtensionPolicy
 
 	case "sp", "securitypolicy":
 		sp := egv1a1.SecurityPolicyList{}
@@ -252,7 +252,7 @@ func runStatus(ctx context.Context, cli client.Client, inputResourceType, namesp
 			return err
 		}
 		resourcesList = &sp
-		resourceKind = gatewayapi.KindSecurityPolicy
+		resourceKind = resource.KindSecurityPolicy
 
 	default:
 		return fmt.Errorf("unknown input resource type: %s, supported input types are: %s",
diff --git a/internal/cmd/egctl/translate.go b/internal/cmd/egctl/translate.go
index 045d4733e..25811d600 100644
--- a/internal/cmd/egctl/translate.go
+++ b/internal/cmd/egctl/translate.go
@@ -11,9 +11,7 @@ import (
 	"fmt"
 	"io"
 	"os"
-	"reflect"
 	"sort"
-	"strings"
 
 	adminv3 "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
 	bootstrapv3 "github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3"
@@ -22,19 +20,12 @@ import (
 	"google.golang.org/protobuf/encoding/protojson"
 	"google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/types/known/anypb"
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/util/sets"
 	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/api/v1alpha1/validation"
-	"github.com/envoyproxy/gateway/internal/envoygateway"
-	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
 	"github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/ratelimit"
 	"github.com/envoyproxy/gateway/internal/xds/bootstrap"
@@ -46,14 +37,12 @@ const (
 	gatewayAPIType = "gateway-api"
 	xdsType        = "xds"
 	irType         = "ir"
-
-	dummyClusterIP = "1.2.3.4"
 )
 
 type TranslationResult struct {
-	gatewayapi.Resources
-	XdsIR   gatewayapi.XdsIRMap    `json:"xdsIR,omitempty" yaml:"xdsIR,omitempty"`
-	InfraIR gatewayapi.InfraIRMap  `json:"infraIR,omitempty" yaml:"infraIR,omitempty"`
+	resource.Resources
+	XdsIR   resource.XdsIRMap      `json:"xdsIR,omitempty" yaml:"xdsIR,omitempty"`
+	InfraIR resource.InfraIRMap    `json:"infraIR,omitempty" yaml:"infraIR,omitempty"`
 	Xds     map[string]interface{} `json:"xds,omitempty"`
 }
 
@@ -235,7 +224,7 @@ func translate(w io.Writer, inFile, inType string, outTypes []string, output, re
 
 	if inType == gatewayAPIType {
 		// Unmarshal input
-		resources, err := kubernetesYAMLToResources(string(inBytes), addMissingResources)
+		resources, err := resource.LoadResourcesFromYAMLString(string(inBytes), addMissingResources)
 		if err != nil {
 			return fmt.Errorf("unable to unmarshal input: %w", err)
 		}
@@ -276,7 +265,7 @@ func translate(w io.Writer, inFile, inType string, outTypes []string, output, re
 	return fmt.Errorf("unable to find translate from input type %s to output type %s", inType, outTypes)
 }
 
-func translateGatewayAPIToIR(resources *gatewayapi.Resources) (*gatewayapi.TranslateResult, error) {
+func translateGatewayAPIToIR(resources *resource.Resources) (*gatewayapi.TranslateResult, error) {
 	if resources.GatewayClass == nil {
 		return nil, fmt.Errorf("the GatewayClass resource is required")
 	}
@@ -303,9 +292,9 @@ func translateGatewayAPIToIR(resources *gatewayapi.Resources) (*gatewayapi.Trans
 	return result, nil
 }
 
-func translateGatewayAPIToGatewayAPI(resources *gatewayapi.Resources) (gatewayapi.Resources, error) {
+func translateGatewayAPIToGatewayAPI(resources *resource.Resources) (resource.Resources, error) {
 	if resources.GatewayClass == nil {
-		return gatewayapi.Resources{}, fmt.Errorf("the GatewayClass resource is required")
+		return resource.Resources{}, fmt.Errorf("the GatewayClass resource is required")
 	}
 
 	// Translate from Gateway API to Xds IR
@@ -341,7 +330,7 @@ func translateGatewayAPIToGatewayAPI(resources *gatewayapi.Resources) (gatewayap
 	return gRes.Resources, nil
 }
 
-func translateGatewayAPIToXds(namespace, dnsDomain string, resourceType string, resources *gatewayapi.Resources) (map[string]any, error) {
+func translateGatewayAPIToXds(namespace, dnsDomain string, resourceType string, resources *resource.Resources) (map[string]any, error) {
 	if resources.GatewayClass == nil {
 		return nil, fmt.Errorf("the GatewayClass resource is required")
 	}
@@ -437,7 +426,7 @@ func printOutput(w io.Writer, result TranslationResult, output string) error {
 }
 
 // constructConfigDump constructs configDump from ResourceVersionTable and BootstrapConfig
-func constructConfigDump(resources *gatewayapi.Resources, tCtx *xds_types.ResourceVersionTable) (*adminv3.ConfigDump, error) {
+func constructConfigDump(resources *resource.Resources, tCtx *xds_types.ResourceVersionTable) (*adminv3.ConfigDump, error) {
 	globalConfigs := &adminv3.ConfigDump{}
 	bootstrapConfigs := &adminv3.BootstrapConfigDump{}
 	proxyBootstrap := &bootstrapv3.Bootstrap{}
@@ -554,427 +543,3 @@ func constructConfigDump(resources *gatewayapi.Resources, tCtx *xds_types.Resour
 
 	return globalConfigs, nil
 }
-
-func addMissingServices(requiredServices map[string]*corev1.Service, obj interface{}) {
-	var objNamespace string
-	protocol := corev1.Protocol(gatewayapi.TCPProtocol)
-
-	refs := []gwapiv1.BackendRef{}
-	switch route := obj.(type) {
-	case *gwapiv1.HTTPRoute:
-		objNamespace = route.Namespace
-		for _, rule := range route.Spec.Rules {
-			for _, httpBakcendRef := range rule.BackendRefs {
-				refs = append(refs, httpBakcendRef.BackendRef)
-			}
-		}
-	case *gwapiv1.GRPCRoute:
-		objNamespace = route.Namespace
-		for _, rule := range route.Spec.Rules {
-			for _, gRPCBakcendRef := range rule.BackendRefs {
-				refs = append(refs, gRPCBakcendRef.BackendRef)
-			}
-		}
-	case *gwapiv1a2.TLSRoute:
-		objNamespace = route.Namespace
-		for _, rule := range route.Spec.Rules {
-			refs = append(refs, rule.BackendRefs...)
-		}
-	case *gwapiv1a2.TCPRoute:
-		objNamespace = route.Namespace
-		for _, rule := range route.Spec.Rules {
-			refs = append(refs, rule.BackendRefs...)
-		}
-	case *gwapiv1a2.UDPRoute:
-		protocol = gatewayapi.UDPProtocol
-		objNamespace = route.Namespace
-		for _, rule := range route.Spec.Rules {
-			refs = append(refs, rule.BackendRefs...)
-		}
-	}
-
-	for _, ref := range refs {
-		if ref.Kind == nil || *ref.Kind != gatewayapi.KindService {
-			continue
-		}
-
-		ns := objNamespace
-		if ref.Namespace != nil {
-			ns = string(*ref.Namespace)
-		}
-		name := string(ref.Name)
-		key := ns + "/" + name
-
-		port := int32(*ref.Port)
-		servicePort := corev1.ServicePort{
-			Name:     fmt.Sprintf("%s-%d", protocol, port),
-			Protocol: protocol,
-			Port:     port,
-		}
-		if service, found := requiredServices[key]; !found {
-			service := &corev1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: ns,
-				},
-				Spec: corev1.ServiceSpec{
-					// Just a dummy IP
-					ClusterIP: dummyClusterIP,
-					Ports:     []corev1.ServicePort{servicePort},
-				},
-			}
-			requiredServices[key] = service
-		} else {
-			inserted := false
-			for _, port := range service.Spec.Ports {
-				if port.Protocol == servicePort.Protocol && port.Port == servicePort.Port {
-					inserted = true
-					break
-				}
-			}
-
-			if !inserted {
-				service.Spec.Ports = append(service.Spec.Ports, servicePort)
-			}
-		}
-	}
-}
-
-// kubernetesYAMLToResources converts a Kubernetes YAML string into GatewayAPI Resources
-func kubernetesYAMLToResources(str string, addMissingResources bool) (*gatewayapi.Resources, error) {
-	resources := gatewayapi.NewResources()
-	var useDefaultNamespace bool
-	providedNamespaceMap := sets.New[string]()
-	requiredNamespaceMap := sets.New[string]()
-	yamls := strings.Split(str, "\n---")
-	combinedScheme := envoygateway.GetScheme()
-	for _, y := range yamls {
-		if strings.TrimSpace(y) == "" {
-			continue
-		}
-		var obj map[string]interface{}
-		err := yaml.Unmarshal([]byte(y), &obj)
-		if err != nil {
-			return nil, err
-		}
-		un := unstructured.Unstructured{Object: obj}
-		gvk := un.GroupVersionKind()
-		name, namespace := un.GetName(), un.GetNamespace()
-		if namespace == "" {
-			// When kubectl applies a resource in yaml which doesn't have a namespace,
-			// the current namespace is applied. Here we do the same thing before translating
-			// the GatewayAPI resource. Otherwise, the resource can't pass the namespace validation
-			useDefaultNamespace = true
-			namespace = config.DefaultNamespace
-		}
-		requiredNamespaceMap.Insert(namespace)
-		kobj, err := combinedScheme.New(gvk)
-		if err != nil {
-			return nil, err
-		}
-		err = combinedScheme.Convert(&un, kobj, nil)
-		if err != nil {
-			return nil, err
-		}
-
-		objType := reflect.TypeOf(kobj)
-		if objType.Kind() != reflect.Ptr {
-			return nil, fmt.Errorf("expected pointer type, but got %s", objType.Kind().String())
-		}
-		kobjVal := reflect.ValueOf(kobj).Elem()
-		spec := kobjVal.FieldByName("Spec")
-
-		switch gvk.Kind {
-		case gatewayapi.KindEnvoyProxy:
-			typedSpec := spec.Interface()
-			envoyProxy := &egv1a1.EnvoyProxy{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(egv1a1.EnvoyProxySpec),
-			}
-			resources.EnvoyProxyForGatewayClass = envoyProxy
-		case gatewayapi.KindGatewayClass:
-			typedSpec := spec.Interface()
-			gatewayClass := &gwapiv1.GatewayClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GatewayClassSpec),
-			}
-			// fill controller name by default controller name when gatewayclass controller name empty.
-			if gatewayClass.Spec.ControllerName == "" {
-				gatewayClass.Spec.ControllerName = egv1a1.GatewayControllerName
-			}
-			resources.GatewayClass = gatewayClass
-		case gatewayapi.KindGateway:
-			typedSpec := spec.Interface()
-			gateway := &gwapiv1.Gateway{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GatewaySpec),
-			}
-			resources.Gateways = append(resources.Gateways, gateway)
-		case gatewayapi.KindTCPRoute:
-			typedSpec := spec.Interface()
-			tcpRoute := &gwapiv1a2.TCPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindTCPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.TCPRouteSpec),
-			}
-			resources.TCPRoutes = append(resources.TCPRoutes, tcpRoute)
-		case gatewayapi.KindUDPRoute:
-			typedSpec := spec.Interface()
-			udpRoute := &gwapiv1a2.UDPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindUDPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.UDPRouteSpec),
-			}
-			resources.UDPRoutes = append(resources.UDPRoutes, udpRoute)
-		case gatewayapi.KindTLSRoute:
-			typedSpec := spec.Interface()
-			tlsRoute := &gwapiv1a2.TLSRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindTLSRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.TLSRouteSpec),
-			}
-			resources.TLSRoutes = append(resources.TLSRoutes, tlsRoute)
-		case gatewayapi.KindHTTPRoute:
-			typedSpec := spec.Interface()
-			httpRoute := &gwapiv1.HTTPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindHTTPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.HTTPRouteSpec),
-			}
-			resources.HTTPRoutes = append(resources.HTTPRoutes, httpRoute)
-		case gatewayapi.KindGRPCRoute:
-			typedSpec := spec.Interface()
-			grpcRoute := &gwapiv1.GRPCRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindGRPCRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GRPCRouteSpec),
-			}
-			resources.GRPCRoutes = append(resources.GRPCRoutes, grpcRoute)
-		case gatewayapi.KindNamespace:
-			namespace := &corev1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: name,
-				},
-			}
-			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap.Insert(name)
-		case gatewayapi.KindService:
-			typedSpec := spec.Interface()
-			service := &corev1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(corev1.ServiceSpec),
-			}
-			if addMissingResources && len(service.Spec.ClusterIP) == 0 {
-				// fill with dummy IP when service clusterIP is empty
-				service.Spec.ClusterIP = dummyClusterIP
-			}
-			resources.Services = append(resources.Services, service)
-		case egv1a1.KindEnvoyPatchPolicy:
-			typedSpec := spec.Interface()
-			envoyPatchPolicy := &egv1a1.EnvoyPatchPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindEnvoyPatchPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec),
-			}
-			resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy)
-		case egv1a1.KindClientTrafficPolicy:
-			typedSpec := spec.Interface()
-			clientTrafficPolicy := &egv1a1.ClientTrafficPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindClientTrafficPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.ClientTrafficPolicySpec),
-			}
-			resources.ClientTrafficPolicies = append(resources.ClientTrafficPolicies, clientTrafficPolicy)
-		case egv1a1.KindBackendTrafficPolicy:
-			typedSpec := spec.Interface()
-			backendTrafficPolicy := &egv1a1.BackendTrafficPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindBackendTrafficPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.BackendTrafficPolicySpec),
-			}
-			resources.BackendTrafficPolicies = append(resources.BackendTrafficPolicies, backendTrafficPolicy)
-		case egv1a1.KindSecurityPolicy:
-			typedSpec := spec.Interface()
-			securityPolicy := &egv1a1.SecurityPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindSecurityPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.SecurityPolicySpec),
-			}
-			resources.SecurityPolicies = append(resources.SecurityPolicies, securityPolicy)
-		}
-	}
-
-	if useDefaultNamespace {
-		if !providedNamespaceMap.Has(config.DefaultNamespace) {
-			namespace := &corev1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: config.DefaultNamespace,
-				},
-			}
-			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap.Insert(config.DefaultNamespace)
-		}
-	}
-
-	if addMissingResources {
-		for ns := range requiredNamespaceMap {
-			if !providedNamespaceMap.Has(ns) {
-				namespace := &corev1.Namespace{
-					ObjectMeta: metav1.ObjectMeta{
-						Name: ns,
-					},
-				}
-				resources.Namespaces = append(resources.Namespaces, namespace)
-			}
-		}
-
-		requiredServiceMap := map[string]*corev1.Service{}
-		for _, route := range resources.TCPRoutes {
-			addMissingServices(requiredServiceMap, route)
-		}
-		for _, route := range resources.UDPRoutes {
-			addMissingServices(requiredServiceMap, route)
-		}
-		for _, route := range resources.TLSRoutes {
-			addMissingServices(requiredServiceMap, route)
-		}
-		for _, route := range resources.HTTPRoutes {
-			addMissingServices(requiredServiceMap, route)
-		}
-		for _, route := range resources.GRPCRoutes {
-			addMissingServices(requiredServiceMap, route)
-		}
-
-		providedServiceMap := map[string]*corev1.Service{}
-		for _, service := range resources.Services {
-			providedServiceMap[service.Namespace+"/"+service.Name] = service
-		}
-
-		for key, service := range requiredServiceMap {
-			if provided, found := providedServiceMap[key]; !found {
-				resources.Services = append(resources.Services, service)
-			} else {
-				providedPorts := sets.NewString()
-				for _, port := range provided.Spec.Ports {
-					portKey := fmt.Sprintf("%s-%d", port.Protocol, port.Port)
-					providedPorts.Insert(portKey)
-				}
-
-				for _, port := range service.Spec.Ports {
-					name := fmt.Sprintf("%s-%d", port.Protocol, port.Port)
-					if !providedPorts.Has(name) {
-						servicePort := corev1.ServicePort{
-							Name:     name,
-							Protocol: port.Protocol,
-							Port:     port.Port,
-						}
-						provided.Spec.Ports = append(provided.Spec.Ports, servicePort)
-					}
-				}
-			}
-		}
-
-		// Add EnvoyProxy if it does not exist
-		if resources.EnvoyProxyForGatewayClass == nil {
-			if err := addDefaultEnvoyProxy(resources); err != nil {
-				return nil, err
-			}
-		}
-	}
-
-	return resources, nil
-}
-
-func addDefaultEnvoyProxy(resources *gatewayapi.Resources) 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
-	}
-	ep := &egv1a1.EnvoyProxy{
-		ObjectMeta: metav1.ObjectMeta{
-			Namespace: namespace,
-			Name:      defaultEnvoyProxyName,
-		},
-		Spec: egv1a1.EnvoyProxySpec{
-			Bootstrap: &egv1a1.ProxyBootstrap{
-				Value: &defaultBootstrapStr,
-			},
-		},
-	}
-	resources.EnvoyProxyForGatewayClass = ep
-	ns := gwapiv1.Namespace(namespace)
-	resources.GatewayClass.Spec.ParametersRef = &gwapiv1.ParametersReference{
-		Group:     gwapiv1.Group(egv1a1.GroupVersion.Group),
-		Kind:      gatewayapi.KindEnvoyProxy,
-		Name:      defaultEnvoyProxyName,
-		Namespace: &ns,
-	}
-	return nil
-}
diff --git a/internal/gatewayapi/address.go b/internal/gatewayapi/address.go
index fea4aeae7..40b5106f4 100644
--- a/internal/gatewayapi/address.go
+++ b/internal/gatewayapi/address.go
@@ -7,15 +7,17 @@ package gatewayapi
 
 import (
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
+
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 var _ AddressesTranslator = (*Translator)(nil)
 
 type AddressesTranslator interface {
-	ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources)
+	ProcessAddresses(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap)
 }
 
-func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) {
+func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap) {
 	for _, gateway := range gateways {
 		// Infra IR already exist
 		irKey := t.getIRKey(gateway.Gateway)
diff --git a/internal/gatewayapi/backendtlspolicy.go b/internal/gatewayapi/backendtlspolicy.go
index 28f77bf82..d58f2789c 100644
--- a/internal/gatewayapi/backendtlspolicy.go
+++ b/internal/gatewayapi/backendtlspolicy.go
@@ -14,11 +14,12 @@ import (
 	gwapiv1a3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
 
 	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/ir"
 )
 
-func (t *Translator) applyBackendTLSSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, parent gwapiv1a2.ParentReference, resources *Resources, envoyProxy *egv1a1.EnvoyProxy) *ir.TLSUpstreamConfig {
+func (t *Translator) applyBackendTLSSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, parent gwapiv1a2.ParentReference, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) *ir.TLSUpstreamConfig {
 	upstreamConfig, policy := t.processBackendTLSPolicy(backendRef, backendNamespace, parent, resources, envoyProxy)
 	return t.applyEnvoyProxyBackendTLSSetting(policy, upstreamConfig, resources, parent, envoyProxy)
 }
@@ -27,7 +28,7 @@ func (t *Translator) processBackendTLSPolicy(
 	backendRef gwapiv1.BackendObjectReference,
 	backendNamespace string,
 	parent gwapiv1a2.ParentReference,
-	resources *Resources,
+	resources *resource.Resources,
 	envoyProxy *egv1a1.EnvoyProxy,
 ) (*ir.TLSUpstreamConfig, *gwapiv1a3.BackendTLSPolicy) {
 	policy := getBackendTLSPolicy(resources.BackendTLSPolicies, backendRef, backendNamespace)
@@ -83,7 +84,7 @@ func (t *Translator) processBackendTLSPolicy(
 	return tlsBundle, policy
 }
 
-func (t *Translator) applyEnvoyProxyBackendTLSSetting(policy *gwapiv1a3.BackendTLSPolicy, tlsConfig *ir.TLSUpstreamConfig, resources *Resources, parent gwapiv1a2.ParentReference, ep *egv1a1.EnvoyProxy) *ir.TLSUpstreamConfig {
+func (t *Translator) applyEnvoyProxyBackendTLSSetting(policy *gwapiv1a3.BackendTLSPolicy, tlsConfig *ir.TLSUpstreamConfig, resources *resource.Resources, parent gwapiv1a2.ParentReference, ep *egv1a1.EnvoyProxy) *ir.TLSUpstreamConfig {
 	if ep == nil || ep.Spec.BackendTLS == nil || tlsConfig == nil {
 		return tlsConfig
 	}
@@ -163,7 +164,7 @@ func getBackendTLSPolicy(policies []*gwapiv1a3.BackendTLSPolicy, backendRef gwap
 	return nil
 }
 
-func getBackendTLSBundle(backendTLSPolicy *gwapiv1a3.BackendTLSPolicy, resources *Resources) (*ir.TLSUpstreamConfig, error) {
+func getBackendTLSBundle(backendTLSPolicy *gwapiv1a3.BackendTLSPolicy, resources *resource.Resources) (*ir.TLSUpstreamConfig, error) {
 	tlsBundle := &ir.TLSUpstreamConfig{
 		SNI:                 string(backendTLSPolicy.Spec.Validation.Hostname),
 		UseSystemTrustStore: ptr.Deref(backendTLSPolicy.Spec.Validation.WellKnownCACertificates, "") == gwapiv1a3.WellKnownCACertificatesSystem,
@@ -177,7 +178,7 @@ func getBackendTLSBundle(backendTLSPolicy *gwapiv1a3.BackendTLSPolicy, resources
 		kind := string(caRef.Kind)
 
 		switch kind {
-		case KindConfigMap:
+		case resource.KindConfigMap:
 			for _, cmap := range resources.ConfigMaps {
 				if cmap.Name == string(caRef.Name) {
 					if crt, dataOk := cmap.Data["ca.crt"]; dataOk {
@@ -190,7 +191,7 @@ func getBackendTLSBundle(backendTLSPolicy *gwapiv1a3.BackendTLSPolicy, resources
 					}
 				}
 			}
-		case KindSecret:
+		case resource.KindSecret:
 			for _, secret := range resources.Secrets {
 				if secret.Name == string(caRef.Name) {
 					if crt, dataOk := secret.Data["ca.crt"]; dataOk {
diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go
index 3fbf5fb25..d71d49f32 100644
--- a/internal/gatewayapi/backendtrafficpolicy.go
+++ b/internal/gatewayapi/backendtrafficpolicy.go
@@ -20,6 +20,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -33,7 +34,7 @@ const (
 func (t *Translator) ProcessBackendTrafficPolicies(backendTrafficPolicies []*egv1a1.BackendTrafficPolicy,
 	gateways []*GatewayContext,
 	routes []RouteContext,
-	xdsIR XdsIRMap,
+	xdsIR resource.XdsIRMap,
 ) []*egv1a1.BackendTrafficPolicy {
 	res := []*egv1a1.BackendTrafficPolicy{}
 
@@ -73,7 +74,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(backendTrafficPolicies []*egv
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind != KindGateway {
+			if currTarget.Kind != resource.KindGateway {
 				policy, found := handledPolicies[policyName]
 				if !found {
 					policy = currPolicy.DeepCopy()
@@ -93,7 +94,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(backendTrafficPolicies []*egv
 				parentRefs := GetParentReferences(route)
 				ancestorRefs := make([]gwapiv1a2.ParentReference, 0, len(parentRefs))
 				for _, p := range parentRefs {
-					if p.Kind == nil || *p.Kind == KindGateway {
+					if p.Kind == nil || *p.Kind == resource.KindGateway {
 						namespace := route.GetNamespace()
 						if p.Namespace != nil {
 							namespace = string(*p.Namespace)
@@ -147,7 +148,7 @@ func (t *Translator) ProcessBackendTrafficPolicies(backendTrafficPolicies []*egv
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind == KindGateway {
+			if currTarget.Kind == resource.KindGateway {
 				policy, found := handledPolicies[policyName]
 				if !found {
 					policy = currPolicy.DeepCopy()
@@ -281,7 +282,7 @@ func resolveBTPolicyRouteTargetRef(policy *egv1a1.BackendTrafficPolicy, target g
 	return route.RouteContext, nil
 }
 
-func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.BackendTrafficPolicy, route RouteContext, xdsIR XdsIRMap) error {
+func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.BackendTrafficPolicy, route RouteContext, xdsIR resource.XdsIRMap) error {
 	var (
 		rl        *ir.RateLimit
 		lb        *ir.LoadBalancer
@@ -418,7 +419,7 @@ func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.Backen
 	return errs
 }
 
-func (t *Translator) translateBackendTrafficPolicyForGateway(policy *egv1a1.BackendTrafficPolicy, target gwapiv1a2.LocalPolicyTargetReferenceWithSectionName, gateway *GatewayContext, xdsIR XdsIRMap) error {
+func (t *Translator) translateBackendTrafficPolicyForGateway(policy *egv1a1.BackendTrafficPolicy, target gwapiv1a2.LocalPolicyTargetReferenceWithSectionName, gateway *GatewayContext, xdsIR resource.XdsIRMap) error {
 	var (
 		rl        *ir.RateLimit
 		lb        *ir.LoadBalancer
diff --git a/internal/gatewayapi/clienttrafficpolicy.go b/internal/gatewayapi/clienttrafficpolicy.go
index 7d4c95e6e..67cd60ad6 100644
--- a/internal/gatewayapi/clienttrafficpolicy.go
+++ b/internal/gatewayapi/clienttrafficpolicy.go
@@ -22,6 +22,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -37,10 +38,10 @@ func hasSectionName(target *gwapiv1a2.LocalPolicyTargetReferenceWithSectionName)
 }
 
 func (t *Translator) ProcessClientTrafficPolicies(
-	resources *Resources,
+	resources *resource.Resources,
 	gateways []*GatewayContext,
-	xdsIR XdsIRMap,
-	infraIR InfraIRMap,
+	xdsIR resource.XdsIRMap,
+	infraIR resource.InfraIRMap,
 ) []*egv1a1.ClientTrafficPolicy {
 	var res []*egv1a1.ClientTrafficPolicy
 
@@ -366,7 +367,7 @@ func validatePortOverlapForClientTrafficPolicy(l *ListenerContext, xds *ir.Xds,
 }
 
 func (t *Translator) translateClientTrafficPolicyForListener(policy *egv1a1.ClientTrafficPolicy, l *ListenerContext,
-	xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources,
+	xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources,
 ) error {
 	// Find IR
 	irKey := t.getIRKey(l.gateway.Gateway)
@@ -758,7 +759,7 @@ func translateHealthCheckSettings(healthCheckSettings *egv1a1.HealthCheckSetting
 }
 
 func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPolicy,
-	irTLSConfig *ir.TLSConfig, resources *Resources,
+	irTLSConfig *ir.TLSConfig, resources *resource.Resources,
 ) (*ir.TLSConfig, error) {
 	// Return if this listener isn't a TLS listener. There has to be
 	// at least one certificate defined, which would cause httpIR/tcpIR to
@@ -805,7 +806,7 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
 	if tlsParams.ClientValidation != nil {
 		from := crossNamespaceFrom{
 			group:     egv1a1.GroupName,
-			kind:      KindClientTrafficPolicy,
+			kind:      resource.KindClientTrafficPolicy,
 			namespace: policy.Namespace,
 		}
 
@@ -814,7 +815,7 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
 		}
 
 		for _, caCertRef := range tlsParams.ClientValidation.CACertificateRefs {
-			if caCertRef.Kind == nil || string(*caCertRef.Kind) == KindSecret { // nolint
+			if caCertRef.Kind == nil || string(*caCertRef.Kind) == resource.KindSecret { // nolint
 				secret, err := t.validateSecretRef(false, from, caCertRef, resources)
 				if err != nil {
 					return irTLSConfig, err
@@ -833,7 +834,7 @@ func (t *Translator) buildListenerTLSParameters(policy *egv1a1.ClientTrafficPoli
 
 				irCACert.Certificate = append(irCACert.Certificate, secretBytes...)
 
-			} else if string(*caCertRef.Kind) == KindConfigMap {
+			} else if string(*caCertRef.Kind) == resource.KindConfigMap {
 				configMap, err := t.validateConfigMapRef(false, from, caCertRef, resources)
 				if err != nil {
 					return irTLSConfig, err
diff --git a/internal/gatewayapi/contexts.go b/internal/gatewayapi/contexts.go
index 6ecb2cf73..7d6aee73d 100644
--- a/internal/gatewayapi/contexts.go
+++ b/internal/gatewayapi/contexts.go
@@ -16,6 +16,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 // GatewayContext wraps a Gateway and provides helper methods for
@@ -29,7 +30,7 @@ type GatewayContext struct {
 
 // ResetListeners resets the listener statuses and re-generates the GatewayContext
 // ListenerContexts from the Gateway spec.
-func (g *GatewayContext) ResetListeners(resource *Resources) {
+func (g *GatewayContext) ResetListeners(resource *resource.Resources) {
 	numListeners := len(g.Spec.Listeners)
 	g.Status.Listeners = make([]gwapiv1.ListenerStatus, numListeners)
 	g.listeners = make([]*ListenerContext, numListeners)
@@ -46,7 +47,7 @@ func (g *GatewayContext) ResetListeners(resource *Resources) {
 	g.attachEnvoyProxy(resource)
 }
 
-func (g *GatewayContext) attachEnvoyProxy(resources *Resources) {
+func (g *GatewayContext) attachEnvoyProxy(resources *resource.Resources) {
 	if g.Spec.Infrastructure != nil && g.Spec.Infrastructure.ParametersRef != nil && !IsMergeGatewaysEnabled(resources) {
 		ref := g.Spec.Infrastructure.ParametersRef
 		if string(ref.Group) == egv1a1.GroupVersion.Group && ref.Kind == egv1a1.KindEnvoyProxy {
@@ -210,7 +211,7 @@ func GetRouteType(route RouteContext) gwapiv1.Kind {
 func GetHostnames(route RouteContext) []string {
 	rv := reflect.ValueOf(route).Elem()
 	kind := rv.FieldByName("Kind").String()
-	if kind == KindTCPRoute || kind == KindUDPRoute {
+	if kind == resource.KindTCPRoute || kind == resource.KindUDPRoute {
 		return nil
 	}
 
diff --git a/internal/gatewayapi/envoyextensionpolicy.go b/internal/gatewayapi/envoyextensionpolicy.go
index f8c06ed0c..473945875 100644
--- a/internal/gatewayapi/envoyextensionpolicy.go
+++ b/internal/gatewayapi/envoyextensionpolicy.go
@@ -23,6 +23,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -35,8 +36,8 @@ const ociURLPrefix = "oci://"
 func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv1a1.EnvoyExtensionPolicy,
 	gateways []*GatewayContext,
 	routes []RouteContext,
-	resources *Resources,
-	xdsIR XdsIRMap,
+	resources *resource.Resources,
+	xdsIR resource.XdsIRMap,
 ) []*egv1a1.EnvoyExtensionPolicy {
 	var res []*egv1a1.EnvoyExtensionPolicy
 
@@ -76,7 +77,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind != KindGateway {
+			if currTarget.Kind != resource.KindGateway {
 				policy, found := handledPolicies[policyName]
 				if !found {
 					policy = currPolicy.DeepCopy()
@@ -96,7 +97,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv
 				parentRefs := GetParentReferences(route)
 				ancestorRefs := make([]gwapiv1a2.ParentReference, 0, len(parentRefs))
 				for _, p := range parentRefs {
-					if p.Kind == nil || *p.Kind == KindGateway {
+					if p.Kind == nil || *p.Kind == resource.KindGateway {
 						namespace := route.GetNamespace()
 						if p.Namespace != nil {
 							namespace = string(*p.Namespace)
@@ -150,7 +151,7 @@ func (t *Translator) ProcessEnvoyExtensionPolicies(envoyExtensionPolicies []*egv
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind == KindGateway {
+			if currTarget.Kind == resource.KindGateway {
 				policy, found := handledPolicies[policyName]
 				if !found {
 					policy = currPolicy.DeepCopy()
@@ -287,8 +288,8 @@ func resolveEEPolicyRouteTargetRef(policy *egv1a1.EnvoyExtensionPolicy, target g
 func (t *Translator) translateEnvoyExtensionPolicyForRoute(
 	policy *egv1a1.EnvoyExtensionPolicy,
 	route RouteContext,
-	xdsIR XdsIRMap,
-	resources *Resources,
+	xdsIR resource.XdsIRMap,
+	resources *resource.Resources,
 ) error {
 	var (
 		wasms     []ir.Wasm
@@ -345,8 +346,8 @@ func (t *Translator) translateEnvoyExtensionPolicyForGateway(
 	policy *egv1a1.EnvoyExtensionPolicy,
 	target gwapiv1a2.LocalPolicyTargetReferenceWithSectionName,
 	gateway *GatewayContext,
-	xdsIR XdsIRMap,
-	resources *Resources,
+	xdsIR resource.XdsIRMap,
+	resources *resource.Resources,
 ) error {
 	var (
 		extProcs  []ir.ExtProc
@@ -401,7 +402,7 @@ func (t *Translator) translateEnvoyExtensionPolicyForGateway(
 	return errs
 }
 
-func (t *Translator) buildExtProcs(policy *egv1a1.EnvoyExtensionPolicy, resources *Resources, envoyProxy *egv1a1.EnvoyProxy) ([]ir.ExtProc, error) {
+func (t *Translator) buildExtProcs(policy *egv1a1.EnvoyExtensionPolicy, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) ([]ir.ExtProc, error) {
 	var extProcIRList []ir.ExtProc
 
 	if policy == nil {
@@ -424,7 +425,7 @@ func (t *Translator) buildExtProc(
 	policyNamespacedName types.NamespacedName,
 	extProc egv1a1.ExtProc,
 	extProcIdx int,
-	resources *Resources,
+	resources *resource.Resources,
 	envoyProxy *egv1a1.EnvoyProxy,
 ) (*ir.ExtProc, error) {
 	var (
@@ -528,7 +529,7 @@ func irConfigNameForExtProc(policy *egv1a1.EnvoyExtensionPolicy, index int) stri
 
 func (t *Translator) buildWasms(
 	policy *egv1a1.EnvoyExtensionPolicy,
-	resources *Resources,
+	resources *resource.Resources,
 ) ([]ir.Wasm, error) {
 	if t.WasmCache == nil {
 		return nil, fmt.Errorf("wasm cache is not initialized")
@@ -556,7 +557,7 @@ func (t *Translator) buildWasm(
 	config egv1a1.Wasm,
 	policy *egv1a1.EnvoyExtensionPolicy,
 	idx int,
-	resources *Resources,
+	resources *resource.Resources,
 ) (*ir.Wasm, error) {
 	var (
 		failOpen   = false
@@ -630,7 +631,7 @@ func (t *Translator) buildWasm(
 		if image.PullSecretRef != nil {
 			from := crossNamespaceFrom{
 				group:     egv1a1.GroupName,
-				kind:      KindEnvoyExtensionPolicy,
+				kind:      resource.KindEnvoyExtensionPolicy,
 				namespace: policy.Namespace,
 			}
 
diff --git a/internal/gatewayapi/envoypatchpolicy.go b/internal/gatewayapi/envoypatchpolicy.go
index c2dd54803..599108012 100644
--- a/internal/gatewayapi/envoypatchpolicy.go
+++ b/internal/gatewayapi/envoypatchpolicy.go
@@ -14,11 +14,12 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 )
 
-func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.EnvoyPatchPolicy, xdsIR XdsIRMap) {
+func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.EnvoyPatchPolicy, xdsIR resource.XdsIRMap) {
 	// Sort based on priority
 	sort.Slice(envoyPatchPolicies, func(i, j int) bool {
 		return envoyPatchPolicies[i].Spec.Priority < envoyPatchPolicies[j].Spec.Priority
@@ -34,7 +35,7 @@ func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.Envo
 		)
 
 		if t.MergeGateways {
-			targetKind = KindGatewayClass
+			targetKind = resource.KindGatewayClass
 			irKey = string(t.GatewayClassName)
 
 			ancestorRefs = []gwapiv1a2.ParentReference{
@@ -45,7 +46,7 @@ func (t *Translator) ProcessEnvoyPatchPolicies(envoyPatchPolicies []*egv1a1.Envo
 				},
 			}
 		} else {
-			targetKind = KindGateway
+			targetKind = resource.KindGateway
 			gatewayNN := types.NamespacedName{
 				Namespace: policy.Namespace,
 				Name:      string(policy.Spec.TargetRef.Name),
diff --git a/internal/gatewayapi/ext_service.go b/internal/gatewayapi/ext_service.go
index aa38008ab..7e13b1010 100644
--- a/internal/gatewayapi/ext_service.go
+++ b/internal/gatewayapi/ext_service.go
@@ -16,6 +16,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/ir"
 )
 
@@ -25,7 +26,7 @@ func (t *Translator) processExtServiceDestination(
 	policyNamespacedName types.NamespacedName,
 	policyKind string,
 	protocol ir.AppProtocol,
-	resources *Resources,
+	resources *resource.Resources,
 	envoyProxy *egv1a1.EnvoyProxy,
 ) (*ir.DestinationSetting, error) {
 	var (
@@ -35,8 +36,8 @@ func (t *Translator) processExtServiceDestination(
 
 	backendNamespace := NamespaceDerefOr(backendRef.Namespace, policyNamespacedName.Namespace)
 
-	switch KindDerefOr(backendRef.Kind, KindService) {
-	case KindService:
+	switch KindDerefOr(backendRef.Kind, resource.KindService) {
+	case resource.KindService:
 		ds = t.processServiceDestinationSetting(backendRef.BackendObjectReference, backendNamespace, protocol, resources, envoyProxy)
 	case egv1a1.KindBackend:
 		if !t.BackendEnabled {
diff --git a/internal/gatewayapi/extensionserverpolicy.go b/internal/gatewayapi/extensionserverpolicy.go
index 3843eb503..395a30ef3 100644
--- a/internal/gatewayapi/extensionserverpolicy.go
+++ b/internal/gatewayapi/extensionserverpolicy.go
@@ -17,6 +17,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -24,7 +25,7 @@ import (
 
 func (t *Translator) ProcessExtensionServerPolicies(policies []unstructured.Unstructured,
 	gateways []*GatewayContext,
-	xdsIR XdsIRMap,
+	xdsIR resource.XdsIRMap,
 ) ([]unstructured.Unstructured, error) {
 	res := []unstructured.Unstructured{}
 
@@ -55,7 +56,7 @@ func (t *Translator) ProcessExtensionServerPolicies(policies []unstructured.Unst
 			continue
 		}
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind != KindGateway {
+			if currTarget.Kind != resource.KindGateway {
 				errs = errors.Join(errs, fmt.Errorf("extension policy %s doesn't target a Gateway", policy.GetName()))
 				continue
 			}
@@ -137,7 +138,7 @@ func (t *Translator) translateExtServerPolicyForGateway(
 	policy *unstructured.Unstructured,
 	gateway *GatewayContext,
 	target gwapiv1a2.LocalPolicyTargetReferenceWithSectionName,
-	xdsIR XdsIRMap,
+	xdsIR resource.XdsIRMap,
 ) bool {
 	irKey := t.getIRKey(gateway.Gateway)
 	gwIR := xdsIR[irKey]
diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go
index aecc2e811..de6be3528 100644
--- a/internal/gatewayapi/filters.go
+++ b/internal/gatewayapi/filters.go
@@ -12,6 +12,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
 	"github.com/envoyproxy/gateway/internal/ir"
 )
@@ -27,8 +28,8 @@ type HTTPFiltersTranslator interface {
 	processRedirectFilter(redirect *gwapiv1.HTTPRequestRedirectFilter, filterContext *HTTPFiltersContext)
 	processRequestHeaderModifierFilter(headerModifier *gwapiv1.HTTPHeaderFilter, filterContext *HTTPFiltersContext)
 	processResponseHeaderModifierFilter(headerModifier *gwapiv1.HTTPHeaderFilter, filterContext *HTTPFiltersContext)
-	processRequestMirrorFilter(filterIdx int, mirror *gwapiv1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *Resources)
-	processExtensionRefHTTPFilter(extRef *gwapiv1.LocalObjectReference, filterContext *HTTPFiltersContext, resources *Resources)
+	processRequestMirrorFilter(filterIdx int, mirror *gwapiv1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *resource.Resources)
+	processExtensionRefHTTPFilter(extRef *gwapiv1.LocalObjectReference, filterContext *HTTPFiltersContext, resources *resource.Resources)
 	processUnsupportedHTTPFilter(filterType string, filterContext *HTTPFiltersContext)
 }
 
@@ -64,7 +65,7 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
 	route RouteContext,
 	filters []gwapiv1.HTTPRouteFilter,
 	ruleIdx int,
-	resources *Resources,
+	resources *resource.Resources,
 ) *HTTPFiltersContext {
 	httpFiltersContext := &HTTPFiltersContext{
 		ParentRef:    parentRef,
@@ -108,7 +109,7 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext,
 func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext,
 	route RouteContext,
 	filters []gwapiv1.GRPCRouteFilter,
-	resources *Resources,
+	resources *resource.Resources,
 ) *HTTPFiltersContext {
 	httpFiltersContext := &HTTPFiltersContext{
 		ParentRef: parentRef,
@@ -730,7 +731,7 @@ func (t *Translator) processResponseHeaderModifierFilter(
 	}
 }
 
-func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjectReference, filterContext *HTTPFiltersContext, resources *Resources) {
+func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjectReference, filterContext *HTTPFiltersContext, resources *resource.Resources) {
 	// Make sure the config actually exists.
 	if extFilter == nil {
 		return
@@ -752,9 +753,9 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec
 			}
 			group := apiVers[:idx]
 			if group == string(extFilter.Group) {
-				resource := res // Capture loop variable
+				res := res // Capture loop variable
 				filterContext.ExtensionRefs = append(filterContext.ExtensionRefs, &ir.UnstructuredRef{
-					Object: &resource,
+					Object: &res,
 				})
 				return
 			}
@@ -771,7 +772,7 @@ func (t *Translator) processRequestMirrorFilter(
 	filterIdx int,
 	mirrorFilter *gwapiv1.HTTPRequestMirrorFilter,
 	filterContext *HTTPFiltersContext,
-	resources *Resources,
+	resources *resource.Resources,
 ) {
 	// Make sure the config actually exists
 	if mirrorFilter == nil {
@@ -793,7 +794,7 @@ func (t *Translator) processRequestMirrorFilter(
 	filterNs := filterContext.Route.GetNamespace()
 	serviceNamespace := NamespaceDerefOr(mirrorBackend.Namespace, filterNs)
 	if !t.validateBackendRef(mirrorBackendRef, filterContext.ParentRef, filterContext.Route,
-		resources, serviceNamespace, KindHTTPRoute) {
+		resources, serviceNamespace, resource.KindHTTPRoute) {
 		return
 	}
 
diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go
index 52df40f47..885077f5c 100644
--- a/internal/gatewayapi/helpers.go
+++ b/internal/gatewayapi/helpers.go
@@ -24,6 +24,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
 )
@@ -114,7 +115,7 @@ func IsRefToGateway(routeNamespace gwapiv1.Namespace, parentRef gwapiv1.ParentRe
 		return false
 	}
 
-	if parentRef.Kind != nil && string(*parentRef.Kind) != KindGateway {
+	if parentRef.Kind != nil && string(*parentRef.Kind) != resource.KindGateway {
 		return false
 	}
 
@@ -442,7 +443,7 @@ func irTLSCACertName(namespace, name string) string {
 	return fmt.Sprintf("%s/%s/%s", namespace, name, caCertKey)
 }
 
-func IsMergeGatewaysEnabled(resources *Resources) bool {
+func IsMergeGatewaysEnabled(resources *resource.Resources) bool {
 	return resources.EnvoyProxyForGatewayClass != nil && resources.EnvoyProxyForGatewayClass.Spec.MergeGateways != nil && *resources.EnvoyProxyForGatewayClass.Spec.MergeGateways
 }
 
@@ -458,7 +459,7 @@ func protocolSliceToStringSlice(protocols []gwapiv1.ProtocolType) []string {
 func getAncestorRefForPolicy(gatewayNN types.NamespacedName, sectionName *gwapiv1a2.SectionName) gwapiv1a2.ParentReference {
 	return gwapiv1a2.ParentReference{
 		Group:       GroupPtr(gwapiv1.GroupName),
-		Kind:        KindPtr(KindGateway),
+		Kind:        KindPtr(resource.KindGateway),
 		Namespace:   NamespacePtr(gatewayNN.Namespace),
 		Name:        gwapiv1.ObjectName(gatewayNN.Name),
 		SectionName: sectionName,
diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go
index b63645a85..88667b8ef 100644
--- a/internal/gatewayapi/listener.go
+++ b/internal/gatewayapi/listener.go
@@ -17,6 +17,7 @@ import (
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -26,10 +27,10 @@ import (
 var _ ListenersTranslator = (*Translator)(nil)
 
 type ListenersTranslator interface {
-	ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources)
+	ProcessListeners(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources)
 }
 
-func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) {
+func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources) {
 	// Infra IR proxy ports must be unique.
 	foundPorts := make(map[string][]*protocolPort)
 	t.validateConflictedLayer7Listeners(gateways)
@@ -57,21 +58,21 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
 				if listener.TLS != nil {
 					switch *listener.TLS.Mode {
 					case gwapiv1.TLSModePassthrough:
-						t.validateAllowedRoutes(listener, KindTLSRoute)
+						t.validateAllowedRoutes(listener, resource.KindTLSRoute)
 					case gwapiv1.TLSModeTerminate:
-						t.validateAllowedRoutes(listener, KindTCPRoute)
+						t.validateAllowedRoutes(listener, resource.KindTCPRoute)
 					default:
-						t.validateAllowedRoutes(listener, KindTCPRoute, KindTLSRoute)
+						t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute)
 					}
 				} else {
-					t.validateAllowedRoutes(listener, KindTCPRoute, KindTLSRoute)
+					t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute)
 				}
 			case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType:
-				t.validateAllowedRoutes(listener, KindHTTPRoute, KindGRPCRoute)
+				t.validateAllowedRoutes(listener, resource.KindHTTPRoute, resource.KindGRPCRoute)
 			case gwapiv1.TCPProtocolType:
-				t.validateAllowedRoutes(listener, KindTCPRoute)
+				t.validateAllowedRoutes(listener, resource.KindTCPRoute)
 			case gwapiv1.UDPProtocolType:
-				t.validateAllowedRoutes(listener, KindUDPRoute)
+				t.validateAllowedRoutes(listener, resource.KindUDPRoute)
 			default:
 				status.SetGatewayListenerStatusCondition(listener.gateway.Gateway,
 					listener.listenerStatusIdx,
@@ -170,7 +171,7 @@ func buildListenerMetadata(listener *ListenerContext, gateway *GatewayContext) *
 	}
 }
 
-func (t *Translator) processProxyObservability(gwCtx *GatewayContext, xdsIR *ir.Xds, envoyProxy *egv1a1.EnvoyProxy, resources *Resources) {
+func (t *Translator) processProxyObservability(gwCtx *GatewayContext, xdsIR *ir.Xds, envoyProxy *egv1a1.EnvoyProxy, resources *resource.Resources) {
 	var err error
 
 	xdsIR.AccessLog, err = t.processAccessLog(envoyProxy, resources)
@@ -195,7 +196,7 @@ func (t *Translator) processProxyObservability(gwCtx *GatewayContext, xdsIR *ir.
 	}
 }
 
-func (t *Translator) processInfraIRListener(listener *ListenerContext, infraIR InfraIRMap, irKey string, servicePort *protocolPort, containerPort int32) {
+func (t *Translator) processInfraIRListener(listener *ListenerContext, infraIR resource.InfraIRMap, irKey string, servicePort *protocolPort, containerPort int32) {
 	var proto ir.ProtocolType
 	switch listener.Protocol {
 	case gwapiv1.HTTPProtocolType:
@@ -225,7 +226,7 @@ func (t *Translator) processInfraIRListener(listener *ListenerContext, infraIR I
 	infraIR[irKey].Proxy.Listeners = append(infraIR[irKey].Proxy.Listeners, proxyListener)
 }
 
-func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources *Resources) (*ir.AccessLog, error) {
+func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources *resource.Resources) (*ir.AccessLog, error) {
 	if envoyproxy == nil ||
 		envoyproxy.Spec.Telemetry == nil ||
 		envoyproxy.Spec.Telemetry.AccessLog == nil ||
@@ -393,7 +394,7 @@ func (t *Translator) processAccessLog(envoyproxy *egv1a1.EnvoyProxy, resources *
 	return irAccessLog, nil
 }
 
-func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.EnvoyProxy, mergeGateways bool, resources *Resources) (*ir.Tracing, error) {
+func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.EnvoyProxy, mergeGateways bool, resources *resource.Resources) (*ir.Tracing, error) {
 	if envoyproxy == nil ||
 		envoyproxy.Spec.Telemetry == nil ||
 		envoyproxy.Spec.Telemetry.Tracing == nil {
@@ -445,7 +446,7 @@ func (t *Translator) processTracing(gw *gwapiv1.Gateway, envoyproxy *egv1a1.Envo
 	}, nil
 }
 
-func (t *Translator) processMetrics(envoyproxy *egv1a1.EnvoyProxy, resources *Resources) (*ir.Metrics, error) {
+func (t *Translator) processMetrics(envoyproxy *egv1a1.EnvoyProxy, resources *resource.Resources) (*ir.Metrics, error) {
 	if envoyproxy == nil ||
 		envoyproxy.Spec.Telemetry == nil ||
 		envoyproxy.Spec.Telemetry.Metrics == nil {
@@ -469,7 +470,7 @@ func (t *Translator) processMetrics(envoyproxy *egv1a1.EnvoyProxy, resources *Re
 	}, nil
 }
 
-func (t *Translator) processBackendRefs(backendCluster egv1a1.BackendCluster, namespace string, resources *Resources, envoyProxy *egv1a1.EnvoyProxy) ([]*ir.DestinationSetting, *ir.TrafficFeatures, error) {
+func (t *Translator) processBackendRefs(backendCluster egv1a1.BackendCluster, namespace string, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) ([]*ir.DestinationSetting, *ir.TrafficFeatures, error) {
 	traffic, err := translateTrafficFeatures(backendCluster.BackendSettings)
 	if err != nil {
 		return nil, nil, err
@@ -477,8 +478,8 @@ func (t *Translator) processBackendRefs(backendCluster egv1a1.BackendCluster, na
 	result := make([]*ir.DestinationSetting, 0, len(backendCluster.BackendRefs))
 	for _, ref := range backendCluster.BackendRefs {
 		ns := NamespaceDerefOr(ref.Namespace, namespace)
-		kind := KindDerefOr(ref.Kind, KindService)
-		if kind != KindService {
+		kind := KindDerefOr(ref.Kind, resource.KindService)
+		if kind != resource.KindService {
 			return nil, nil, errors.New("only service kind is supported for backendRefs")
 		}
 		if err := validateBackendService(ref.BackendObjectReference, resources, ns, corev1.ProtocolTCP); err != nil {
diff --git a/internal/gatewayapi/resource/load.go b/internal/gatewayapi/resource/load.go
new file mode 100644
index 000000000..cacc3ebe6
--- /dev/null
+++ b/internal/gatewayapi/resource/load.go
@@ -0,0 +1,468 @@
+// 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 resource
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/util/sets"
+	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/envoygateway"
+	"github.com/envoyproxy/gateway/internal/envoygateway/config"
+	"github.com/envoyproxy/gateway/internal/xds/bootstrap"
+)
+
+const dummyClusterIP = "1.2.3.4"
+
+// LoadResourcesFromYAMLString will load Resources from given Kubernetes YAML string.
+// TODO: This function should be able to process arbitrary number of resources,
+//
+//	tracked by https://github.com/envoyproxy/gateway/issues/3207
+func LoadResourcesFromYAMLString(yamlStr string, addMissingResources bool) (*Resources, error) {
+	// TODO(sh2): Add local validations
+	r, err := kubernetesYAMLToResources(yamlStr, addMissingResources)
+	if err != nil {
+		return nil, err
+	}
+
+	return r, nil
+}
+
+// kubernetesYAMLToResources converts a Kubernetes YAML string into GatewayAPI Resources.
+func kubernetesYAMLToResources(str string, addMissingResources bool) (*Resources, error) {
+	resources := NewResources()
+	var useDefaultNamespace bool
+	providedNamespaceMap := sets.New[string]()
+	requiredNamespaceMap := sets.New[string]()
+	yamls := strings.Split(str, "\n---")
+	combinedScheme := envoygateway.GetScheme()
+	for _, y := range yamls {
+		if strings.TrimSpace(y) == "" {
+			continue
+		}
+		var obj map[string]interface{}
+		err := yaml.Unmarshal([]byte(y), &obj)
+		if err != nil {
+			return nil, err
+		}
+
+		un := unstructured.Unstructured{Object: obj}
+		gvk := un.GroupVersionKind()
+		name, namespace := un.GetName(), un.GetNamespace()
+		if namespace == "" {
+			// When kubectl applies a resource in yaml which doesn't have a namespace,
+			// the current namespace is applied. Here we do the same thing before translating
+			// the GatewayAPI resource. Otherwise, the resource can't pass the namespace validation
+			useDefaultNamespace = true
+			namespace = config.DefaultNamespace
+		}
+
+		requiredNamespaceMap.Insert(namespace)
+		kobj, err := combinedScheme.New(gvk)
+		if err != nil {
+			return nil, err
+		}
+		err = combinedScheme.Convert(&un, kobj, nil)
+		if err != nil {
+			return nil, err
+		}
+
+		objType := reflect.TypeOf(kobj)
+		if objType.Kind() != reflect.Ptr {
+			return nil, fmt.Errorf("expected pointer type, but got %s", objType.Kind().String())
+		}
+		kobjVal := reflect.ValueOf(kobj).Elem()
+		spec := kobjVal.FieldByName("Spec")
+
+		switch gvk.Kind {
+		case KindEnvoyProxy:
+			typedSpec := spec.Interface()
+			envoyProxy := &egv1a1.EnvoyProxy{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(egv1a1.EnvoyProxySpec),
+			}
+			// TODO: only support loading one envoyproxy for now.
+			resources.EnvoyProxyForGatewayClass = envoyProxy
+		case KindGatewayClass:
+			typedSpec := spec.Interface()
+			gatewayClass := &gwapiv1.GatewayClass{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1.GatewayClassSpec),
+			}
+			// fill controller name by default controller name when gatewayclass controller name empty.
+			if addMissingResources && len(gatewayClass.Spec.ControllerName) == 0 {
+				gatewayClass.Spec.ControllerName = egv1a1.GatewayControllerName
+			}
+			resources.GatewayClass = gatewayClass
+		case KindGateway:
+			typedSpec := spec.Interface()
+			gateway := &gwapiv1.Gateway{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1.GatewaySpec),
+			}
+			resources.Gateways = append(resources.Gateways, gateway)
+		case KindTCPRoute:
+			typedSpec := spec.Interface()
+			tcpRoute := &gwapiv1a2.TCPRoute{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindTCPRoute,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1a2.TCPRouteSpec),
+			}
+			resources.TCPRoutes = append(resources.TCPRoutes, tcpRoute)
+		case KindUDPRoute:
+			typedSpec := spec.Interface()
+			udpRoute := &gwapiv1a2.UDPRoute{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindUDPRoute,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1a2.UDPRouteSpec),
+			}
+			resources.UDPRoutes = append(resources.UDPRoutes, udpRoute)
+		case KindTLSRoute:
+			typedSpec := spec.Interface()
+			tlsRoute := &gwapiv1a2.TLSRoute{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindTLSRoute,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1a2.TLSRouteSpec),
+			}
+			resources.TLSRoutes = append(resources.TLSRoutes, tlsRoute)
+		case KindHTTPRoute:
+			typedSpec := spec.Interface()
+			httpRoute := &gwapiv1.HTTPRoute{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindHTTPRoute,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1.HTTPRouteSpec),
+			}
+			resources.HTTPRoutes = append(resources.HTTPRoutes, httpRoute)
+		case KindGRPCRoute:
+			typedSpec := spec.Interface()
+			grpcRoute := &gwapiv1.GRPCRoute{
+				TypeMeta: metav1.TypeMeta{
+					Kind: KindGRPCRoute,
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(gwapiv1.GRPCRouteSpec),
+			}
+			resources.GRPCRoutes = append(resources.GRPCRoutes, grpcRoute)
+		case KindNamespace:
+			namespace := &corev1.Namespace{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: name,
+				},
+			}
+			resources.Namespaces = append(resources.Namespaces, namespace)
+			providedNamespaceMap.Insert(name)
+		case KindService:
+			typedSpec := spec.Interface()
+			service := &corev1.Service{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: namespace,
+				},
+				Spec: typedSpec.(corev1.ServiceSpec),
+			}
+			if addMissingResources && len(service.Spec.ClusterIP) == 0 {
+				// fill with dummy IP when service clusterIP is empty
+				service.Spec.ClusterIP = dummyClusterIP
+			}
+			resources.Services = append(resources.Services, service)
+		case KindEnvoyPatchPolicy:
+			typedSpec := spec.Interface()
+			envoyPatchPolicy := &egv1a1.EnvoyPatchPolicy{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       egv1a1.KindEnvoyPatchPolicy,
+					APIVersion: egv1a1.GroupVersion.String(),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      name,
+				},
+				Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec),
+			}
+			resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy)
+		case KindClientTrafficPolicy:
+			typedSpec := spec.Interface()
+			clientTrafficPolicy := &egv1a1.ClientTrafficPolicy{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       KindClientTrafficPolicy,
+					APIVersion: egv1a1.GroupVersion.String(),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      name,
+				},
+				Spec: typedSpec.(egv1a1.ClientTrafficPolicySpec),
+			}
+			resources.ClientTrafficPolicies = append(resources.ClientTrafficPolicies, clientTrafficPolicy)
+		case KindBackendTrafficPolicy:
+			typedSpec := spec.Interface()
+			backendTrafficPolicy := &egv1a1.BackendTrafficPolicy{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       KindBackendTrafficPolicy,
+					APIVersion: egv1a1.GroupVersion.String(),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      name,
+				},
+				Spec: typedSpec.(egv1a1.BackendTrafficPolicySpec),
+			}
+			resources.BackendTrafficPolicies = append(resources.BackendTrafficPolicies, backendTrafficPolicy)
+		case KindSecurityPolicy:
+			typedSpec := spec.Interface()
+			securityPolicy := &egv1a1.SecurityPolicy{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       KindSecurityPolicy,
+					APIVersion: egv1a1.GroupVersion.String(),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Namespace: namespace,
+					Name:      name,
+				},
+				Spec: typedSpec.(egv1a1.SecurityPolicySpec),
+			}
+			resources.SecurityPolicies = append(resources.SecurityPolicies, securityPolicy)
+		}
+	}
+
+	if useDefaultNamespace {
+		if !providedNamespaceMap.Has(config.DefaultNamespace) {
+			namespace := &corev1.Namespace{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: config.DefaultNamespace,
+				},
+			}
+			resources.Namespaces = append(resources.Namespaces, namespace)
+			providedNamespaceMap.Insert(config.DefaultNamespace)
+		}
+	}
+
+	if addMissingResources {
+		for ns := range requiredNamespaceMap {
+			if !providedNamespaceMap.Has(ns) {
+				namespace := &corev1.Namespace{
+					ObjectMeta: metav1.ObjectMeta{
+						Name: ns,
+					},
+				}
+				resources.Namespaces = append(resources.Namespaces, namespace)
+			}
+		}
+
+		requiredServiceMap := map[string]*corev1.Service{}
+		for _, route := range resources.TCPRoutes {
+			addMissingServices(requiredServiceMap, route)
+		}
+		for _, route := range resources.UDPRoutes {
+			addMissingServices(requiredServiceMap, route)
+		}
+		for _, route := range resources.TLSRoutes {
+			addMissingServices(requiredServiceMap, route)
+		}
+		for _, route := range resources.HTTPRoutes {
+			addMissingServices(requiredServiceMap, route)
+		}
+		for _, route := range resources.GRPCRoutes {
+			addMissingServices(requiredServiceMap, route)
+		}
+
+		providedServiceMap := map[string]*corev1.Service{}
+		for _, service := range resources.Services {
+			providedServiceMap[service.Namespace+"/"+service.Name] = service
+		}
+
+		for key, service := range requiredServiceMap {
+			if provided, found := providedServiceMap[key]; !found {
+				resources.Services = append(resources.Services, service)
+			} else {
+				providedPorts := sets.NewString()
+				for _, port := range provided.Spec.Ports {
+					portKey := fmt.Sprintf("%s-%d", port.Protocol, port.Port)
+					providedPorts.Insert(portKey)
+				}
+
+				for _, port := range service.Spec.Ports {
+					name := fmt.Sprintf("%s-%d", port.Protocol, port.Port)
+					if !providedPorts.Has(name) {
+						servicePort := corev1.ServicePort{
+							Name:     name,
+							Protocol: port.Protocol,
+							Port:     port.Port,
+						}
+						provided.Spec.Ports = append(provided.Spec.Ports, servicePort)
+					}
+				}
+			}
+		}
+
+		// Add EnvoyProxy if it does not exist
+		if resources.EnvoyProxyForGatewayClass == nil {
+			if err := addDefaultEnvoyProxy(resources); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return resources, nil
+}
+
+func addMissingServices(requiredServices map[string]*corev1.Service, obj interface{}) {
+	var objNamespace string
+	protocol := corev1.Protocol("TCP")
+
+	var refs []gwapiv1.BackendRef
+	switch route := obj.(type) {
+	case *gwapiv1.HTTPRoute:
+		objNamespace = route.Namespace
+		for _, rule := range route.Spec.Rules {
+			for _, httpBakcendRef := range rule.BackendRefs {
+				refs = append(refs, httpBakcendRef.BackendRef)
+			}
+		}
+	case *gwapiv1.GRPCRoute:
+		objNamespace = route.Namespace
+		for _, rule := range route.Spec.Rules {
+			for _, gRPCBakcendRef := range rule.BackendRefs {
+				refs = append(refs, gRPCBakcendRef.BackendRef)
+			}
+		}
+	case *gwapiv1a2.TLSRoute:
+		objNamespace = route.Namespace
+		for _, rule := range route.Spec.Rules {
+			refs = append(refs, rule.BackendRefs...)
+		}
+	case *gwapiv1a2.TCPRoute:
+		objNamespace = route.Namespace
+		for _, rule := range route.Spec.Rules {
+			refs = append(refs, rule.BackendRefs...)
+		}
+	case *gwapiv1a2.UDPRoute:
+		protocol = "UDP"
+		objNamespace = route.Namespace
+		for _, rule := range route.Spec.Rules {
+			refs = append(refs, rule.BackendRefs...)
+		}
+	}
+
+	for _, ref := range refs {
+		if ref.Kind == nil || *ref.Kind != KindService {
+			continue
+		}
+
+		ns := objNamespace
+		if ref.Namespace != nil {
+			ns = string(*ref.Namespace)
+		}
+		name := string(ref.Name)
+		key := ns + "/" + name
+
+		port := int32(*ref.Port)
+		servicePort := corev1.ServicePort{
+			Name:     fmt.Sprintf("%s-%d", protocol, port),
+			Protocol: protocol,
+			Port:     port,
+		}
+		if service, found := requiredServices[key]; !found {
+			service := &corev1.Service{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      name,
+					Namespace: ns,
+				},
+				Spec: corev1.ServiceSpec{
+					// Just a dummy IP
+					ClusterIP: dummyClusterIP,
+					Ports:     []corev1.ServicePort{servicePort},
+				},
+			}
+			requiredServices[key] = service
+		} else {
+			inserted := false
+			for _, port := range service.Spec.Ports {
+				if port.Protocol == servicePort.Protocol && port.Port == servicePort.Port {
+					inserted = true
+					break
+				}
+			}
+
+			if !inserted {
+				service.Spec.Ports = append(service.Spec.Ports, servicePort)
+			}
+		}
+	}
+}
+
+func addDefaultEnvoyProxy(resources *Resources) 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
+	}
+	ep := &egv1a1.EnvoyProxy{
+		ObjectMeta: metav1.ObjectMeta{
+			Namespace: namespace,
+			Name:      defaultEnvoyProxyName,
+		},
+		Spec: egv1a1.EnvoyProxySpec{
+			Bootstrap: &egv1a1.ProxyBootstrap{
+				Value: &defaultBootstrapStr,
+			},
+		},
+	}
+	resources.EnvoyProxyForGatewayClass = ep
+	ns := gwapiv1.Namespace(namespace)
+	resources.GatewayClass.Spec.ParametersRef = &gwapiv1.ParametersReference{
+		Group:     gwapiv1.Group(egv1a1.GroupVersion.Group),
+		Kind:      KindEnvoyProxy,
+		Name:      defaultEnvoyProxyName,
+		Namespace: &ns,
+	}
+	return nil
+}
diff --git a/internal/gatewayapi/resource.go b/internal/gatewayapi/resource/resource.go
similarity index 99%
rename from internal/gatewayapi/resource.go
rename to internal/gatewayapi/resource/resource.go
index 3595e9c1c..a5d9e6fff 100644
--- a/internal/gatewayapi/resource.go
+++ b/internal/gatewayapi/resource/resource.go
@@ -3,7 +3,7 @@
 // The full text of the Apache license is available in the LICENSE file at
 // the root of the repo.
 
-package gatewayapi
+package resource
 
 import (
 	"cmp"
diff --git a/internal/gatewayapi/resource/supported_kind.go b/internal/gatewayapi/resource/supported_kind.go
new file mode 100644
index 000000000..5c2c21954
--- /dev/null
+++ b/internal/gatewayapi/resource/supported_kind.go
@@ -0,0 +1,29 @@
+// 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 resource
+
+const (
+	KindConfigMap            = "ConfigMap"
+	KindClientTrafficPolicy  = "ClientTrafficPolicy"
+	KindBackendTrafficPolicy = "BackendTrafficPolicy"
+	KindBackendTLSPolicy     = "BackendTLSPolicy"
+	KindBackend              = "Backend"
+	KindEnvoyPatchPolicy     = "EnvoyPatchPolicy"
+	KindEnvoyExtensionPolicy = "EnvoyExtensionPolicy"
+	KindSecurityPolicy       = "SecurityPolicy"
+	KindEnvoyProxy           = "EnvoyProxy"
+	KindGateway              = "Gateway"
+	KindGatewayClass         = "GatewayClass"
+	KindGRPCRoute            = "GRPCRoute"
+	KindHTTPRoute            = "HTTPRoute"
+	KindNamespace            = "Namespace"
+	KindTLSRoute             = "TLSRoute"
+	KindTCPRoute             = "TCPRoute"
+	KindUDPRoute             = "UDPRoute"
+	KindService              = "Service"
+	KindServiceImport        = "ServiceImport"
+	KindSecret               = "Secret"
+)
diff --git a/internal/gatewayapi/zz_generated.deepcopy.go b/internal/gatewayapi/resource/zz_generated.deepcopy.go
similarity index 99%
rename from internal/gatewayapi/zz_generated.deepcopy.go
rename to internal/gatewayapi/resource/zz_generated.deepcopy.go
index 0ed43eea3..61cf9dfb4 100644
--- a/internal/gatewayapi/zz_generated.deepcopy.go
+++ b/internal/gatewayapi/resource/zz_generated.deepcopy.go
@@ -7,7 +7,7 @@
 
 // Code generated by controller-gen. DO NOT EDIT.
 
-package gatewayapi
+package resource
 
 import (
 	"github.com/envoyproxy/gateway/api/v1alpha1"
diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go
index 0e5678247..743337591 100644
--- a/internal/gatewayapi/route.go
+++ b/internal/gatewayapi/route.go
@@ -21,6 +21,7 @@ import (
 	mcsapiv1a1 "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils/regex"
@@ -42,14 +43,14 @@ var (
 )
 
 type RoutesTranslator interface {
-	ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*HTTPRouteContext
-	ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*GRPCRouteContext
-	ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*TLSRouteContext
-	ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*TCPRouteContext
-	ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*UDPRouteContext
+	ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*HTTPRouteContext
+	ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*GRPCRouteContext
+	ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*TLSRouteContext
+	ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*TCPRouteContext
+	ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*UDPRouteContext
 }
 
-func (t *Translator) ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*HTTPRouteContext {
+func (t *Translator) ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*HTTPRouteContext {
 	var relevantHTTPRoutes []*HTTPRouteContext
 
 	for _, h := range httpRoutes {
@@ -77,7 +78,7 @@ func (t *Translator) ProcessHTTPRoutes(httpRoutes []*gwapiv1.HTTPRoute, gateways
 	return relevantHTTPRoutes
 }
 
-func (t *Translator) ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*GRPCRouteContext {
+func (t *Translator) ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*GRPCRouteContext {
 	var relevantGRPCRoutes []*GRPCRouteContext
 
 	for _, g := range grpcRoutes {
@@ -105,7 +106,7 @@ func (t *Translator) ProcessGRPCRoutes(grpcRoutes []*gwapiv1.GRPCRoute, gateways
 	return relevantGRPCRoutes
 }
 
-func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, resources *Resources, xdsIR XdsIRMap) {
+func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, resources *resource.Resources, xdsIR resource.XdsIRMap) {
 	for _, parentRef := range httpRoute.ParentRefs {
 		// Need to compute Route rules within the parentRef loop because
 		// any conditions that come out of it have to go on each RouteParentStatus,
@@ -172,7 +173,7 @@ func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, res
 	}
 }
 
-func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRef *RouteParentContext, resources *Resources) ([]*ir.HTTPRoute, error) {
+func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRef *RouteParentContext, resources *resource.Resources) ([]*ir.HTTPRoute, error) {
 	var routeRoutes []*ir.HTTPRoute
 	var envoyProxy *egv1a1.EnvoyProxy
 
@@ -462,7 +463,7 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir
 	}
 }
 
-func (t *Translator) processGRPCRouteParentRefs(grpcRoute *GRPCRouteContext, resources *Resources, xdsIR XdsIRMap) {
+func (t *Translator) processGRPCRouteParentRefs(grpcRoute *GRPCRouteContext, resources *resource.Resources, xdsIR resource.XdsIRMap) {
 	for _, parentRef := range grpcRoute.ParentRefs {
 
 		// Need to compute Route rules within the parentRef loop because
@@ -528,7 +529,7 @@ func (t *Translator) processGRPCRouteParentRefs(grpcRoute *GRPCRouteContext, res
 	}
 }
 
-func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRef *RouteParentContext, resources *Resources) ([]*ir.HTTPRoute, error) {
+func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRef *RouteParentContext, resources *resource.Resources) ([]*ir.HTTPRoute, error) {
 	var routeRoutes []*ir.HTTPRoute
 
 	// compute matches, filters, backends
@@ -686,7 +687,7 @@ func (t *Translator) processGRPCRouteMethodRegularExpression(method *gwapiv1.GRP
 	}
 }
 
-func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR XdsIRMap) bool {
+func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, routeRoutes []*ir.HTTPRoute, parentRef *RouteParentContext, xdsIR resource.XdsIRMap) bool {
 	var hasHostnameIntersection bool
 
 	for _, listener := range parentRef.listeners {
@@ -753,7 +754,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
 		irListener := xdsIR[irKey].GetHTTPListener(irListenerName(listener))
 
 		if irListener != nil {
-			if GetRouteType(route) == KindGRPCRoute {
+			if GetRouteType(route) == resource.KindGRPCRoute {
 				irListener.IsHTTP2 = true
 			}
 			irListener.Routes = append(irListener.Routes, perHostRoutes...)
@@ -785,7 +786,7 @@ func filterEGPrefix(in map[string]string) map[string]string {
 	return out
 }
 
-func (t *Translator) ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways []*GatewayContext, resources *Resources, xdsIR XdsIRMap) []*TLSRouteContext {
+func (t *Translator) ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways []*GatewayContext, resources *resource.Resources, xdsIR resource.XdsIRMap) []*TLSRouteContext {
 	var relevantTLSRoutes []*TLSRouteContext
 
 	for _, tls := range tlsRoutes {
@@ -813,7 +814,7 @@ func (t *Translator) ProcessTLSRoutes(tlsRoutes []*gwapiv1a2.TLSRoute, gateways
 	return relevantTLSRoutes
 }
 
-func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resources *Resources, xdsIR XdsIRMap) {
+func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resources *resource.Resources, xdsIR resource.XdsIRMap) {
 	for _, parentRef := range tlsRoute.ParentRefs {
 
 		// Need to compute Route rules within the parentRef loop because
@@ -912,8 +913,8 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour
 	}
 }
 
-func (t *Translator) ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways []*GatewayContext, resources *Resources,
-	xdsIR XdsIRMap,
+func (t *Translator) ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways []*GatewayContext, resources *resource.Resources,
+	xdsIR resource.XdsIRMap,
 ) []*UDPRouteContext {
 	var relevantUDPRoutes []*UDPRouteContext
 
@@ -942,7 +943,7 @@ func (t *Translator) ProcessUDPRoutes(udpRoutes []*gwapiv1a2.UDPRoute, gateways
 	return relevantUDPRoutes
 }
 
-func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resources *Resources, xdsIR XdsIRMap) {
+func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resources *resource.Resources, xdsIR resource.XdsIRMap) {
 	for _, parentRef := range udpRoute.ParentRefs {
 		// Need to compute Route rules within the parentRef loop because
 		// any conditions that come out of it have to go on each RouteParentStatus,
@@ -1045,8 +1046,8 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour
 	}
 }
 
-func (t *Translator) ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways []*GatewayContext, resources *Resources,
-	xdsIR XdsIRMap,
+func (t *Translator) ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways []*GatewayContext, resources *resource.Resources,
+	xdsIR resource.XdsIRMap,
 ) []*TCPRouteContext {
 	var relevantTCPRoutes []*TCPRouteContext
 
@@ -1075,7 +1076,7 @@ func (t *Translator) ProcessTCPRoutes(tcpRoutes []*gwapiv1a2.TCPRoute, gateways
 	return relevantTCPRoutes
 }
 
-func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resources *Resources, xdsIR XdsIRMap) {
+func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resources *resource.Resources, xdsIR resource.XdsIRMap) {
 	for _, parentRef := range tcpRoute.ParentRefs {
 		// Need to compute Route rules within the parentRef loop because
 		// any conditions that come out of it have to go on each RouteParentStatus,
@@ -1194,7 +1195,7 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
 // returns the weight for the backend so that 500 error responses can be returned for invalid backends in
 // the same proportion as the backend would have otherwise received
 func (t *Translator) processDestination(backendRefContext BackendRefContext,
-	parentRef *RouteParentContext, route RouteContext, resources *Resources,
+	parentRef *RouteParentContext, route RouteContext, resources *resource.Resources,
 ) (ds *ir.DestinationSetting) {
 	routeType := GetRouteType(route)
 	weight := uint32(1)
@@ -1225,8 +1226,8 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 		addrType  *ir.DestinationAddressType
 	)
 	protocol := inspectAppProtocolByRouteKind(routeType)
-	switch KindDerefOr(backendRef.Kind, KindService) {
-	case KindServiceImport:
+	switch KindDerefOr(backendRef.Kind, resource.KindService) {
+	case resource.KindServiceImport:
 		serviceImport := resources.GetServiceImport(backendNamespace, string(backendRef.Name))
 		var servicePort mcsapiv1a1.ServicePort
 		for _, port := range serviceImport.Spec.Ports {
@@ -1237,7 +1238,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 		}
 
 		if !t.IsEnvoyServiceRouting(envoyProxy) {
-			endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, KindService))
+			endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, resource.KindService))
 			endpoints, addrType = getIREndpointsFromEndpointSlices(endpointSlices, servicePort.Name, servicePort.Protocol)
 		} else {
 			backendIps := resources.GetServiceImport(backendNamespace, string(backendRef.Name)).Spec.IPs
@@ -1255,7 +1256,7 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 			Endpoints:   endpoints,
 			AddressType: addrType,
 		}
-	case KindService:
+	case resource.KindService:
 		ds = t.processServiceDestinationSetting(backendRef.BackendObjectReference, backendNamespace, protocol, resources, envoyProxy)
 
 		ds.TLS = t.applyBackendTLSSetting(
@@ -1310,12 +1311,12 @@ func (t *Translator) processDestination(backendRefContext BackendRefContext,
 
 func validateDestinationSettings(destinationSettings *ir.DestinationSetting, endpointRoutingDisabled bool, kind *gwapiv1.Kind) error {
 	// TODO: support mixed endpointslice address type for the same backendRef
-	switch KindDerefOr(kind, KindService) {
+	switch KindDerefOr(kind, resource.KindService) {
 	case egv1a1.KindBackend:
 		if destinationSettings.AddressType != nil && *destinationSettings.AddressType == ir.MIXED {
 			return fmt.Errorf("mixed FQDN and IP or Unix address type for the same backendRef is not supported")
 		}
-	case KindService, KindServiceImport:
+	case resource.KindService, resource.KindServiceImport:
 		if !endpointRoutingDisabled && destinationSettings.AddressType != nil && *destinationSettings.AddressType == ir.MIXED {
 			return fmt.Errorf("mixed endpointslice address type for the same backendRef is not supported")
 		}
@@ -1328,7 +1329,7 @@ func (t *Translator) processServiceDestinationSetting(
 	backendRef gwapiv1.BackendObjectReference,
 	backendNamespace string,
 	protocol ir.AppProtocol,
-	resources *Resources,
+	resources *resource.Resources,
 	envoyProxy *egv1a1.EnvoyProxy,
 ) *ir.DestinationSetting {
 	var (
@@ -1357,7 +1358,7 @@ func (t *Translator) processServiceDestinationSetting(
 
 	// Route to endpoints by default
 	if !t.IsEnvoyServiceRouting(envoyProxy) {
-		endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, KindService))
+		endpointSlices := resources.GetEndpointSlicesForBackend(backendNamespace, string(backendRef.Name), KindDerefOr(backendRef.Kind, resource.KindService))
 		endpoints, addrType = getIREndpointsFromEndpointSlices(endpointSlices, servicePort.Name, servicePort.Protocol)
 	} else {
 		// Fall back to Service ClusterIP routing
@@ -1377,11 +1378,11 @@ func (t *Translator) processServiceDestinationSetting(
 func getBackendFilters(routeType gwapiv1.Kind, backendRefContext BackendRefContext) (backendFilters any) {
 	filters := GetFilters(backendRefContext)
 	switch routeType {
-	case KindHTTPRoute:
+	case resource.KindHTTPRoute:
 		if len(filters.([]gwapiv1.HTTPRouteFilter)) > 0 {
 			return filters.([]gwapiv1.HTTPRouteFilter)
 		}
-	case KindGRPCRoute:
+	case resource.KindGRPCRoute:
 		if len(filters.([]gwapiv1.GRPCRouteFilter)) > 0 {
 			return filters.([]gwapiv1.GRPCRouteFilter)
 		}
@@ -1390,7 +1391,7 @@ func getBackendFilters(routeType gwapiv1.Kind, backendRefContext BackendRefConte
 	return nil
 }
 
-func (t *Translator) processDestinationFilters(routeType gwapiv1.Kind, backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext, resources *Resources) *ir.DestinationFilters {
+func (t *Translator) processDestinationFilters(routeType gwapiv1.Kind, backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext, resources *resource.Resources) *ir.DestinationFilters {
 	backendFilters := getBackendFilters(routeType, backendRefContext)
 	if backendFilters == nil {
 		return nil
@@ -1428,15 +1429,15 @@ func applyHTTPFiltersContextToDestinationFilters(httpFiltersContext *HTTPFilters
 
 func inspectAppProtocolByRouteKind(kind gwapiv1.Kind) ir.AppProtocol {
 	switch kind {
-	case KindUDPRoute:
+	case resource.KindUDPRoute:
 		return ir.UDP
-	case KindHTTPRoute:
+	case resource.KindHTTPRoute:
 		return ir.HTTP
-	case KindTCPRoute:
+	case resource.KindTCPRoute:
 		return ir.TCP
-	case KindGRPCRoute:
+	case resource.KindGRPCRoute:
 		return ir.GRPC
-	case KindTLSRoute:
+	case resource.KindTLSRoute:
 		return ir.HTTPS
 	}
 	return ir.TCP
@@ -1445,7 +1446,7 @@ func inspectAppProtocolByRouteKind(kind gwapiv1.Kind) ir.AppProtocol {
 // processAllowedListenersForParentRefs finds out if the route attaches to one of our
 // Gateways' listeners, and if so, gets the list of listeners that allow it to
 // attach for each parentRef.
-func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteContext, gateways []*GatewayContext, resources *Resources) bool {
+func (t *Translator) processAllowedListenersForParentRefs(routeContext RouteContext, gateways []*GatewayContext, resources *resource.Resources) bool {
 	var relevantRoute bool
 	ns := gwapiv1.Namespace(routeContext.GetNamespace())
 	for _, parentRef := range GetParentReferences(routeContext) {
@@ -1615,7 +1616,7 @@ func getTargetBackendReference(backendRef gwapiv1a2.BackendObjectReference) gwap
 	return ref
 }
 
-func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, resources *Resources) *ir.DestinationSetting {
+func (t *Translator) processBackendDestinationSetting(backendRef gwapiv1.BackendObjectReference, backendNamespace string, resources *resource.Resources) *ir.DestinationSetting {
 	var (
 		dstEndpoints []*ir.DestinationEndpoint
 		dstAddrType  *ir.DestinationAddressType
diff --git a/internal/gatewayapi/runner/runner.go b/internal/gatewayapi/runner/runner.go
index 651e16352..3f1605c11 100644
--- a/internal/gatewayapi/runner/runner.go
+++ b/internal/gatewayapi/runner/runner.go
@@ -30,6 +30,7 @@ import (
 	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	extension "github.com/envoyproxy/gateway/internal/extension/types"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/message"
 	"github.com/envoyproxy/gateway/internal/utils"
 	"github.com/envoyproxy/gateway/internal/wasm"
@@ -115,7 +116,7 @@ func (r *Runner) startWasmCache(ctx context.Context) {
 
 func (r *Runner) subscribeAndTranslate(ctx context.Context) {
 	message.HandleSubscription(message.Metadata{Runner: string(egv1a1.LogComponentGatewayAPIRunner), Message: "provider-resources"}, r.ProviderResources.GatewayAPIResources.Subscribe(ctx),
-		func(update message.Update[string, *gatewayapi.ControllerResources], errChan chan error) {
+		func(update message.Update[string, *resource.ControllerResources], errChan chan error) {
 			r.Logger.Info("received an update")
 			val := update.Value
 			// There is only 1 key which is the controller name
diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go
index 887b63386..86d39602f 100644
--- a/internal/gatewayapi/securitypolicy.go
+++ b/internal/gatewayapi/securitypolicy.go
@@ -26,6 +26,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	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/ir"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -46,8 +47,8 @@ const (
 func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.SecurityPolicy,
 	gateways []*GatewayContext,
 	routes []RouteContext,
-	resources *Resources,
-	xdsIR XdsIRMap,
+	resources *resource.Resources,
+	xdsIR resource.XdsIRMap,
 ) []*egv1a1.SecurityPolicy {
 	var res []*egv1a1.SecurityPolicy
 
@@ -87,7 +88,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, routes)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind != KindGateway {
+			if currTarget.Kind != resource.KindGateway {
 				var (
 					targetedRoute  RouteContext
 					parentGateways []gwapiv1a2.ParentReference
@@ -114,7 +115,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security
 				// The parent gateways are also used to set the status of the policy.
 				parentRefs := GetParentReferences(targetedRoute)
 				for _, p := range parentRefs {
-					if p.Kind == nil || *p.Kind == KindGateway {
+					if p.Kind == nil || *p.Kind == resource.KindGateway {
 						namespace := targetedRoute.GetNamespace()
 						if p.Namespace != nil {
 							namespace = string(*p.Namespace)
@@ -165,7 +166,7 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security
 		policyName := utils.NamespacedName(currPolicy)
 		targetRefs := getPolicyTargetRefs(currPolicy.Spec.PolicyTargetReferences, gateways)
 		for _, currTarget := range targetRefs {
-			if currTarget.Kind == KindGateway {
+			if currTarget.Kind == resource.KindGateway {
 				var (
 					targetedGateway *GatewayContext
 					resolveErr      *status.PolicyResolveError
@@ -322,7 +323,7 @@ func resolveSecurityPolicyRouteTargetRef(
 
 func (t *Translator) translateSecurityPolicyForRoute(
 	policy *egv1a1.SecurityPolicy, route RouteContext,
-	resources *Resources, xdsIR XdsIRMap,
+	resources *resource.Resources, xdsIR resource.XdsIRMap,
 ) error {
 	// Build IR
 	var (
@@ -419,8 +420,8 @@ func (t *Translator) translateSecurityPolicyForGateway(
 	policy *egv1a1.SecurityPolicy,
 	gateway *GatewayContext,
 	target gwapiv1a2.LocalPolicyTargetReferenceWithSectionName,
-	resources *Resources,
-	xdsIR XdsIRMap,
+	resources *resource.Resources,
+	xdsIR resource.XdsIRMap,
 ) error {
 	// Build IR
 	var (
@@ -564,7 +565,7 @@ func (t *Translator) buildJWT(jwt *egv1a1.JWT) *ir.JWT {
 
 func (t *Translator) buildOIDC(
 	policy *egv1a1.SecurityPolicy,
-	resources *Resources,
+	resources *resource.Resources,
 ) (*ir.OIDC, error) {
 	var (
 		oidc         = policy.Spec.OIDC
@@ -575,7 +576,7 @@ func (t *Translator) buildOIDC(
 
 	from := crossNamespaceFrom{
 		group:     egv1a1.GroupName,
-		kind:      KindSecurityPolicy,
+		kind:      resource.KindSecurityPolicy,
 		namespace: policy.Namespace,
 	}
 	if clientSecret, err = t.validateSecretRef(
@@ -773,7 +774,7 @@ func validateTokenEndpoint(tokenEndpoint string) error {
 
 func (t *Translator) buildBasicAuth(
 	policy *egv1a1.SecurityPolicy,
-	resources *Resources,
+	resources *resource.Resources,
 ) (*ir.BasicAuth, error) {
 	var (
 		basicAuth   = policy.Spec.BasicAuth
@@ -783,7 +784,7 @@ func (t *Translator) buildBasicAuth(
 
 	from := crossNamespaceFrom{
 		group:     egv1a1.GroupName,
-		kind:      KindSecurityPolicy,
+		kind:      resource.KindSecurityPolicy,
 		namespace: policy.Namespace,
 	}
 	if usersSecret, err = t.validateSecretRef(
@@ -804,7 +805,7 @@ func (t *Translator) buildBasicAuth(
 	}, nil
 }
 
-func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Resources, envoyProxy *egv1a1.EnvoyProxy) (*ir.ExtAuth, error) {
+func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *resource.Resources, envoyProxy *egv1a1.EnvoyProxy) (*ir.ExtAuth, error) {
 	var (
 		http      = policy.Spec.ExtAuth.HTTP
 		grpc      = policy.Spec.ExtAuth.GRPC
@@ -849,7 +850,7 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Reso
 		extServiceDest, err := t.processExtServiceDestination(
 			&backendRef,
 			pnn,
-			KindSecurityPolicy,
+			resource.KindSecurityPolicy,
 			protocol,
 			resources,
 			envoyProxy,
@@ -860,7 +861,7 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Reso
 		ds = append(ds, extServiceDest)
 	}
 	rd := ir.RouteDestination{
-		Name:     irIndexedExtServiceDestinationName(pnn, egv1a1.KindSecurityPolicy, 0),
+		Name:     irIndexedExtServiceDestinationName(pnn, resource.KindSecurityPolicy, 0),
 		Settings: ds,
 	}
 
@@ -891,14 +892,14 @@ func (t *Translator) buildExtAuth(policy *egv1a1.SecurityPolicy, resources *Reso
 	return extAuth, nil
 }
 
-func backendRefAuthority(resources *Resources, backendRef *gwapiv1.BackendObjectReference, policy *egv1a1.SecurityPolicy) string {
+func backendRefAuthority(resources *resource.Resources, backendRef *gwapiv1.BackendObjectReference, policy *egv1a1.SecurityPolicy) string {
 	if backendRef == nil {
 		return ""
 	}
 
 	backendNamespace := NamespaceDerefOr(backendRef.Namespace, policy.Namespace)
-	backendKind := KindDerefOr(backendRef.Kind, KindService)
-	if backendKind == egv1a1.KindBackend {
+	backendKind := KindDerefOr(backendRef.Kind, resource.KindService)
+	if backendKind == resource.KindBackend {
 		backend := resources.GetBackend(backendNamespace, string(backendRef.Name))
 		if backend != nil {
 			// TODO: exists multi FQDN endpoints?
diff --git a/internal/gatewayapi/sort.go b/internal/gatewayapi/sort.go
index c11787a60..95643a9e1 100644
--- a/internal/gatewayapi/sort.go
+++ b/internal/gatewayapi/sort.go
@@ -8,6 +8,7 @@ package gatewayapi
 import (
 	"sort"
 
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/ir"
 )
 
@@ -81,7 +82,7 @@ func (x XdsIRRoutes) Less(i, j int) bool {
 // sortXdsIR sorts the xdsIR based on the match precedence
 // defined in the Gateway API spec.
 // https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/v1.HTTPRouteRule
-func sortXdsIRMap(xdsIR XdsIRMap) {
+func sortXdsIRMap(xdsIR resource.XdsIRMap) {
 	for _, irItem := range xdsIR {
 		for _, http := range irItem.HTTP {
 			// descending order
diff --git a/internal/gatewayapi/translator.go b/internal/gatewayapi/translator.go
index 6346bb1a4..0e6d683d8 100644
--- a/internal/gatewayapi/translator.go
+++ b/internal/gatewayapi/translator.go
@@ -16,31 +16,12 @@ import (
 	gwapiv1a3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/ir"
 	"github.com/envoyproxy/gateway/internal/wasm"
 )
 
 const (
-	KindConfigMap            = "ConfigMap"
-	KindClientTrafficPolicy  = "ClientTrafficPolicy"
-	KindBackendTrafficPolicy = "BackendTrafficPolicy"
-	KindBackendTLSPolicy     = "BackendTLSPolicy"
-	KindEnvoyPatchPolicy     = "EnvoyPatchPolicy"
-	KindEnvoyExtensionPolicy = "EnvoyExtensionPolicy"
-	KindSecurityPolicy       = "SecurityPolicy"
-	KindEnvoyProxy           = "EnvoyProxy"
-	KindGateway              = "Gateway"
-	KindGatewayClass         = "GatewayClass"
-	KindGRPCRoute            = "GRPCRoute"
-	KindHTTPRoute            = "HTTPRoute"
-	KindNamespace            = "Namespace"
-	KindTLSRoute             = "TLSRoute"
-	KindTCPRoute             = "TCPRoute"
-	KindUDPRoute             = "UDPRoute"
-	KindService              = "Service"
-	KindServiceImport        = "ServiceImport"
-	KindSecret               = "Secret"
-
 	GroupMultiClusterService = "multicluster.x-k8s.io"
 	// OwningGatewayNamespaceLabel is the owner reference label used for managed infra.
 	// The value should be the namespace of the accepted Envoy Gateway.
@@ -61,8 +42,8 @@ const (
 var _ TranslatorManager = (*Translator)(nil)
 
 type TranslatorManager interface {
-	Translate(resources *Resources) (*TranslateResult, error)
-	GetRelevantGateways(resources *Resources) []*GatewayContext
+	Translate(resources *resource.Resources) (*TranslateResult, error)
+	GetRelevantGateways(resources *resource.Resources) []*GatewayContext
 
 	RoutesTranslator
 	ListenersTranslator
@@ -113,9 +94,9 @@ type Translator struct {
 }
 
 type TranslateResult struct {
-	Resources
-	XdsIR   XdsIRMap   `json:"xdsIR" yaml:"xdsIR"`
-	InfraIR InfraIRMap `json:"infraIR" yaml:"infraIR"`
+	resource.Resources
+	XdsIR   resource.XdsIRMap   `json:"xdsIR" yaml:"xdsIR"`
+	InfraIR resource.InfraIRMap `json:"infraIR" yaml:"infraIR"`
 }
 
 func newTranslateResult(gateways []*GatewayContext,
@@ -131,7 +112,7 @@ func newTranslateResult(gateways []*GatewayContext,
 	envoyExtensionPolicies []*egv1a1.EnvoyExtensionPolicy,
 	extPolicies []unstructured.Unstructured,
 	backends []*egv1a1.Backend,
-	xdsIR XdsIRMap, infraIR InfraIRMap,
+	xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap,
 ) *TranslateResult {
 	translateResult := &TranslateResult{
 		XdsIR:   xdsIR,
@@ -168,7 +149,7 @@ func newTranslateResult(gateways []*GatewayContext,
 	return translateResult
 }
 
-func (t *Translator) Translate(resources *Resources) (*TranslateResult, error) {
+func (t *Translator) Translate(resources *resource.Resources) (*TranslateResult, error) {
 	// Get Gateways belonging to our GatewayClass.
 	gateways := t.GetRelevantGateways(resources)
 
@@ -178,7 +159,7 @@ func (t *Translator) Translate(resources *Resources) (*TranslateResult, error) {
 	})
 
 	// Build IR maps.
-	xdsIR, infraIR := t.InitIRs(gateways, resources)
+	xdsIR, infraIR := t.InitIRs(gateways)
 
 	// Process all Listeners for all relevant Gateways.
 	t.ProcessListeners(gateways, xdsIR, infraIR, resources)
@@ -187,7 +168,7 @@ func (t *Translator) Translate(resources *Resources) (*TranslateResult, error) {
 	t.ProcessEnvoyPatchPolicies(resources.EnvoyPatchPolicies, xdsIR)
 
 	// Process all Addresses for all relevant Gateways.
-	t.ProcessAddresses(gateways, xdsIR, infraIR, resources)
+	t.ProcessAddresses(gateways, xdsIR, infraIR)
 
 	// process all Backends
 	backends := t.ProcessBackends(resources.Backends)
@@ -263,7 +244,7 @@ func (t *Translator) Translate(resources *Resources) (*TranslateResult, error) {
 
 // GetRelevantGateways returns GatewayContexts, containing a copy of the original
 // Gateway with the Listener statuses reset.
-func (t *Translator) GetRelevantGateways(resources *Resources) []*GatewayContext {
+func (t *Translator) GetRelevantGateways(resources *resource.Resources) []*GatewayContext {
 	var relevant []*GatewayContext
 
 	for _, gateway := range resources.Gateways {
@@ -285,9 +266,9 @@ func (t *Translator) GetRelevantGateways(resources *Resources) []*GatewayContext
 }
 
 // InitIRs checks if mergeGateways is enabled in EnvoyProxy config and initializes XdsIR and InfraIR maps with adequate keys.
-func (t *Translator) InitIRs(gateways []*GatewayContext, resources *Resources) (map[string]*ir.Xds, map[string]*ir.Infra) {
-	xdsIR := make(XdsIRMap)
-	infraIR := make(InfraIRMap)
+func (t *Translator) InitIRs(gateways []*GatewayContext) (map[string]*ir.Xds, map[string]*ir.Infra) {
+	xdsIR := make(resource.XdsIRMap)
+	infraIR := make(resource.InfraIRMap)
 
 	var irKey string
 	for _, gateway := range gateways {
diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go
index d92dee3bc..87020d7f6 100644
--- a/internal/gatewayapi/validate.go
+++ b/internal/gatewayapi/validate.go
@@ -20,11 +20,12 @@ import (
 	gwapiv1b1 "sigs.k8s.io/gateway-api/apis/v1beta1"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
 )
 
 func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext,
-	resources *Resources, backendNamespace string, routeKind gwapiv1.Kind,
+	resources *resource.Resources, backendNamespace string, routeKind gwapiv1.Kind,
 ) bool {
 	backendRef := GetBackendRef(backendRefContext)
 
@@ -44,12 +45,12 @@ func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, par
 		return false
 	}
 	protocol := corev1.ProtocolTCP
-	if routeKind == KindUDPRoute {
+	if routeKind == resource.KindUDPRoute {
 		protocol = corev1.ProtocolUDP
 	}
-	backendRefKind := KindDerefOr(backendRef.Kind, KindService)
+	backendRefKind := KindDerefOr(backendRef.Kind, resource.KindService)
 	switch backendRefKind {
-	case KindService:
+	case resource.KindService:
 		if err := validateBackendService(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil {
 			routeStatus := GetRouteStatus(route)
 			status.SetRouteStatusCondition(routeStatus,
@@ -62,7 +63,7 @@ func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, par
 			)
 			return false
 		}
-	case KindServiceImport:
+	case resource.KindServiceImport:
 		if !t.validateBackendServiceImport(backendRef, parentRef, resources, backendNamespace, route, protocol) {
 			return false
 		}
@@ -91,7 +92,7 @@ func (t *Translator) validateBackendRefGroup(backendRef *gwapiv1a2.BackendRef, p
 }
 
 func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) bool {
-	if backendRef.Kind != nil && *backendRef.Kind != KindService && *backendRef.Kind != KindServiceImport && *backendRef.Kind != egv1a1.KindBackend {
+	if backendRef.Kind != nil && *backendRef.Kind != resource.KindService && *backendRef.Kind != resource.KindServiceImport && *backendRef.Kind != egv1a1.KindBackend {
 		routeStatus := GetRouteStatus(route)
 		status.SetRouteStatusCondition(routeStatus,
 			parentRef.routeParentStatusIdx,
@@ -111,13 +112,13 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, par
 	var unsupportedFilters bool
 
 	switch routeKind {
-	case KindHTTPRoute:
+	case resource.KindHTTPRoute:
 		for _, filter := range filters.([]gwapiv1.HTTPRouteFilter) {
 			if filter.Type != gwapiv1.HTTPRouteFilterRequestHeaderModifier && filter.Type != gwapiv1.HTTPRouteFilterResponseHeaderModifier {
 				unsupportedFilters = true
 			}
 		}
-	case KindGRPCRoute:
+	case resource.KindGRPCRoute:
 		for _, filter := range filters.([]gwapiv1.GRPCRouteFilter) {
 			if filter.Type != gwapiv1.GRPCRouteFilterRequestHeaderModifier && filter.Type != gwapiv1.GRPCRouteFilterResponseHeaderModifier {
 				unsupportedFilters = true
@@ -144,7 +145,7 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, par
 }
 
 func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext,
-	resources *Resources, routeKind gwapiv1.Kind,
+	resources *resource.Resources, routeKind gwapiv1.Kind,
 ) bool {
 	if backendRef.Namespace != nil && string(*backendRef.Namespace) != "" && string(*backendRef.Namespace) != route.GetNamespace() {
 		if !t.validateCrossNamespaceRef(
@@ -155,7 +156,7 @@ func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef,
 			},
 			crossNamespaceTo{
 				group:     GroupDerefOr(backendRef.Group, ""),
-				kind:      KindDerefOr(backendRef.Kind, KindService),
+				kind:      KindDerefOr(backendRef.Kind, resource.KindService),
 				namespace: string(*backendRef.Namespace),
 				name:      string(backendRef.Name),
 			},
@@ -168,7 +169,7 @@ func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef,
 				gwapiv1.RouteConditionResolvedRefs,
 				metav1.ConditionFalse,
 				gwapiv1.RouteReasonRefNotPermitted,
-				fmt.Sprintf("Backend ref to %s %s/%s not permitted by any ReferenceGrant.", KindDerefOr(backendRef.Kind, KindService), *backendRef.Namespace, backendRef.Name),
+				fmt.Sprintf("Backend ref to %s %s/%s not permitted by any ReferenceGrant.", KindDerefOr(backendRef.Kind, resource.KindService), *backendRef.Namespace, backendRef.Name),
 			)
 			return false
 		}
@@ -196,7 +197,7 @@ func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, paren
 	return true
 }
 
-func validateBackendService(backendRef gwapiv1a2.BackendObjectReference, resources *Resources,
+func validateBackendService(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources,
 	serviceNamespace string, protocol corev1.Protocol,
 ) error {
 	service := resources.GetService(serviceNamespace, string(backendRef.Name))
@@ -223,7 +224,7 @@ func validateBackendService(backendRef gwapiv1a2.BackendObjectReference, resourc
 	return nil
 }
 
-func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *Resources,
+func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *resource.Resources,
 	serviceImportNamespace string, route RouteContext, protocol corev1.Protocol,
 ) bool {
 	serviceImport := resources.GetServiceImport(serviceImportNamespace, string(backendRef.Name))
@@ -268,7 +269,7 @@ func (t *Translator) validateBackendServiceImport(backendRef *gwapiv1a2.BackendR
 	return true
 }
 
-func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *Resources,
+func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, resources *resource.Resources,
 	backendNamespace string, route RouteContext, kind gwapiv1.Kind,
 ) bool {
 	// TODO: support additional route kinds
@@ -287,7 +288,7 @@ func (t *Translator) validateBackendRefBackend(backendRef *gwapiv1a2.BackendRef,
 		return false
 	}
 
-	if kind != KindHTTPRoute {
+	if kind != resource.KindHTTPRoute {
 		status.SetRouteStatusCondition(routeStatus,
 			parentRef.routeParentStatusIdx,
 			route.GetGeneration(),
@@ -428,7 +429,7 @@ func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) {
 	}
 }
 
-func (t *Translator) validateTerminateModeAndGetTLSSecrets(listener *ListenerContext, resources *Resources) []*corev1.Secret {
+func (t *Translator) validateTerminateModeAndGetTLSSecrets(listener *ListenerContext, resources *resource.Resources) []*corev1.Secret {
 	if len(listener.TLS.CertificateRefs) == 0 {
 		status.SetGatewayListenerStatusCondition(listener.gateway.Gateway,
 			listener.listenerStatusIdx,
@@ -454,13 +455,13 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets(listener *ListenerCon
 			break
 		}
 
-		if certificateRef.Kind != nil && string(*certificateRef.Kind) != KindSecret {
+		if certificateRef.Kind != nil && string(*certificateRef.Kind) != resource.KindSecret {
 			status.SetGatewayListenerStatusCondition(listener.gateway.Gateway,
 				listener.listenerStatusIdx,
 				gwapiv1.ListenerConditionResolvedRefs,
 				metav1.ConditionFalse,
 				gwapiv1.ListenerReasonInvalidCertificateRef,
-				fmt.Sprintf("Listener's TLS certificate ref kind must be %s.", KindSecret),
+				fmt.Sprintf("Listener's TLS certificate ref kind must be %s.", resource.KindSecret),
 			)
 			break
 		}
@@ -471,12 +472,12 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets(listener *ListenerCon
 			if !t.validateCrossNamespaceRef(
 				crossNamespaceFrom{
 					group:     gwapiv1.GroupName,
-					kind:      KindGateway,
+					kind:      resource.KindGateway,
 					namespace: listener.gateway.Namespace,
 				},
 				crossNamespaceTo{
 					group:     "",
-					kind:      KindSecret,
+					kind:      resource.KindSecret,
 					namespace: string(*certificateRef.Namespace),
 					name:      string(certificateRef.Name),
 				},
@@ -547,7 +548,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets(listener *ListenerCon
 	return secrets
 }
 
-func (t *Translator) validateTLSConfiguration(listener *ListenerContext, resources *Resources) {
+func (t *Translator) validateTLSConfiguration(listener *ListenerContext, resources *resource.Resources) {
 	switch listener.Protocol {
 	case gwapiv1.HTTPProtocolType, gwapiv1.UDPProtocolType, gwapiv1.TCPProtocolType:
 		if listener.TLS != nil {
@@ -914,7 +915,7 @@ func (t *Translator) validateSecretRef(
 	allowCrossNamespace bool,
 	from crossNamespaceFrom,
 	secretObjRef gwapiv1b1.SecretObjectReference,
-	resources *Resources,
+	resources *resource.Resources,
 ) (*corev1.Secret, error) {
 	if err := t.validateSecretObjectRef(allowCrossNamespace, from, secretObjRef, resources); err != nil {
 		return nil, err
@@ -938,7 +939,7 @@ func (t *Translator) validateConfigMapRef(
 	allowCrossNamespace bool,
 	from crossNamespaceFrom,
 	secretObjRef gwapiv1b1.SecretObjectReference,
-	resources *Resources,
+	resources *resource.Resources,
 ) (*corev1.ConfigMap, error) {
 	if err := t.validateSecretObjectRef(allowCrossNamespace, from, secretObjRef, resources); err != nil {
 		return nil, err
@@ -962,7 +963,7 @@ func (t *Translator) validateSecretObjectRef(
 	allowCrossNamespace bool,
 	from crossNamespaceFrom,
 	secretRef gwapiv1b1.SecretObjectReference,
-	resources *Resources,
+	resources *resource.Resources,
 ) error {
 	var kind string
 	if secretRef.Group != nil && string(*secretRef.Group) != "" {
@@ -970,13 +971,13 @@ func (t *Translator) validateSecretObjectRef(
 	}
 
 	if secretRef.Kind == nil { // nolint
-		kind = KindSecret
-	} else if string(*secretRef.Kind) == KindSecret {
-		kind = KindSecret
-	} else if string(*secretRef.Kind) == KindConfigMap {
-		kind = KindConfigMap
+		kind = resource.KindSecret
+	} else if string(*secretRef.Kind) == resource.KindSecret {
+		kind = resource.KindSecret
+	} else if string(*secretRef.Kind) == resource.KindConfigMap {
+		kind = resource.KindConfigMap
 	} else {
-		return fmt.Errorf("secret ref kind must be %s", KindSecret)
+		return fmt.Errorf("secret ref kind must be %s", resource.KindSecret)
 	}
 
 	if secretRef.Namespace != nil &&
@@ -1024,7 +1025,7 @@ func (t *Translator) validateExtServiceBackendReference(
 	backendRef *gwapiv1.BackendObjectReference,
 	ownerNamespace string,
 	policyKind string,
-	resources *Resources,
+	resources *resource.Resources,
 ) error {
 	// These are sanity checks, they should never happen because the API server
 	// should have caught them
@@ -1034,7 +1035,7 @@ func (t *Translator) validateExtServiceBackendReference(
 				" the group field or setting it to an empty string) and the" +
 				" gateway.envoyproxy.io API group are supported")
 	}
-	if backendRef.Kind != nil && *backendRef.Kind != KindService && *backendRef.Kind != egv1a1.KindBackend {
+	if backendRef.Kind != nil && *backendRef.Kind != resource.KindService && *backendRef.Kind != egv1a1.KindBackend {
 		return errors.New("kind is invalid, only Service (specified by omitting " +
 			"the kind field or setting it to 'Service') and Backend are supported")
 	}
@@ -1042,9 +1043,9 @@ func (t *Translator) validateExtServiceBackendReference(
 		return errors.New("a valid port number corresponding to a port on the Service must be specified")
 	}
 
-	backendRefKind := KindDerefOr(backendRef.Kind, KindService)
+	backendRefKind := KindDerefOr(backendRef.Kind, resource.KindService)
 	switch backendRefKind {
-	case KindService:
+	case resource.KindService:
 		// check if the service is valid
 		serviceNamespace := NamespaceDerefOr(backendRef.Namespace, ownerNamespace)
 		service := resources.GetService(serviceNamespace, string(backendRef.Name))
diff --git a/internal/kubernetes/secret.go b/internal/kubernetes/secret.go
index ff98d6187..f2774dce4 100644
--- a/internal/kubernetes/secret.go
+++ b/internal/kubernetes/secret.go
@@ -15,13 +15,13 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 // ValidateSecretObjectReference validate secret object reference for extension tls and ratelimit tls settings.
 func ValidateSecretObjectReference(ctx context.Context, client k8sclient.Client, secretObjRef *gwapiv1.SecretObjectReference, namespace string) (*corev1.Secret, string, error) {
 	if (secretObjRef.Group == nil || *secretObjRef.Group == corev1.GroupName) &&
-		(secretObjRef.Kind == nil || *secretObjRef.Kind == gatewayapi.KindSecret) {
+		(secretObjRef.Kind == nil || *secretObjRef.Kind == resource.KindSecret) {
 		secret := &corev1.Secret{}
 		secretNamespace := namespace
 		if secretObjRef.Namespace != nil && string(*secretObjRef.Namespace) != "" {
diff --git a/internal/message/types.go b/internal/message/types.go
index 6a39685a8..3e3923e6c 100644
--- a/internal/message/types.go
+++ b/internal/message/types.go
@@ -13,7 +13,7 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/ir"
 	xdstypes "github.com/envoyproxy/gateway/internal/xds/types"
 )
@@ -22,7 +22,7 @@ import (
 type ProviderResources struct {
 	// GatewayAPIResources is a map from a GatewayClass name to
 	// a group of gateway API and other related resources.
-	GatewayAPIResources watchable.Map[string, *gatewayapi.ControllerResources]
+	GatewayAPIResources watchable.Map[string, *resource.ControllerResources]
 
 	// GatewayAPIStatuses is a group of gateway api
 	// resource statuses maps.
@@ -35,7 +35,7 @@ type ProviderResources struct {
 	ExtensionStatuses
 }
 
-func (p *ProviderResources) GetResources() []*gatewayapi.Resources {
+func (p *ProviderResources) GetResources() []*resource.Resources {
 	if p.GatewayAPIResources.Len() == 0 {
 		return nil
 	}
@@ -47,7 +47,7 @@ func (p *ProviderResources) GetResources() []*gatewayapi.Resources {
 	return nil
 }
 
-func (p *ProviderResources) GetResourcesByGatewayClass(name string) *gatewayapi.Resources {
+func (p *ProviderResources) GetResourcesByGatewayClass(name string) *resource.Resources {
 	for _, r := range p.GetResources() {
 		if r != nil && r.GatewayClass != nil && r.GatewayClass.Name == name {
 			return r
diff --git a/internal/provider/file/resources.go b/internal/provider/file/resources.go
index 8dcd60ac7..a89f3ae16 100644
--- a/internal/provider/file/resources.go
+++ b/internal/provider/file/resources.go
@@ -9,26 +9,14 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
-	"reflect"
 	"strings"
 
-	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/util/sets"
-	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/envoygateway"
-	"github.com/envoyproxy/gateway/internal/envoygateway/config"
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 // loadFromFilesAndDirs loads resources from specific files and directories.
-func loadFromFilesAndDirs(files, dirs []string) ([]*gatewayapi.Resources, error) {
-	var rs []*gatewayapi.Resources
+func loadFromFilesAndDirs(files, dirs []string) ([]*resource.Resources, error) {
+	var rs []*resource.Resources
 
 	for _, file := range files {
 		r, err := loadFromFile(file)
@@ -50,7 +38,7 @@ func loadFromFilesAndDirs(files, dirs []string) ([]*gatewayapi.Resources, error)
 }
 
 // loadFromFile loads resources from a specific file.
-func loadFromFile(path string) (*gatewayapi.Resources, error) {
+func loadFromFile(path string) (*resource.Resources, error) {
 	if _, err := os.Stat(path); err != nil {
 		if os.IsNotExist(err) {
 			return nil, fmt.Errorf("file %s is not exist", path)
@@ -63,17 +51,17 @@ func loadFromFile(path string) (*gatewayapi.Resources, error) {
 		return nil, err
 	}
 
-	return convertKubernetesYAMLToResources(string(bytes))
+	return resource.LoadResourcesFromYAMLString(string(bytes), false)
 }
 
 // loadFromDir loads resources from all the files under a specific directory excluding subdirectories.
-func loadFromDir(path string) ([]*gatewayapi.Resources, error) {
+func loadFromDir(path string) ([]*resource.Resources, error) {
 	entries, err := os.ReadDir(path)
 	if err != nil {
 		return nil, err
 	}
 
-	var rs []*gatewayapi.Resources
+	var rs []*resource.Resources
 	for _, entry := range entries {
 		// Ignoring subdirectories and all hidden files and directories.
 		if entry.IsDir() || strings.HasPrefix(entry.Name(), ".") {
@@ -90,246 +78,3 @@ func loadFromDir(path string) ([]*gatewayapi.Resources, error) {
 
 	return rs, nil
 }
-
-// TODO(sh2): This function is copied and updated from internal/cmd/egctl/translate.go.
-// This function should be able to process arbitrary number of resources, so we
-// need to come up with a way to extend the GatewayClass and EnvoyProxy field to array
-// instead of single variable in gatewayapi.Resources structure.
-//
-// - This issue is tracked by https://github.com/envoyproxy/gateway/issues/3207
-//
-// convertKubernetesYAMLToResources converts a Kubernetes YAML string into GatewayAPI Resources.
-func convertKubernetesYAMLToResources(str string) (*gatewayapi.Resources, error) {
-	resources := gatewayapi.NewResources()
-	var useDefaultNamespace bool
-	providedNamespaceMap := sets.New[string]()
-	requiredNamespaceMap := sets.New[string]()
-	yamls := strings.Split(str, "\n---")
-	combinedScheme := envoygateway.GetScheme()
-	for _, y := range yamls {
-		if strings.TrimSpace(y) == "" {
-			continue
-		}
-		var obj map[string]interface{}
-		err := yaml.Unmarshal([]byte(y), &obj)
-		if err != nil {
-			return nil, err
-		}
-		un := unstructured.Unstructured{Object: obj}
-		gvk := un.GroupVersionKind()
-		name, namespace := un.GetName(), un.GetNamespace()
-		if namespace == "" {
-			// When kubectl applies a resource in yaml which doesn't have a namespace,
-			// the current namespace is applied. Here we do the same thing before translating
-			// the GatewayAPI resource. Otherwise, the resource can't pass the namespace validation
-			useDefaultNamespace = true
-			namespace = config.DefaultNamespace
-		}
-		requiredNamespaceMap.Insert(namespace)
-		kobj, err := combinedScheme.New(gvk)
-		if err != nil {
-			return nil, err
-		}
-		err = combinedScheme.Convert(&un, kobj, nil)
-		if err != nil {
-			return nil, err
-		}
-
-		objType := reflect.TypeOf(kobj)
-		if objType.Kind() != reflect.Ptr {
-			return nil, fmt.Errorf("expected pointer type, but got %s", objType.Kind().String())
-		}
-		kobjVal := reflect.ValueOf(kobj).Elem()
-		spec := kobjVal.FieldByName("Spec")
-
-		switch gvk.Kind {
-		case gatewayapi.KindEnvoyProxy:
-			typedSpec := spec.Interface()
-			envoyProxy := &egv1a1.EnvoyProxy{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(egv1a1.EnvoyProxySpec),
-			}
-			resources.EnvoyProxyForGatewayClass = envoyProxy
-		case gatewayapi.KindGatewayClass:
-			typedSpec := spec.Interface()
-			gatewayClass := &gwapiv1.GatewayClass{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GatewayClassSpec),
-			}
-			// fill controller name by default controller name when gatewayclass controller name empty.
-			if gatewayClass.Spec.ControllerName == "" {
-				gatewayClass.Spec.ControllerName = egv1a1.GatewayControllerName
-			}
-			resources.GatewayClass = gatewayClass
-		case gatewayapi.KindGateway:
-			typedSpec := spec.Interface()
-			gateway := &gwapiv1.Gateway{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GatewaySpec),
-			}
-			resources.Gateways = append(resources.Gateways, gateway)
-		case gatewayapi.KindTCPRoute:
-			typedSpec := spec.Interface()
-			tcpRoute := &gwapiv1a2.TCPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindTCPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.TCPRouteSpec),
-			}
-			resources.TCPRoutes = append(resources.TCPRoutes, tcpRoute)
-		case gatewayapi.KindUDPRoute:
-			typedSpec := spec.Interface()
-			udpRoute := &gwapiv1a2.UDPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindUDPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.UDPRouteSpec),
-			}
-			resources.UDPRoutes = append(resources.UDPRoutes, udpRoute)
-		case gatewayapi.KindTLSRoute:
-			typedSpec := spec.Interface()
-			tlsRoute := &gwapiv1a2.TLSRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindTLSRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1a2.TLSRouteSpec),
-			}
-			resources.TLSRoutes = append(resources.TLSRoutes, tlsRoute)
-		case gatewayapi.KindHTTPRoute:
-			typedSpec := spec.Interface()
-			httpRoute := &gwapiv1.HTTPRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindHTTPRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.HTTPRouteSpec),
-			}
-			resources.HTTPRoutes = append(resources.HTTPRoutes, httpRoute)
-		case gatewayapi.KindGRPCRoute:
-			typedSpec := spec.Interface()
-			grpcRoute := &gwapiv1.GRPCRoute{
-				TypeMeta: metav1.TypeMeta{
-					Kind: gatewayapi.KindGRPCRoute,
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(gwapiv1.GRPCRouteSpec),
-			}
-			resources.GRPCRoutes = append(resources.GRPCRoutes, grpcRoute)
-		case gatewayapi.KindNamespace:
-			namespace := &corev1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: name,
-				},
-			}
-			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap.Insert(name)
-		case gatewayapi.KindService:
-			typedSpec := spec.Interface()
-			service := &corev1.Service{
-				ObjectMeta: metav1.ObjectMeta{
-					Name:      name,
-					Namespace: namespace,
-				},
-				Spec: typedSpec.(corev1.ServiceSpec),
-			}
-			resources.Services = append(resources.Services, service)
-		case egv1a1.KindEnvoyPatchPolicy:
-			typedSpec := spec.Interface()
-			envoyPatchPolicy := &egv1a1.EnvoyPatchPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindEnvoyPatchPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.EnvoyPatchPolicySpec),
-			}
-			resources.EnvoyPatchPolicies = append(resources.EnvoyPatchPolicies, envoyPatchPolicy)
-		case egv1a1.KindClientTrafficPolicy:
-			typedSpec := spec.Interface()
-			clientTrafficPolicy := &egv1a1.ClientTrafficPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindClientTrafficPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.ClientTrafficPolicySpec),
-			}
-			resources.ClientTrafficPolicies = append(resources.ClientTrafficPolicies, clientTrafficPolicy)
-		case egv1a1.KindBackendTrafficPolicy:
-			typedSpec := spec.Interface()
-			backendTrafficPolicy := &egv1a1.BackendTrafficPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindBackendTrafficPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.BackendTrafficPolicySpec),
-			}
-			resources.BackendTrafficPolicies = append(resources.BackendTrafficPolicies, backendTrafficPolicy)
-		case egv1a1.KindSecurityPolicy:
-			typedSpec := spec.Interface()
-			securityPolicy := &egv1a1.SecurityPolicy{
-				TypeMeta: metav1.TypeMeta{
-					Kind:       egv1a1.KindSecurityPolicy,
-					APIVersion: egv1a1.GroupVersion.String(),
-				},
-				ObjectMeta: metav1.ObjectMeta{
-					Namespace: namespace,
-					Name:      name,
-				},
-				Spec: typedSpec.(egv1a1.SecurityPolicySpec),
-			}
-			resources.SecurityPolicies = append(resources.SecurityPolicies, securityPolicy)
-		}
-	}
-
-	if useDefaultNamespace {
-		if !providedNamespaceMap.Has(config.DefaultNamespace) {
-			namespace := &corev1.Namespace{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: config.DefaultNamespace,
-				},
-			}
-			resources.Namespaces = append(resources.Namespaces, namespace)
-			providedNamespaceMap.Insert(config.DefaultNamespace)
-		}
-	}
-
-	return resources, nil
-}
diff --git a/internal/provider/file/store.go b/internal/provider/file/store.go
index 5a45f1fd6..90c520564 100644
--- a/internal/provider/file/store.go
+++ b/internal/provider/file/store.go
@@ -9,7 +9,7 @@ import (
 	"github.com/fsnotify/fsnotify"
 	"github.com/go-logr/logr"
 
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/message"
 )
 
@@ -46,7 +46,7 @@ func (r *resourcesStore) HandleEvent(event fsnotify.Event, files, dirs []string)
 
 // LoadAndStore loads and stores all resources from files and directories.
 func (r *resourcesStore) LoadAndStore(files, dirs []string) error {
-	rs, err := loadFromFilesAndDirs(files, dirs)
+	resources, err := loadFromFilesAndDirs(files, dirs)
 	if err != nil {
 		return err
 	}
@@ -61,10 +61,10 @@ func (r *resourcesStore) LoadAndStore(files, dirs []string) error {
 
 	// We cannot make sure by the time the Write event was triggered, whether the GatewayClass exist,
 	// so here we just simply Store the first gatewayapi.Resources that has GatewayClass.
-	gwcResources := make(gatewayapi.ControllerResources, 0, 1)
-	for _, resource := range rs {
-		if resource.GatewayClass != nil {
-			gwcResources = append(gwcResources, resource)
+	gwcResources := make(resource.ControllerResources, 0, 1)
+	for _, res := range resources {
+		if res.GatewayClass != nil {
+			gwcResources = append(gwcResources, res)
 		}
 	}
 	if len(gwcResources) == 0 {
diff --git a/internal/provider/kubernetes/controller.go b/internal/provider/kubernetes/controller.go
index 1c0555c07..a07ca6ab1 100644
--- a/internal/provider/kubernetes/controller.go
+++ b/internal/provider/kubernetes/controller.go
@@ -38,6 +38,7 @@ import (
 	"github.com/envoyproxy/gateway/api/v1alpha1/validation"
 	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
 	"github.com/envoyproxy/gateway/internal/logging"
 	"github.com/envoyproxy/gateway/internal/message"
@@ -193,10 +194,10 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, _ reconcile.Reques
 	// - Gateway API resources: Gateways, xRoutes ...
 	// - Envoy Gateway customized resources: EnvoyPatchPolicies, ClientTrafficPolicies, BackendTrafficPolicies ...
 	// - Referenced resources: Services, ServiceImports, EndpointSlices, Secrets, ConfigMaps ...
-	gwcResources := make(gatewayapi.ControllerResources, 0, len(managedGCs))
+	gwcResources := make(resource.ControllerResources, 0, len(managedGCs))
 	for _, managedGC := range managedGCs {
 		// Initialize resource types.
-		gwcResource := gatewayapi.NewResources()
+		gwcResource := resource.NewResources()
 		gwcResource.GatewayClass = managedGC
 		gwcResources = append(gwcResources, gwcResource)
 		resourceMappings := newResourceMapping()
@@ -322,7 +323,7 @@ func (r *gatewayAPIReconciler) Reconcile(ctx context.Context, _ reconcile.Reques
 	return reconcile.Result{}, nil
 }
 
-func (r *gatewayAPIReconciler) processEnvoyProxySecretRef(ctx context.Context, gwcResource *gatewayapi.Resources) {
+func (r *gatewayAPIReconciler) processEnvoyProxySecretRef(ctx context.Context, gwcResource *resource.Resources) {
 	if gwcResource.EnvoyProxyForGatewayClass == nil || gwcResource.EnvoyProxyForGatewayClass.Spec.BackendTLS == nil || gwcResource.EnvoyProxyForGatewayClass.Spec.BackendTLS.ClientCertificateRef == nil {
 		return
 	}
@@ -332,9 +333,9 @@ func (r *gatewayAPIReconciler) processEnvoyProxySecretRef(ctx context.Context, g
 			ctx,
 			newResourceMapping(),
 			gwcResource,
-			gatewayapi.KindGateway,
+			resource.KindGateway,
 			gwcResource.EnvoyProxyForGatewayClass.Namespace,
-			gatewayapi.KindEnvoyProxy,
+			resource.KindEnvoyProxy,
 			*certRef); err != nil {
 			r.log.Error(err,
 				"failed to process TLS SecretRef for EnvoyProxy",
@@ -375,15 +376,15 @@ func (r *gatewayAPIReconciler) managedGatewayClasses(ctx context.Context) ([]*gw
 // - ServiceImports
 // - EndpointSlices
 // - Backends
-func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResource *gatewayapi.Resources, resourceMappings *resourceMappings) {
+func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResource *resource.Resources, resourceMappings *resourceMappings) {
 	for backendRef := range resourceMappings.allAssociatedBackendRefs {
-		backendRefKind := gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService)
+		backendRefKind := gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService)
 		r.log.Info("processing Backend", "kind", backendRefKind, "namespace", string(*backendRef.Namespace),
 			"name", string(backendRef.Name))
 
 		var endpointSliceLabelKey string
 		switch backendRefKind {
-		case gatewayapi.KindService:
+		case resource.KindService:
 			service := new(corev1.Service)
 			err := r.client.Get(ctx, types.NamespacedName{Namespace: string(*backendRef.Namespace), Name: string(backendRef.Name)}, service)
 			if err != nil {
@@ -397,7 +398,7 @@ func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResour
 			}
 			endpointSliceLabelKey = discoveryv1.LabelServiceName
 
-		case gatewayapi.KindServiceImport:
+		case resource.KindServiceImport:
 			serviceImport := new(mcsapiv1a1.ServiceImport)
 			err := r.client.Get(ctx, types.NamespacedName{Namespace: string(*backendRef.Namespace), Name: string(backendRef.Name)}, serviceImport)
 			if err != nil {
@@ -454,7 +455,7 @@ func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResour
 // - Secrets for OIDC and BasicAuth
 // - BackendRefs for ExAuth
 func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) {
 	// we don't return errors from this method, because we want to continue reconciling
 	// the rest of the SecurityPolicies despite that one reference is invalid. This
@@ -472,7 +473,7 @@ func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
 				ctx,
 				resourceMap,
 				resourceTree,
-				gatewayapi.KindSecurityPolicy,
+				resource.KindSecurityPolicy,
 				policy.Namespace,
 				policy.Name,
 				oidc.ClientSecret); err != nil {
@@ -489,7 +490,7 @@ func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
 				ctx,
 				resourceMap,
 				resourceTree,
-				gatewayapi.KindSecurityPolicy,
+				resource.KindSecurityPolicy,
 				policy.Namespace,
 				policy.Name,
 				basicAuth.Users); err != nil {
@@ -529,12 +530,12 @@ func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
 
 			if backendNamespace != policy.Namespace {
 				from := ObjectKindNamespacedName{
-					kind:      gatewayapi.KindSecurityPolicy,
+					kind:      resource.KindSecurityPolicy,
 					namespace: policy.Namespace,
 					name:      policy.Name,
 				}
 				to := ObjectKindNamespacedName{
-					kind:      gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService),
+					kind:      gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService),
 					namespace: backendNamespace,
 					name:      string(backendRef.Name),
 				}
@@ -558,7 +559,7 @@ func (r *gatewayAPIReconciler) processSecurityPolicyObjectRefs(
 // processOIDCHMACSecret adds the OIDC HMAC Secret to the resourceTree.
 // The OIDC HMAC Secret is created by the CertGen job and is used by SecurityPolicy
 // to configure OAuth2 filters.
-func (r *gatewayAPIReconciler) processOIDCHMACSecret(ctx context.Context, resourceTree *gatewayapi.Resources) {
+func (r *gatewayAPIReconciler) processOIDCHMACSecret(ctx context.Context, resourceTree *resource.Resources) {
 	var (
 		secret corev1.Secret
 		err    error
@@ -589,7 +590,7 @@ func (r *gatewayAPIReconciler) processOIDCHMACSecret(ctx context.Context, resour
 func (r *gatewayAPIReconciler) processSecretRef(
 	ctx context.Context,
 	resourceMap *resourceMappings,
-	resourceTree *gatewayapi.Resources,
+	resourceTree *resource.Resources,
 	ownerKind string,
 	ownerNS string,
 	ownerName string,
@@ -612,7 +613,7 @@ func (r *gatewayAPIReconciler) processSecretRef(
 			name:      ownerName,
 		}
 		to := ObjectKindNamespacedName{
-			kind:      gatewayapi.KindSecret,
+			kind:      resource.KindSecret,
 			namespace: secretNS,
 			name:      secret.Name,
 		}
@@ -640,19 +641,19 @@ func (r *gatewayAPIReconciler) processSecretRef(
 // processCtpConfigMapRefs adds the referenced ConfigMaps in ClientTrafficPolicies
 // to the resourceTree
 func (r *gatewayAPIReconciler) processCtpConfigMapRefs(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) {
 	for _, policy := range resourceTree.ClientTrafficPolicies {
 		tls := policy.Spec.TLS
 
 		if tls != nil && tls.ClientValidation != nil {
 			for _, caCertRef := range tls.ClientValidation.CACertificateRefs {
-				if caCertRef.Kind != nil && string(*caCertRef.Kind) == gatewayapi.KindConfigMap {
+				if caCertRef.Kind != nil && string(*caCertRef.Kind) == resource.KindConfigMap {
 					if err := r.processConfigMapRef(
 						ctx,
 						resourceMap,
 						resourceTree,
-						gatewayapi.KindClientTrafficPolicy,
+						resource.KindClientTrafficPolicy,
 						policy.Namespace,
 						policy.Name,
 						caCertRef); err != nil {
@@ -666,12 +667,12 @@ func (r *gatewayAPIReconciler) processCtpConfigMapRefs(
 							"failed to process CACertificateRef for ClientTrafficPolicy",
 							"policy", policy, "caCertificateRef", caCertRef.Name)
 					}
-				} else if caCertRef.Kind == nil || string(*caCertRef.Kind) == gatewayapi.KindSecret {
+				} else if caCertRef.Kind == nil || string(*caCertRef.Kind) == resource.KindSecret {
 					if err := r.processSecretRef(
 						ctx,
 						resourceMap,
 						resourceTree,
-						gatewayapi.KindClientTrafficPolicy,
+						resource.KindClientTrafficPolicy,
 						policy.Namespace,
 						policy.Name,
 						caCertRef); err != nil {
@@ -691,7 +692,7 @@ func (r *gatewayAPIReconciler) processCtpConfigMapRefs(
 func (r *gatewayAPIReconciler) processConfigMapRef(
 	ctx context.Context,
 	resourceMap *resourceMappings,
-	resourceTree *gatewayapi.Resources,
+	resourceTree *resource.Resources,
 	ownerKind string,
 	ownerNS string,
 	ownerName string,
@@ -714,7 +715,7 @@ func (r *gatewayAPIReconciler) processConfigMapRef(
 			name:      ownerName,
 		}
 		to := ObjectKindNamespacedName{
-			kind:      gatewayapi.KindConfigMap,
+			kind:      resource.KindConfigMap,
 			namespace: configMapNS,
 			name:      configMap.Name,
 		}
@@ -807,7 +808,7 @@ func (r *gatewayAPIReconciler) findReferenceGrant(ctx context.Context, from, to
 	return nil, nil
 }
 
-func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *gwapiv1.GatewayClass, resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *gwapiv1.GatewayClass, resourceMap *resourceMappings, resourceTree *resource.Resources) error {
 	// Find gateways for the managedGC
 	// Find the Gateways that reference this Class.
 	gatewayList := &gwapiv1.GatewayList{}
@@ -844,7 +845,7 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g
 							ctx,
 							resourceMap,
 							resourceTree,
-							gatewayapi.KindGateway,
+							resource.KindGateway,
 							gtw.Namespace,
 							gtw.Name,
 							certRef); err != nil {
@@ -893,7 +894,7 @@ func (r *gatewayAPIReconciler) processGateways(ctx context.Context, managedGC *g
 }
 
 // processEnvoyPatchPolicies adds EnvoyPatchPolicies to the resourceTree
-func (r *gatewayAPIReconciler) processEnvoyPatchPolicies(ctx context.Context, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processEnvoyPatchPolicies(ctx context.Context, resourceTree *resource.Resources) error {
 	envoyPatchPolicies := egv1a1.EnvoyPatchPolicyList{}
 	if err := r.client.List(ctx, &envoyPatchPolicies); err != nil {
 		return fmt.Errorf("error listing EnvoyPatchPolicies: %w", err)
@@ -912,7 +913,7 @@ func (r *gatewayAPIReconciler) processEnvoyPatchPolicies(ctx context.Context, re
 
 // processClientTrafficPolicies adds ClientTrafficPolicies to the resourceTree
 func (r *gatewayAPIReconciler) processClientTrafficPolicies(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) error {
 	clientTrafficPolicies := egv1a1.ClientTrafficPolicyList{}
 	if err := r.client.List(ctx, &clientTrafficPolicies); err != nil {
@@ -933,7 +934,7 @@ func (r *gatewayAPIReconciler) processClientTrafficPolicies(
 }
 
 // processBackendTrafficPolicies adds BackendTrafficPolicies to the resourceTree
-func (r *gatewayAPIReconciler) processBackendTrafficPolicies(ctx context.Context, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processBackendTrafficPolicies(ctx context.Context, resourceTree *resource.Resources) error {
 	backendTrafficPolicies := egv1a1.BackendTrafficPolicyList{}
 	if err := r.client.List(ctx, &backendTrafficPolicies); err != nil {
 		return fmt.Errorf("error listing BackendTrafficPolicies: %w", err)
@@ -951,7 +952,7 @@ func (r *gatewayAPIReconciler) processBackendTrafficPolicies(ctx context.Context
 
 // processSecurityPolicies adds SecurityPolicies and their referenced resources to the resourceTree
 func (r *gatewayAPIReconciler) processSecurityPolicies(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) error {
 	securityPolicies := egv1a1.SecurityPolicyList{}
 	if err := r.client.List(ctx, &securityPolicies); err != nil {
@@ -976,7 +977,7 @@ func (r *gatewayAPIReconciler) processSecurityPolicies(
 
 // processBackendTLSPolicies adds BackendTLSPolicies and their referenced resources to the resourceTree
 func (r *gatewayAPIReconciler) processBackendTLSPolicies(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) error {
 	backendTLSPolicies := gwapiv1a3.BackendTLSPolicyList{}
 	if err := r.client.List(ctx, &backendTLSPolicies); err != nil {
@@ -997,7 +998,7 @@ func (r *gatewayAPIReconciler) processBackendTLSPolicies(
 }
 
 // processBackends adds Backends to the resourceTree
-func (r *gatewayAPIReconciler) processBackends(ctx context.Context, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processBackends(ctx context.Context, resourceTree *resource.Resources) error {
 	backends := egv1a1.BackendList{}
 	if err := r.client.List(ctx, &backends); err != nil {
 		return fmt.Errorf("error listing Backends: %w", err)
@@ -1571,7 +1572,7 @@ func (r *gatewayAPIReconciler) enqueueClass(_ context.Context, _ client.Object)
 }
 
 // processGatewayParamsRef processes the infrastructure.parametersRef of the provided Gateway.
-func (r *gatewayAPIReconciler) processGatewayParamsRef(ctx context.Context, gtw *gwapiv1.Gateway, resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processGatewayParamsRef(ctx context.Context, gtw *gwapiv1.Gateway, resourceMap *resourceMappings, resourceTree *resource.Resources) error {
 	if gtw == nil || gtw.Spec.Infrastructure == nil || gtw.Spec.Infrastructure.ParametersRef == nil {
 		return nil
 	}
@@ -1603,7 +1604,7 @@ func (r *gatewayAPIReconciler) processGatewayParamsRef(ctx context.Context, gtw
 				ctx,
 				resourceMap,
 				resourceTree,
-				gatewayapi.KindGateway,
+				resource.KindGateway,
 				gtw.Namespace,
 				gtw.Name,
 				*certRef); err != nil {
@@ -1619,7 +1620,7 @@ func (r *gatewayAPIReconciler) processGatewayParamsRef(ctx context.Context, gtw
 }
 
 // processGatewayClassParamsRef processes the parametersRef of the provided GatewayClass.
-func (r *gatewayAPIReconciler) processGatewayClassParamsRef(ctx context.Context, gc *gwapiv1.GatewayClass, resourceMap *resourceMappings, resourceTree *gatewayapi.Resources) error {
+func (r *gatewayAPIReconciler) processGatewayClassParamsRef(ctx context.Context, gc *gwapiv1.GatewayClass, resourceMap *resourceMappings, resourceTree *resource.Resources) error {
 	if !refsEnvoyProxy(gc) {
 		return fmt.Errorf("unsupported parametersRef for gatewayclass %s", gc.Name)
 	}
@@ -1712,8 +1713,8 @@ func (r *gatewayAPIReconciler) serviceImportCRDExists(mgr manager.Manager) bool
 	}
 	serviceImportFound := false
 	for _, list := range apiResourceList {
-		for _, resource := range list.APIResources {
-			if list.GroupVersion == mcsapiv1a1.GroupVersion.String() && resource.Kind == gatewayapi.KindServiceImport {
+		for _, res := range list.APIResources {
+			if list.GroupVersion == mcsapiv1a1.GroupVersion.String() && res.Kind == resource.KindServiceImport {
 				serviceImportFound = true
 				break
 			}
@@ -1725,7 +1726,7 @@ func (r *gatewayAPIReconciler) serviceImportCRDExists(mgr manager.Manager) bool
 
 func (r *gatewayAPIReconciler) processBackendTLSPolicyRefs(
 	ctx context.Context,
-	resourceTree *gatewayapi.Resources,
+	resourceTree *resource.Resources,
 	resourceMap *resourceMappings,
 ) {
 	for _, policy := range resourceTree.BackendTLSPolicies {
@@ -1734,8 +1735,8 @@ func (r *gatewayAPIReconciler) processBackendTLSPolicyRefs(
 		if tls.CACertificateRefs != nil {
 			for _, caCertRef := range tls.CACertificateRefs {
 				// if kind is not Secret or ConfigMap, we skip early to avoid further calculation overhead
-				if string(caCertRef.Kind) == gatewayapi.KindConfigMap ||
-					string(caCertRef.Kind) == gatewayapi.KindSecret {
+				if string(caCertRef.Kind) == resource.KindConfigMap ||
+					string(caCertRef.Kind) == resource.KindSecret {
 
 					var err error
 					caRefNew := gwapiv1b1.SecretObjectReference{
@@ -1745,22 +1746,22 @@ func (r *gatewayAPIReconciler) processBackendTLSPolicyRefs(
 						Namespace: gatewayapi.NamespacePtr(policy.Namespace),
 					}
 					switch string(caCertRef.Kind) {
-					case gatewayapi.KindConfigMap:
+					case resource.KindConfigMap:
 						err = r.processConfigMapRef(
 							ctx,
 							resourceMap,
 							resourceTree,
-							gatewayapi.KindBackendTLSPolicy,
+							resource.KindBackendTLSPolicy,
 							policy.Namespace,
 							policy.Name,
 							caRefNew)
 
-					case gatewayapi.KindSecret:
+					case resource.KindSecret:
 						err = r.processSecretRef(
 							ctx,
 							resourceMap,
 							resourceTree,
-							gatewayapi.KindBackendTLSPolicy,
+							resource.KindBackendTLSPolicy,
 							policy.Namespace,
 							policy.Name,
 							caRefNew)
@@ -1784,7 +1785,7 @@ func (r *gatewayAPIReconciler) processBackendTLSPolicyRefs(
 
 // processEnvoyExtensionPolicies adds EnvoyExtensionPolicies and their referenced resources to the resourceTree
 func (r *gatewayAPIReconciler) processEnvoyExtensionPolicies(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) error {
 	envoyExtensionPolicies := egv1a1.EnvoyExtensionPolicyList{}
 	if err := r.client.List(ctx, &envoyExtensionPolicies); err != nil {
@@ -1807,7 +1808,7 @@ func (r *gatewayAPIReconciler) processEnvoyExtensionPolicies(
 
 // processExtensionServerPolicies adds directly attached policies intended for the extension server
 func (r *gatewayAPIReconciler) processExtensionServerPolicies(
-	ctx context.Context, resourceTree *gatewayapi.Resources,
+	ctx context.Context, resourceTree *resource.Resources,
 ) error {
 	for _, gvk := range r.extServerPolicies {
 		polList := unstructured.UnstructuredList{}
@@ -1843,7 +1844,7 @@ func (r *gatewayAPIReconciler) processExtensionServerPolicies(
 // - BackendRefs for ExtProcs
 // - SecretRefs for Wasms
 func (r *gatewayAPIReconciler) processEnvoyExtensionPolicyObjectRefs(
-	ctx context.Context, resourceTree *gatewayapi.Resources, resourceMap *resourceMappings,
+	ctx context.Context, resourceTree *resource.Resources, resourceMap *resourceMappings,
 ) {
 	// we don't return errors from this method, because we want to continue reconciling
 	// the rest of the EnvoyExtensionPolicies despite that one reference is invalid. This
@@ -1868,12 +1869,12 @@ func (r *gatewayAPIReconciler) processEnvoyExtensionPolicyObjectRefs(
 
 				if backendNamespace != policy.Namespace {
 					from := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindHTTPRoute,
+						kind:      resource.KindHTTPRoute,
 						namespace: policy.Namespace,
 						name:      policy.Name,
 					}
 					to := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService),
+						kind:      gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService),
 						namespace: backendNamespace,
 						name:      string(backendRef.Name),
 					}
@@ -1900,7 +1901,7 @@ func (r *gatewayAPIReconciler) processEnvoyExtensionPolicyObjectRefs(
 					ctx,
 					resourceMap,
 					resourceTree,
-					gatewayapi.KindSecurityPolicy,
+					resource.KindSecurityPolicy,
 					policy.Namespace,
 					policy.Name,
 					*wasm.Code.Image.PullSecretRef); err != nil {
diff --git a/internal/provider/kubernetes/helpers.go b/internal/provider/kubernetes/helpers.go
index 847bdc352..0069aba5c 100644
--- a/internal/provider/kubernetes/helpers.go
+++ b/internal/provider/kubernetes/helpers.go
@@ -18,6 +18,7 @@ import (
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 const (
@@ -141,7 +142,7 @@ func terminatesTLS(listener *gwapiv1.Listener) bool {
 // refsSecret returns true if ref refers to a Secret.
 func refsSecret(ref *gwapiv1.SecretObjectReference) bool {
 	return (ref.Group == nil || *ref.Group == corev1.GroupName) &&
-		(ref.Kind == nil || *ref.Kind == gatewayapi.KindSecret)
+		(ref.Kind == nil || *ref.Kind == resource.KindSecret)
 }
 
 // validateBackendRef validates that ref is a reference to a local Service.
@@ -155,9 +156,9 @@ func validateBackendRef(ref *gwapiv1.BackendRef) error {
 		return nil
 	case gatewayapi.GroupDerefOr(ref.Group, corev1.GroupName) != corev1.GroupName && gatewayapi.GroupDerefOr(ref.Group, corev1.GroupName) != mcsapiv1a1.GroupName && gatewayapi.GroupDerefOr(ref.Group, corev1.GroupName) != egv1a1.GroupName:
 		return fmt.Errorf("invalid group; must be nil, empty string %q or %q", mcsapiv1a1.GroupName, egv1a1.GroupName)
-	case gatewayapi.KindDerefOr(ref.Kind, gatewayapi.KindService) != gatewayapi.KindService && gatewayapi.KindDerefOr(ref.Kind, gatewayapi.KindService) != gatewayapi.KindServiceImport && gatewayapi.KindDerefOr(ref.Kind, gatewayapi.KindService) != egv1a1.KindBackend:
+	case gatewayapi.KindDerefOr(ref.Kind, resource.KindService) != resource.KindService && gatewayapi.KindDerefOr(ref.Kind, resource.KindService) != resource.KindServiceImport && gatewayapi.KindDerefOr(ref.Kind, resource.KindService) != egv1a1.KindBackend:
 		return fmt.Errorf("invalid kind %q; must be %q, %q or %q",
-			*ref.BackendObjectReference.Kind, gatewayapi.KindService, gatewayapi.KindServiceImport, egv1a1.KindBackend)
+			*ref.BackendObjectReference.Kind, resource.KindService, resource.KindServiceImport, egv1a1.KindBackend)
 	}
 
 	return nil
diff --git a/internal/provider/kubernetes/indexers.go b/internal/provider/kubernetes/indexers.go
index 443c667e3..395b1c680 100644
--- a/internal/provider/kubernetes/indexers.go
+++ b/internal/provider/kubernetes/indexers.go
@@ -19,6 +19,7 @@ import (
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 const (
@@ -79,7 +80,7 @@ func gatewayHTTPRouteIndexFunc(rawObj client.Object) []string {
 	httproute := rawObj.(*gwapiv1.HTTPRoute)
 	var gateways []string
 	for _, parent := range httproute.Spec.ParentRefs {
-		if parent.Kind == nil || string(*parent.Kind) == gatewayapi.KindGateway {
+		if parent.Kind == nil || string(*parent.Kind) == resource.KindGateway {
 			// If an explicit Gateway namespace is not provided, use the HTTPRoute namespace to
 			// lookup the provided Gateway Name.
 			gateways = append(gateways,
@@ -98,7 +99,7 @@ func backendHTTPRouteIndexFunc(rawObj client.Object) []string {
 	var backendRefs []string
 	for _, rule := range httproute.Spec.Rules {
 		for _, backend := range rule.BackendRefs {
-			if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService || string(*backend.Kind) == egv1a1.KindBackend {
+			if backend.Kind == nil || string(*backend.Kind) == resource.KindService || string(*backend.Kind) == egv1a1.KindBackend {
 				// If an explicit Backend namespace is not provided, use the HTTPRoute namespace to
 				// lookup the provided Gateway Name.
 				backendRefs = append(backendRefs,
@@ -118,7 +119,7 @@ func secretEnvoyProxyIndexFunc(rawObj client.Object) []string {
 	var secretReferences []string
 	if ep.Spec.BackendTLS != nil {
 		if ep.Spec.BackendTLS.ClientCertificateRef != nil {
-			if *ep.Spec.BackendTLS.ClientCertificateRef.Kind == gatewayapi.KindSecret {
+			if *ep.Spec.BackendTLS.ClientCertificateRef.Kind == resource.KindSecret {
 				secretReferences = append(secretReferences,
 					types.NamespacedName{
 						Namespace: gatewayapi.NamespaceDerefOr(ep.Spec.BackendTLS.ClientCertificateRef.Namespace, ep.Namespace),
@@ -172,7 +173,7 @@ func accessLogRefs(ep *egv1a1.EnvoyProxy) []string {
 			}
 
 			for _, ref := range backendRefs {
-				if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService {
+				if ref.Kind == nil || string(*ref.Kind) == resource.KindService {
 					refs = append(refs,
 						types.NamespacedName{
 							Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace),
@@ -197,7 +198,7 @@ func metricRefs(ep *egv1a1.EnvoyProxy) []string {
 	for _, sink := range ep.Spec.Telemetry.Metrics.Sinks {
 		if sink.OpenTelemetry != nil {
 			for _, backend := range sink.OpenTelemetry.BackendRefs {
-				if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService {
+				if backend.Kind == nil || string(*backend.Kind) == resource.KindService {
 					refs = append(refs,
 						types.NamespacedName{
 							Namespace: gatewayapi.NamespaceDerefOr(backend.Namespace, ep.Namespace),
@@ -220,7 +221,7 @@ func traceRefs(ep *egv1a1.EnvoyProxy) []string {
 	}
 
 	for _, ref := range ep.Spec.Telemetry.Tracing.Provider.BackendRefs {
-		if ref.Kind == nil || string(*ref.Kind) == gatewayapi.KindService {
+		if ref.Kind == nil || string(*ref.Kind) == resource.KindService {
 			refs = append(refs,
 				types.NamespacedName{
 					Namespace: gatewayapi.NamespaceDerefOr(ref.Namespace, ep.Namespace),
@@ -252,7 +253,7 @@ func gatewayGRPCRouteIndexFunc(rawObj client.Object) []string {
 	grpcroute := rawObj.(*gwapiv1.GRPCRoute)
 	var gateways []string
 	for _, parent := range grpcroute.Spec.ParentRefs {
-		if parent.Kind == nil || string(*parent.Kind) == gatewayapi.KindGateway {
+		if parent.Kind == nil || string(*parent.Kind) == resource.KindGateway {
 			// If an explicit Gateway namespace is not provided, use the GRPCRoute namespace to
 			// lookup the provided Gateway Name.
 			gateways = append(gateways,
@@ -271,7 +272,7 @@ func backendGRPCRouteIndexFunc(rawObj client.Object) []string {
 	var backendRefs []string
 	for _, rule := range grpcroute.Spec.Rules {
 		for _, backend := range rule.BackendRefs {
-			if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService || string(*backend.Kind) == egv1a1.KindBackend {
+			if backend.Kind == nil || string(*backend.Kind) == resource.KindService || string(*backend.Kind) == egv1a1.KindBackend {
 				// If an explicit Backend namespace is not provided, use the GRPCRoute namespace to
 				// lookup the provided Gateway Name.
 				backendRefs = append(backendRefs,
@@ -294,7 +295,7 @@ func addTLSRouteIndexers(ctx context.Context, mgr manager.Manager) error {
 		tlsRoute := rawObj.(*gwapiv1a2.TLSRoute)
 		var gateways []string
 		for _, parent := range tlsRoute.Spec.ParentRefs {
-			if string(*parent.Kind) == gatewayapi.KindGateway {
+			if string(*parent.Kind) == resource.KindGateway {
 				// If an explicit Gateway namespace is not provided, use the TLSRoute namespace to
 				// lookup the provided Gateway Name.
 				gateways = append(gateways,
@@ -321,7 +322,7 @@ func backendTLSRouteIndexFunc(rawObj client.Object) []string {
 	var backendRefs []string
 	for _, rule := range tlsroute.Spec.Rules {
 		for _, backend := range rule.BackendRefs {
-			if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService || string(*backend.Kind) == egv1a1.KindBackend {
+			if backend.Kind == nil || string(*backend.Kind) == resource.KindService || string(*backend.Kind) == egv1a1.KindBackend {
 				// If an explicit Backend namespace is not provided, use the TLSRoute namespace to
 				// lookup the provided Gateway Name.
 				backendRefs = append(backendRefs,
@@ -344,7 +345,7 @@ func addTCPRouteIndexers(ctx context.Context, mgr manager.Manager) error {
 		tcpRoute := rawObj.(*gwapiv1a2.TCPRoute)
 		var gateways []string
 		for _, parent := range tcpRoute.Spec.ParentRefs {
-			if string(*parent.Kind) == gatewayapi.KindGateway {
+			if string(*parent.Kind) == resource.KindGateway {
 				// If an explicit Gateway namespace is not provided, use the TCPRoute namespace to
 				// lookup the provided Gateway Name.
 				gateways = append(gateways,
@@ -371,7 +372,7 @@ func backendTCPRouteIndexFunc(rawObj client.Object) []string {
 	var backendRefs []string
 	for _, rule := range tcpRoute.Spec.Rules {
 		for _, backend := range rule.BackendRefs {
-			if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService || string(*backend.Kind) == egv1a1.KindBackend {
+			if backend.Kind == nil || string(*backend.Kind) == resource.KindService || string(*backend.Kind) == egv1a1.KindBackend {
 				// If an explicit Backend namespace is not provided, use the TCPRoute namespace to
 				// lookup the provided Gateway Name.
 				backendRefs = append(backendRefs,
@@ -396,7 +397,7 @@ func addUDPRouteIndexers(ctx context.Context, mgr manager.Manager) error {
 		udpRoute := rawObj.(*gwapiv1a2.UDPRoute)
 		var gateways []string
 		for _, parent := range udpRoute.Spec.ParentRefs {
-			if string(*parent.Kind) == gatewayapi.KindGateway {
+			if string(*parent.Kind) == resource.KindGateway {
 				// If an explicit Gateway namespace is not provided, use the UDPRoute namespace to
 				// lookup the provided Gateway Name.
 				gateways = append(gateways,
@@ -423,7 +424,7 @@ func backendUDPRouteIndexFunc(rawObj client.Object) []string {
 	var backendRefs []string
 	for _, rule := range udproute.Spec.Rules {
 		for _, backend := range rule.BackendRefs {
-			if backend.Kind == nil || string(*backend.Kind) == gatewayapi.KindService || string(*backend.Kind) == egv1a1.KindBackend {
+			if backend.Kind == nil || string(*backend.Kind) == resource.KindService || string(*backend.Kind) == egv1a1.KindBackend {
 				// If an explicit Backend namespace is not provided, use the UDPRoute namespace to
 				// lookup the provided Gateway Name.
 				backendRefs = append(backendRefs,
@@ -463,7 +464,7 @@ func secretGatewayIndexFunc(rawObj client.Object) []string {
 			continue
 		}
 		for _, cert := range listener.TLS.CertificateRefs {
-			if *cert.Kind == gatewayapi.KindSecret {
+			if *cert.Kind == resource.KindSecret {
 				// If an explicit Secret namespace is not provided, use the Gateway namespace to
 				// lookup the provided Secret Name.
 				secretReferences = append(secretReferences,
@@ -582,7 +583,7 @@ func configMapCtpIndexFunc(rawObj client.Object) []string {
 	var configMapReferences []string
 	if ctp.Spec.TLS != nil && ctp.Spec.TLS.ClientValidation != nil {
 		for _, caCertRef := range ctp.Spec.TLS.ClientValidation.CACertificateRefs {
-			if caCertRef.Kind != nil && string(*caCertRef.Kind) == gatewayapi.KindConfigMap {
+			if caCertRef.Kind != nil && string(*caCertRef.Kind) == resource.KindConfigMap {
 				// If an explicit configmap namespace is not provided, use the ctp namespace to
 				// lookup the provided config map Name.
 				configMapReferences = append(configMapReferences,
@@ -602,7 +603,7 @@ func secretCtpIndexFunc(rawObj client.Object) []string {
 	var secretReferences []string
 	if ctp.Spec.TLS != nil && ctp.Spec.TLS.ClientValidation != nil {
 		for _, caCertRef := range ctp.Spec.TLS.ClientValidation.CACertificateRefs {
-			if caCertRef.Kind == nil || (string(*caCertRef.Kind) == gatewayapi.KindSecret) {
+			if caCertRef.Kind == nil || (string(*caCertRef.Kind) == resource.KindSecret) {
 				// If an explicit namespace is not provided, use the ctp namespace to
 				// lookup the provided secrent Name.
 				secretReferences = append(secretReferences,
@@ -633,7 +634,7 @@ func configMapBtlsIndexFunc(rawObj client.Object) []string {
 	var configMapReferences []string
 	if btls.Spec.Validation.CACertificateRefs != nil {
 		for _, caCertRef := range btls.Spec.Validation.CACertificateRefs {
-			if string(caCertRef.Kind) == gatewayapi.KindConfigMap {
+			if string(caCertRef.Kind) == resource.KindConfigMap {
 				configMapReferences = append(configMapReferences,
 					types.NamespacedName{
 						Namespace: btls.Namespace,
diff --git a/internal/provider/kubernetes/routes.go b/internal/provider/kubernetes/routes.go
index c52e39ef3..d298e7e0e 100644
--- a/internal/provider/kubernetes/routes.go
+++ b/internal/provider/kubernetes/routes.go
@@ -17,13 +17,14 @@ import (
 	gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/utils"
 )
 
 // processTLSRoutes finds TLSRoutes corresponding to a gatewayNamespaceName, further checks for
 // the backend references and pushes the TLSRoutes to the resourceTree.
 func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayNamespaceName string,
-	resourceMap *resourceMappings, resourceTree *gatewayapi.Resources,
+	resourceMap *resourceMappings, resourceTree *resource.Resources,
 ) error {
 	tlsRouteList := &gwapiv1a2.TLSRouteList{}
 	if err := r.client.List(ctx, tlsRouteList, &client.ListOptions{
@@ -69,8 +70,8 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName
 				})
 
 				if backendNamespace != tlsRoute.Namespace {
-					from := ObjectKindNamespacedName{kind: gatewayapi.KindTLSRoute, namespace: tlsRoute.Namespace, name: tlsRoute.Name}
-					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
+					from := ObjectKindNamespacedName{kind: resource.KindTLSRoute, namespace: tlsRoute.Namespace, name: tlsRoute.Name}
+					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
 					refGrant, err := r.findReferenceGrant(ctx, from, to)
 					switch {
 					case err != nil:
@@ -101,7 +102,7 @@ func (r *gatewayAPIReconciler) processTLSRoutes(ctx context.Context, gatewayName
 // processGRPCRoutes finds GRPCRoutes corresponding to a gatewayNamespaceName, further checks for
 // the backend references and pushes the GRPCRoutes to the resourceTree.
 func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNamespaceName string,
-	resourceMap *resourceMappings, resourceTree *gatewayapi.Resources,
+	resourceMap *resourceMappings, resourceTree *resource.Resources,
 ) error {
 	grpcRouteList := &gwapiv1.GRPCRouteList{}
 
@@ -148,12 +149,12 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam
 
 				if backendNamespace != grpcRoute.Namespace {
 					from := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindGRPCRoute,
+						kind:      resource.KindGRPCRoute,
 						namespace: grpcRoute.Namespace,
 						name:      grpcRoute.Name,
 					}
 					to := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService),
+						kind:      gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService),
 						namespace: backendNamespace,
 						name:      string(backendRef.Name),
 					}
@@ -226,7 +227,7 @@ func (r *gatewayAPIReconciler) processGRPCRoutes(ctx context.Context, gatewayNam
 // processHTTPRoutes finds HTTPRoutes corresponding to a gatewayNamespaceName, further checks for
 // the backend references and pushes the HTTPRoutes to the resourceTree.
 func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNamespaceName string,
-	resourceMap *resourceMappings, resourceTree *gatewayapi.Resources,
+	resourceMap *resourceMappings, resourceTree *resource.Resources,
 ) error {
 	httpRouteList := &gwapiv1.HTTPRouteList{}
 
@@ -282,12 +283,12 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 
 				if backendNamespace != httpRoute.Namespace {
 					from := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindHTTPRoute,
+						kind:      resource.KindHTTPRoute,
 						namespace: httpRoute.Namespace,
 						name:      httpRoute.Name,
 					}
 					to := ObjectKindNamespacedName{
-						kind:      gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService),
+						kind:      gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService),
 						namespace: backendNamespace,
 						name:      string(backendRef.Name),
 					}
@@ -349,12 +350,12 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 
 					if backendNamespace != httpRoute.Namespace {
 						from := ObjectKindNamespacedName{
-							kind:      gatewayapi.KindHTTPRoute,
+							kind:      resource.KindHTTPRoute,
 							namespace: httpRoute.Namespace,
 							name:      httpRoute.Name,
 						}
 						to := ObjectKindNamespacedName{
-							kind:      gatewayapi.KindDerefOr(mirrorBackendRef.Kind, gatewayapi.KindService),
+							kind:      gatewayapi.KindDerefOr(mirrorBackendRef.Kind, resource.KindService),
 							namespace: backendNamespace,
 							name:      string(mirrorBackendRef.Name),
 						}
@@ -413,7 +414,7 @@ func (r *gatewayAPIReconciler) processHTTPRoutes(ctx context.Context, gatewayNam
 // processTCPRoutes finds TCPRoutes corresponding to a gatewayNamespaceName, further checks for
 // the backend references and pushes the TCPRoutes to the resourceTree.
 func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayNamespaceName string,
-	resourceMap *resourceMappings, resourceTree *gatewayapi.Resources,
+	resourceMap *resourceMappings, resourceTree *resource.Resources,
 ) error {
 	tcpRouteList := &gwapiv1a2.TCPRouteList{}
 	if err := r.client.List(ctx, tcpRouteList, &client.ListOptions{
@@ -459,8 +460,8 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName
 				})
 
 				if backendNamespace != tcpRoute.Namespace {
-					from := ObjectKindNamespacedName{kind: gatewayapi.KindTCPRoute, namespace: tcpRoute.Namespace, name: tcpRoute.Name}
-					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
+					from := ObjectKindNamespacedName{kind: resource.KindTCPRoute, namespace: tcpRoute.Namespace, name: tcpRoute.Name}
+					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
 					refGrant, err := r.findReferenceGrant(ctx, from, to)
 					switch {
 					case err != nil:
@@ -491,7 +492,7 @@ func (r *gatewayAPIReconciler) processTCPRoutes(ctx context.Context, gatewayName
 // processUDPRoutes finds UDPRoutes corresponding to a gatewayNamespaceName, further checks for
 // the backend references and pushes the UDPRoutes to the resourceTree.
 func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayNamespaceName string,
-	resourceMap *resourceMappings, resourceTree *gatewayapi.Resources,
+	resourceMap *resourceMappings, resourceTree *resource.Resources,
 ) error {
 	udpRouteList := &gwapiv1a2.UDPRouteList{}
 	if err := r.client.List(ctx, udpRouteList, &client.ListOptions{
@@ -537,8 +538,8 @@ func (r *gatewayAPIReconciler) processUDPRoutes(ctx context.Context, gatewayName
 				})
 
 				if backendNamespace != udpRoute.Namespace {
-					from := ObjectKindNamespacedName{kind: gatewayapi.KindUDPRoute, namespace: udpRoute.Namespace, name: udpRoute.Name}
-					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, gatewayapi.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
+					from := ObjectKindNamespacedName{kind: resource.KindUDPRoute, namespace: udpRoute.Namespace, name: udpRoute.Name}
+					to := ObjectKindNamespacedName{kind: gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService), namespace: backendNamespace, name: string(backendRef.Name)}
 					refGrant, err := r.findReferenceGrant(ctx, from, to)
 					switch {
 					case err != nil:
diff --git a/internal/provider/kubernetes/status_updater.go b/internal/provider/kubernetes/status_updater.go
index 59ff64d33..9da708f1b 100644
--- a/internal/provider/kubernetes/status_updater.go
+++ b/internal/provider/kubernetes/status_updater.go
@@ -23,7 +23,7 @@ import (
 	gwapiv1a3 "sigs.k8s.io/gateway-api/apis/v1alpha3"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/metrics"
 )
 
@@ -318,35 +318,35 @@ func kindOf(obj interface{}) string {
 	var kind string
 	switch o := obj.(type) {
 	case *gwapiv1.GatewayClass:
-		kind = gatewayapi.KindGatewayClass
+		kind = resource.KindGatewayClass
 	case *gwapiv1.Gateway:
-		kind = gatewayapi.KindGateway
+		kind = resource.KindGateway
 	case *gwapiv1.HTTPRoute:
-		kind = gatewayapi.KindHTTPRoute
+		kind = resource.KindHTTPRoute
 	case *gwapiv1a2.TLSRoute:
-		kind = gatewayapi.KindTLSRoute
+		kind = resource.KindTLSRoute
 	case *gwapiv1a2.TCPRoute:
-		kind = gatewayapi.KindTCPRoute
+		kind = resource.KindTCPRoute
 	case *gwapiv1a2.UDPRoute:
-		kind = gatewayapi.KindUDPRoute
+		kind = resource.KindUDPRoute
 	case *gwapiv1.GRPCRoute:
-		kind = gatewayapi.KindGRPCRoute
+		kind = resource.KindGRPCRoute
 	case *egv1a1.EnvoyPatchPolicy:
-		kind = gatewayapi.KindEnvoyPatchPolicy
+		kind = resource.KindEnvoyPatchPolicy
 	case *egv1a1.ClientTrafficPolicy:
-		kind = gatewayapi.KindClientTrafficPolicy
+		kind = resource.KindClientTrafficPolicy
 	case *egv1a1.BackendTrafficPolicy:
-		kind = gatewayapi.KindBackendTrafficPolicy
+		kind = resource.KindBackendTrafficPolicy
 	case *egv1a1.SecurityPolicy:
-		kind = gatewayapi.KindSecurityPolicy
+		kind = resource.KindSecurityPolicy
 	case *egv1a1.EnvoyExtensionPolicy:
-		kind = gatewayapi.KindEnvoyExtensionPolicy
+		kind = resource.KindEnvoyExtensionPolicy
 	case *gwapiv1a3.BackendTLSPolicy:
-		kind = gatewayapi.KindBackendTLSPolicy
+		kind = resource.KindBackendTLSPolicy
 	case *unstructured.Unstructured:
 		kind = o.GetKind()
 	case *egv1a1.Backend:
-		kind = egv1a1.KindBackend
+		kind = resource.KindBackend
 	default:
 		kind = "Unknown"
 	}
diff --git a/site/content/en/contributions/DEVELOP.md b/site/content/en/contributions/DEVELOP.md
index c953048a4..f972c547f 100644
--- a/site/content/en/contributions/DEVELOP.md
+++ b/site/content/en/contributions/DEVELOP.md
@@ -156,7 +156,7 @@ The performance and scalability concerns come from several aspects for control-p
 - The rate of configuration changes.
 
 The benchmark test is running on a [Kind][Kind] cluster, you can start a Kind cluster and 
-run benchmark test on it by executing `make benchmark-test`.
+run benchmark test on it by executing `make benchmark`.
 
 The benchmark report will be included in the release artifacts, you can learn more by downloading
 the detailed benchmark report, namely `benchmark_report.zip`.


Test patch:
diff --git a/internal/cmd/egctl/status_test.go b/internal/cmd/egctl/status_test.go
index 68123a696..2d2b6ad61 100644
--- a/internal/cmd/egctl/status_test.go
+++ b/internal/cmd/egctl/status_test.go
@@ -19,6 +19,7 @@ import (
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func TestWriteStatus(t *testing.T) {
@@ -40,7 +41,7 @@ func TestWriteStatus(t *testing.T) {
 			name:               "egctl x status gc -v, but no resources",
 			resourceList:       &gwapiv1.GatewayClassList{},
 			resourceNamespaced: false,
-			resourceKind:       gatewayapi.KindGatewayClass,
+			resourceKind:       resource.KindGatewayClass,
 			quiet:              false,
 			verbose:            true,
 			allNamespaces:      false,
@@ -80,7 +81,7 @@ func TestWriteStatus(t *testing.T) {
 				},
 			},
 			resourceNamespaced: false,
-			resourceKind:       gatewayapi.KindGatewayClass,
+			resourceKind:       resource.KindGatewayClass,
 			quiet:              false,
 			verbose:            false,
 			allNamespaces:      false,
@@ -122,7 +123,7 @@ gc        foobar2   test-status-2   test reason 2
 				},
 			},
 			resourceNamespaced: false,
-			resourceKind:       gatewayapi.KindGatewayClass,
+			resourceKind:       resource.KindGatewayClass,
 			quiet:              false,
 			verbose:            true,
 			allNamespaces:      false,
@@ -164,7 +165,7 @@ gc        foobar2   test-status-2   test reason 2   test message 2   123457
 				},
 			},
 			resourceNamespaced: false,
-			resourceKind:       gatewayapi.KindGatewayClass,
+			resourceKind:       resource.KindGatewayClass,
 			quiet:              true,
 			verbose:            true,
 			allNamespaces:      false,
@@ -177,7 +178,7 @@ gc        foobar2   test-status-2   test reason 2   test message 2   123457
 			name:               "egctl x status gtw -v -A, no resources",
 			resourceList:       &gwapiv1.GatewayList{},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindGateway,
+			resourceKind:       resource.KindGateway,
 			quiet:              false,
 			verbose:            true,
 			allNamespaces:      true,
@@ -218,7 +219,7 @@ gc        foobar2   test-status-2   test reason 2   test message 2   123457
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindGateway,
+			resourceKind:       resource.KindGateway,
 			quiet:              false,
 			verbose:            true,
 			allNamespaces:      true,
@@ -287,7 +288,7 @@ default     gtw       foobar2   test-status-2   test reason 2   test message 2
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindGateway,
+			resourceKind:       resource.KindGateway,
 			quiet:              true,
 			verbose:            true,
 			allNamespaces:      true,
@@ -311,7 +312,7 @@ default2    gtw2      foobar4   test-status-4   test reason 4   test message 4
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-1"),
 										},
 										Conditions: []metav1.Condition{
@@ -347,7 +348,7 @@ default2    gtw2      foobar4   test-status-4   test reason 4   test message 4
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-2"),
 										},
 										Conditions: []metav1.Condition{
@@ -376,7 +377,7 @@ default2    gtw2      foobar4   test-status-4   test reason 4   test message 4
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindHTTPRoute,
+			resourceKind:       resource.KindHTTPRoute,
 			quiet:              false,
 			verbose:            false,
 			allNamespaces:      true,
@@ -402,7 +403,7 @@ default2    http2     gateway/test-2   foobar4   test-status-4   test reason 4
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-1"),
 										},
 										Conditions: []metav1.Condition{
@@ -438,7 +439,7 @@ default2    http2     gateway/test-2   foobar4   test-status-4   test reason 4
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-2"),
 										},
 										Conditions: []metav1.Condition{
@@ -467,7 +468,7 @@ default2    http2     gateway/test-2   foobar4   test-status-4   test reason 4
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindHTTPRoute,
+			resourceKind:       resource.KindHTTPRoute,
 			quiet:              true,
 			verbose:            false,
 			allNamespaces:      false,
@@ -491,7 +492,7 @@ http2     gateway/test-2   foobar4   test-status-4   test reason 4
 							Ancestors: []gwapiv1a2.PolicyAncestorStatus{
 								{
 									AncestorRef: gwapiv1.ParentReference{
-										Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+										Kind: gatewayapi.KindPtr(resource.KindGateway),
 										Name: gwapiv1.ObjectName("test"),
 									},
 									Conditions: []metav1.Condition{
@@ -519,7 +520,7 @@ http2     gateway/test-2   foobar4   test-status-4   test reason 4
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindBackendTLSPolicy,
+			resourceKind:       resource.KindBackendTLSPolicy,
 			quiet:              false,
 			verbose:            false,
 			allNamespaces:      false,
@@ -543,7 +544,7 @@ btls      gateway/test         foobar2   test-status-2   test reason 2
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-1"),
 										},
 										Conditions: []metav1.Condition{
@@ -567,7 +568,7 @@ btls      gateway/test         foobar2   test-status-2   test reason 2
 									},
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-2"),
 										},
 										Conditions: []metav1.Condition{
@@ -603,7 +604,7 @@ btls      gateway/test         foobar2   test-status-2   test reason 2
 								Parents: []gwapiv1.RouteParentStatus{
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-3"),
 										},
 										Conditions: []metav1.Condition{
@@ -627,7 +628,7 @@ btls      gateway/test         foobar2   test-status-2   test reason 2
 									},
 									{
 										ParentRef: gwapiv1.ParentReference{
-											Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+											Kind: gatewayapi.KindPtr(resource.KindGateway),
 											Name: gwapiv1.ObjectName("test-4"),
 										},
 										Conditions: []metav1.Condition{
@@ -656,7 +657,7 @@ btls      gateway/test         foobar2   test-status-2   test reason 2
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindHTTPRoute,
+			resourceKind:       resource.KindHTTPRoute,
 			quiet:              false,
 			verbose:            false,
 			allNamespaces:      true,
@@ -685,7 +686,7 @@ default2    http2     gateway/test-3   foobar6   test-status-6   test reason 6
 							Ancestors: []gwapiv1a2.PolicyAncestorStatus{
 								{
 									AncestorRef: gwapiv1.ParentReference{
-										Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+										Kind: gatewayapi.KindPtr(resource.KindGateway),
 										Name: gwapiv1.ObjectName("test-1"),
 									},
 									Conditions: []metav1.Condition{
@@ -709,7 +710,7 @@ default2    http2     gateway/test-3   foobar6   test-status-6   test reason 6
 								},
 								{
 									AncestorRef: gwapiv1.ParentReference{
-										Kind: gatewayapi.KindPtr(gatewayapi.KindHTTPRoute),
+										Kind: gatewayapi.KindPtr(resource.KindHTTPRoute),
 										Name: gwapiv1.ObjectName("test-2"),
 									},
 									Conditions: []metav1.Condition{
@@ -743,7 +744,7 @@ default2    http2     gateway/test-3   foobar6   test-status-6   test reason 6
 							Ancestors: []gwapiv1a2.PolicyAncestorStatus{
 								{
 									AncestorRef: gwapiv1.ParentReference{
-										Kind: gatewayapi.KindPtr(gatewayapi.KindGateway),
+										Kind: gatewayapi.KindPtr(resource.KindGateway),
 										Name: gwapiv1.ObjectName("test-3"),
 									},
 									Conditions: []metav1.Condition{
@@ -767,7 +768,7 @@ default2    http2     gateway/test-3   foobar6   test-status-6   test reason 6
 								},
 								{
 									AncestorRef: gwapiv1.ParentReference{
-										Kind: gatewayapi.KindPtr(gatewayapi.KindGRPCRoute),
+										Kind: gatewayapi.KindPtr(resource.KindGRPCRoute),
 										Name: gwapiv1.ObjectName("test-4"),
 									},
 									Conditions: []metav1.Condition{
@@ -795,7 +796,7 @@ default2    http2     gateway/test-3   foobar6   test-status-6   test reason 6
 				},
 			},
 			resourceNamespaced: true,
-			resourceKind:       gatewayapi.KindBackendTrafficPolicy,
+			resourceKind:       resource.KindBackendTrafficPolicy,
 			quiet:              false,
 			verbose:            false,
 			allNamespaces:      false,
diff --git a/internal/gatewayapi/contexts_test.go b/internal/gatewayapi/contexts_test.go
index b594dc92e..ec6bfe6e1 100644
--- a/internal/gatewayapi/contexts_test.go
+++ b/internal/gatewayapi/contexts_test.go
@@ -12,11 +12,12 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/gatewayapi/status"
 )
 
 func TestContexts(t *testing.T) {
-	r := &Resources{
+	r := &resource.Resources{
 		GatewayClass: &gwapiv1.GatewayClass{
 			ObjectMeta: metav1.ObjectMeta{
 				Name: "foo",
@@ -68,7 +69,7 @@ func TestContexts(t *testing.T) {
 }
 
 func TestContextsStaleListener(t *testing.T) {
-	r := &Resources{
+	r := &resource.Resources{
 		GatewayClass: &gwapiv1.GatewayClass{
 			ObjectMeta: metav1.ObjectMeta{
 				Name: "foo",
diff --git a/internal/gatewayapi/resource_test.go b/internal/gatewayapi/resource/resource_test.go
similarity index 99%
rename from internal/gatewayapi/resource_test.go
rename to internal/gatewayapi/resource/resource_test.go
index 8b9fddc0f..3255cb6b0 100644
--- a/internal/gatewayapi/resource_test.go
+++ b/internal/gatewayapi/resource/resource_test.go
@@ -3,7 +3,7 @@
 // The full text of the Apache license is available in the LICENSE file at
 // the root of the repo.
 
-package gatewayapi
+package resource
 
 import (
 	"testing"
diff --git a/internal/gatewayapi/translator_test.go b/internal/gatewayapi/translator_test.go
index 42bb1ca37..7184326fd 100644
--- a/internal/gatewayapi/translator_test.go
+++ b/internal/gatewayapi/translator_test.go
@@ -33,6 +33,7 @@ import (
 	"sigs.k8s.io/yaml"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/utils/field"
 	"github.com/envoyproxy/gateway/internal/utils/file"
 	"github.com/envoyproxy/gateway/internal/wasm"
@@ -68,7 +69,7 @@ func TestTranslate(t *testing.T) {
 			input, err := os.ReadFile(inputFile)
 			require.NoError(t, err)
 
-			resources := &Resources{}
+			resources := &resource.Resources{}
 			mustUnmarshal(t, input, resources)
 			envoyPatchPolicyEnabled := true
 			backendEnabled := true
@@ -334,7 +335,7 @@ func TestTranslateWithExtensionKinds(t *testing.T) {
 			input, err := os.ReadFile(inputFile)
 			require.NoError(t, err)
 
-			resources := &Resources{}
+			resources := &resource.Resources{}
 			mustUnmarshal(t, input, resources)
 
 			translator := &Translator{
diff --git a/internal/provider/kubernetes/controller_test.go b/internal/provider/kubernetes/controller_test.go
index b2fb1c3d7..c1cece277 100644
--- a/internal/provider/kubernetes/controller_test.go
+++ b/internal/provider/kubernetes/controller_test.go
@@ -19,6 +19,7 @@ import (
 	"github.com/envoyproxy/gateway/internal/envoygateway"
 	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/logging"
 )
 
@@ -274,7 +275,7 @@ func TestProcessGatewayClassParamsRef(t *testing.T) {
 			}
 
 			// Process the test case gatewayclasses.
-			resourceTree := gatewayapi.NewResources()
+			resourceTree := resource.NewResources()
 			resourceMap := newResourceMapping()
 			err := r.processGatewayClassParamsRef(context.Background(), tc.gc, resourceMap, resourceTree)
 			if tc.expected {
diff --git a/internal/provider/kubernetes/extensionpolicies_test.go b/internal/provider/kubernetes/extensionpolicies_test.go
index dbfb2904f..3d74ff270 100644
--- a/internal/provider/kubernetes/extensionpolicies_test.go
+++ b/internal/provider/kubernetes/extensionpolicies_test.go
@@ -17,7 +17,7 @@ import (
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/envoygateway"
-	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/logging"
 )
 
@@ -226,7 +226,7 @@ func TestProcessExtensionPolicies(t *testing.T) {
 				WithObjects(objs...).
 				Build()
 
-			resourceTree := gatewayapi.NewResources()
+			resourceTree := resource.NewResources()
 			err := r.processExtensionServerPolicies(ctx, resourceTree)
 			if !tc.errorExpected {
 				require.NoError(t, err)
diff --git a/internal/provider/kubernetes/kubernetes_test.go b/internal/provider/kubernetes/kubernetes_test.go
index b82836ef8..d673def5c 100644
--- a/internal/provider/kubernetes/kubernetes_test.go
+++ b/internal/provider/kubernetes/kubernetes_test.go
@@ -35,6 +35,7 @@ import (
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/envoygateway/config"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/message"
 	"github.com/envoyproxy/gateway/internal/provider/kubernetes/test"
 	"github.com/envoyproxy/gateway/internal/utils"
@@ -1600,7 +1601,7 @@ func TestNamespaceSelectorProvider(t *testing.T) {
 	}, defaultWait, defaultTick)
 }
 
-func waitUntilGatewayClassResourcesAreReady(resources *message.ProviderResources, gatewayClassName string) (*gatewayapi.Resources, bool) {
+func waitUntilGatewayClassResourcesAreReady(resources *message.ProviderResources, gatewayClassName string) (*resource.Resources, bool) {
 	res := resources.GetResourcesByGatewayClass(gatewayClassName)
 	if res == nil {
 		return nil, false
diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go
index 054de1e53..a442ddcf2 100644
--- a/internal/provider/kubernetes/predicates_test.go
+++ b/internal/provider/kubernetes/predicates_test.go
@@ -24,6 +24,7 @@ import (
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/envoygateway"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/infrastructure/kubernetes/proxy"
 	"github.com/envoyproxy/gateway/internal/logging"
 	"github.com/envoyproxy/gateway/internal/provider/kubernetes/test"
@@ -221,7 +222,7 @@ func TestValidateSecretForReconcile(t *testing.T) {
 			configs: []client.Object{
 				test.GetGatewayClass("test-gc", egv1a1.GatewayControllerName, nil),
 				test.GetSecureGateway(types.NamespacedName{Name: "scheduled-status-test"}, "test-gc", test.GroupKindNamespacedName{
-					Kind: gatewayapi.KindSecret,
+					Kind: resource.KindSecret,
 					Name: "secret",
 				}),
 			},
@@ -233,7 +234,7 @@ func TestValidateSecretForReconcile(t *testing.T) {
 			configs: []client.Object{
 				test.GetGatewayClass("test-gc", "not.configured/controller", nil),
 				test.GetSecureGateway(types.NamespacedName{Name: "scheduled-status-test"}, "test-gc", test.GroupKindNamespacedName{
-					Kind: gatewayapi.KindSecret,
+					Kind: resource.KindSecret,
 					Name: "secret",
 				}),
 			},
diff --git a/internal/provider/kubernetes/routes_test.go b/internal/provider/kubernetes/routes_test.go
index 9bd4126d3..5fc365465 100644
--- a/internal/provider/kubernetes/routes_test.go
+++ b/internal/provider/kubernetes/routes_test.go
@@ -25,6 +25,7 @@ import (
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/envoygateway"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/internal/logging"
 	"github.com/envoyproxy/gateway/internal/utils"
 )
@@ -107,7 +108,7 @@ func TestProcessHTTPRoutes(t *testing.T) {
 										BackendRef: gwapiv1.BackendRef{
 											BackendObjectReference: gwapiv1.BackendObjectReference{
 												Group: gatewayapi.GroupPtr(corev1.GroupName),
-												Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+												Kind:  gatewayapi.KindPtr(resource.KindService),
 												Name:  "test",
 											},
 										},
@@ -169,7 +170,7 @@ func TestProcessHTTPRoutes(t *testing.T) {
 										BackendRef: gwapiv1.BackendRef{
 											BackendObjectReference: gwapiv1.BackendObjectReference{
 												Group: gatewayapi.GroupPtr(corev1.GroupName),
-												Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+												Kind:  gatewayapi.KindPtr(resource.KindService),
 												Name:  "test",
 											},
 										},
@@ -257,7 +258,7 @@ func TestProcessHTTPRoutes(t *testing.T) {
 										BackendRef: gwapiv1.BackendRef{
 											BackendObjectReference: gwapiv1.BackendObjectReference{
 												Group: gatewayapi.GroupPtr(corev1.GroupName),
-												Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+												Kind:  gatewayapi.KindPtr(resource.KindService),
 												Name:  "test",
 											},
 										},
@@ -320,7 +321,7 @@ func TestProcessHTTPRoutes(t *testing.T) {
 										BackendRef: gwapiv1.BackendRef{
 											BackendObjectReference: gwapiv1.BackendObjectReference{
 												Group: gatewayapi.GroupPtr(corev1.GroupName),
-												Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+												Kind:  gatewayapi.KindPtr(resource.KindService),
 												Name:  "test",
 											},
 										},
@@ -382,7 +383,7 @@ func TestProcessHTTPRoutes(t *testing.T) {
 			}, defaultWait, defaultTick)
 
 			// Process the test case httproutes.
-			resourceTree := gatewayapi.NewResources()
+			resourceTree := resource.NewResources()
 			resourceMap := newResourceMapping()
 			err := r.processHTTPRoutes(ctx, gwNsName, resourceMap, resourceTree)
 			if tc.expected {
@@ -478,7 +479,7 @@ func TestProcessGRPCRoutes(t *testing.T) {
 										BackendRef: gwapiv1.BackendRef{
 											BackendObjectReference: gwapiv1.BackendObjectReference{
 												Group: gatewayapi.GroupPtr(corev1.GroupName),
-												Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+												Kind:  gatewayapi.KindPtr(resource.KindService),
 												Name:  "test",
 											},
 										},
@@ -524,7 +525,7 @@ func TestProcessGRPCRoutes(t *testing.T) {
 				Build()
 
 			// Process the test case httproutes.
-			resourceTree := gatewayapi.NewResources()
+			resourceTree := resource.NewResources()
 			resourceMap := newResourceMapping()
 			err := r.processGRPCRoutes(ctx, gwNsName, resourceMap, resourceTree)
 			if tc.expected {
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index fa4621480..0d1be81fc 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -26,6 +26,8 @@ API group.
 - [EnvoyPatchPolicy](#envoypatchpolicy)
 - [EnvoyPatchPolicyList](#envoypatchpolicylist)
 - [EnvoyProxy](#envoyproxy)
+- [HTTPRouteFilter](#httproutefilter)
+- [HTTPRouteFilterList](#httproutefilterlist)
 - [SecurityPolicy](#securitypolicy)
 - [SecurityPolicyList](#securitypolicylist)
 
@@ -1891,6 +1893,83 @@ _Appears in:_
 | `headersToBackend` | _string array_ |  false  | HeadersToBackend are the authorization response headers that will be added<br />to the original client request before sending it to the backend server.<br />Note that coexisting headers will be overridden.<br />If not specified, no authorization response headers will be added to the<br />original client request. |
 
 
+#### HTTPPathModifier
+
+
+
+
+
+_Appears in:_
+- [HTTPURLRewriteFilter](#httpurlrewritefilter)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `type` | _[HTTPPathModifierType](#httppathmodifiertype)_ |  true  |  |
+| `replaceRegexMatch` | _[ReplaceRegexMatch](#replaceregexmatch)_ |  true  | ReplaceRegexMatch defines a path regex rewrite. The path portions matched by the regex pattern are replaced by the defined substitution.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-regex-rewrite<br />Some examples:<br />(1) replaceRegexMatch:<br />      pattern: ^/service/([^/]+)(/.*)$<br />      substitution: \2/instance/\1<br />    Would transform /service/foo/v1/api into /v1/api/instance/foo.<br />(2) replaceRegexMatch:<br />      pattern: one<br />      substitution: two<br />    Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/two/zzz.<br />(3) replaceRegexMatch:<br />      pattern: ^(.*?)one(.*)$<br />      substitution: \1two\2<br />    Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/one/zzz.<br />(3) replaceRegexMatch:<br />      pattern: (?i)/xxx/<br />      substitution: /yyy/<br />    Would transform path /aaa/XxX/bbb into /aaa/yyy/bbb (case-insensitive). |
+
+
+#### HTTPPathModifierType
+
+_Underlying type:_ _string_
+
+HTTPPathModifierType defines the type of path redirect or rewrite.
+
+_Appears in:_
+- [HTTPPathModifier](#httppathmodifier)
+
+| Value | Description |
+| ----- | ----------- |
+| `ReplaceRegexMatch` | RegexHTTPPathModifier This type of modifier indicates that the portions of the path that match the specified<br /> regex would be substituted with the specified substitution value<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/type/matcher/v3/regex.proto#type-matcher-v3-regexmatchandsubstitute<br /> | 
+
+
+#### HTTPRouteFilter
+
+
+
+HTTPRouteFilter is a custom Envoy Gateway HTTPRouteFilter which provides extended
+traffic processing options such as path regex rewrite, direct response and more.
+
+_Appears in:_
+- [HTTPRouteFilterList](#httproutefilterlist)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `apiVersion` | _string_ | |`gateway.envoyproxy.io/v1alpha1`
+| `kind` | _string_ | |`HTTPRouteFilter`
+| `metadata` | _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ |  true  | Refer to Kubernetes API documentation for fields of `metadata`. |
+| `spec` | _[HTTPRouteFilterSpec](#httproutefilterspec)_ |  true  | Spec defines the desired state of HTTPRouteFilter. |
+
+
+#### HTTPRouteFilterList
+
+
+
+HTTPRouteFilterList contains a list of HTTPRouteFilter resources.
+
+
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `apiVersion` | _string_ | |`gateway.envoyproxy.io/v1alpha1`
+| `kind` | _string_ | |`HTTPRouteFilterList`
+| `metadata` | _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#listmeta-v1-meta)_ |  true  | Refer to Kubernetes API documentation for fields of `metadata`. |
+| `items` | _[HTTPRouteFilter](#httproutefilter) array_ |  true  |  |
+
+
+#### HTTPRouteFilterSpec
+
+
+
+HTTPRouteFilterSpec defines the desired state of HTTPRouteFilter.
+
+_Appears in:_
+- [HTTPRouteFilter](#httproutefilter)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `urlRewrite` | _[HTTPURLRewriteFilter](#httpurlrewritefilter)_ |  false  |  |
+
+
 #### HTTPStatus
 
 _Underlying type:_ _integer_
@@ -1918,6 +1997,20 @@ _Appears in:_
 | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ |  false  | The maximum duration of an HTTP connection.<br />Default: unlimited. |
 
 
+#### HTTPURLRewriteFilter
+
+
+
+HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host
+
+_Appears in:_
+- [HTTPRouteFilterSpec](#httproutefilterspec)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `path` | _[HTTPPathModifier](#httppathmodifier)_ |  false  | Path defines a path rewrite. |
+
+
 #### HTTPWasmCodeSource
 
 
@@ -3288,6 +3381,21 @@ _Appears in:_
 | `uri` | _string_ |  true  | URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to<br />validate the server certificate. |
 
 
+#### ReplaceRegexMatch
+
+
+
+
+
+_Appears in:_
+- [HTTPPathModifier](#httppathmodifier)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `pattern` | _string_ |  true  | Pattern matches a regular expression against the value of the HTTP Path.The regex string must<br />adhere to the syntax documented in https://github.com/google/re2/wiki/Syntax. |
+| `substitution` | _string_ |  true  | Substitution is an expression that replaces the matched portion.The expression may include numbered<br />capture groups that adhere to syntax documented in https://github.com/google/re2/wiki/Syntax. |
+
+
 #### RequestHeaderCustomTag
 
 
diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md
index fa4621480..0d1be81fc 100644
--- a/site/content/zh/latest/api/extension_types.md
+++ b/site/content/zh/latest/api/extension_types.md
@@ -26,6 +26,8 @@ API group.
 - [EnvoyPatchPolicy](#envoypatchpolicy)
 - [EnvoyPatchPolicyList](#envoypatchpolicylist)
 - [EnvoyProxy](#envoyproxy)
+- [HTTPRouteFilter](#httproutefilter)
+- [HTTPRouteFilterList](#httproutefilterlist)
 - [SecurityPolicy](#securitypolicy)
 - [SecurityPolicyList](#securitypolicylist)
 
@@ -1891,6 +1893,83 @@ _Appears in:_
 | `headersToBackend` | _string array_ |  false  | HeadersToBackend are the authorization response headers that will be added<br />to the original client request before sending it to the backend server.<br />Note that coexisting headers will be overridden.<br />If not specified, no authorization response headers will be added to the<br />original client request. |
 
 
+#### HTTPPathModifier
+
+
+
+
+
+_Appears in:_
+- [HTTPURLRewriteFilter](#httpurlrewritefilter)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `type` | _[HTTPPathModifierType](#httppathmodifiertype)_ |  true  |  |
+| `replaceRegexMatch` | _[ReplaceRegexMatch](#replaceregexmatch)_ |  true  | ReplaceRegexMatch defines a path regex rewrite. The path portions matched by the regex pattern are replaced by the defined substitution.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-regex-rewrite<br />Some examples:<br />(1) replaceRegexMatch:<br />      pattern: ^/service/([^/]+)(/.*)$<br />      substitution: \2/instance/\1<br />    Would transform /service/foo/v1/api into /v1/api/instance/foo.<br />(2) replaceRegexMatch:<br />      pattern: one<br />      substitution: two<br />    Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/two/zzz.<br />(3) replaceRegexMatch:<br />      pattern: ^(.*?)one(.*)$<br />      substitution: \1two\2<br />    Would transform /xxx/one/yyy/one/zzz into /xxx/two/yyy/one/zzz.<br />(3) replaceRegexMatch:<br />      pattern: (?i)/xxx/<br />      substitution: /yyy/<br />    Would transform path /aaa/XxX/bbb into /aaa/yyy/bbb (case-insensitive). |
+
+
+#### HTTPPathModifierType
+
+_Underlying type:_ _string_
+
+HTTPPathModifierType defines the type of path redirect or rewrite.
+
+_Appears in:_
+- [HTTPPathModifier](#httppathmodifier)
+
+| Value | Description |
+| ----- | ----------- |
+| `ReplaceRegexMatch` | RegexHTTPPathModifier This type of modifier indicates that the portions of the path that match the specified<br /> regex would be substituted with the specified substitution value<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/type/matcher/v3/regex.proto#type-matcher-v3-regexmatchandsubstitute<br /> | 
+
+
+#### HTTPRouteFilter
+
+
+
+HTTPRouteFilter is a custom Envoy Gateway HTTPRouteFilter which provides extended
+traffic processing options such as path regex rewrite, direct response and more.
+
+_Appears in:_
+- [HTTPRouteFilterList](#httproutefilterlist)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `apiVersion` | _string_ | |`gateway.envoyproxy.io/v1alpha1`
+| `kind` | _string_ | |`HTTPRouteFilter`
+| `metadata` | _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ |  true  | Refer to Kubernetes API documentation for fields of `metadata`. |
+| `spec` | _[HTTPRouteFilterSpec](#httproutefilterspec)_ |  true  | Spec defines the desired state of HTTPRouteFilter. |
+
+
+#### HTTPRouteFilterList
+
+
+
+HTTPRouteFilterList contains a list of HTTPRouteFilter resources.
+
+
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `apiVersion` | _string_ | |`gateway.envoyproxy.io/v1alpha1`
+| `kind` | _string_ | |`HTTPRouteFilterList`
+| `metadata` | _[ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#listmeta-v1-meta)_ |  true  | Refer to Kubernetes API documentation for fields of `metadata`. |
+| `items` | _[HTTPRouteFilter](#httproutefilter) array_ |  true  |  |
+
+
+#### HTTPRouteFilterSpec
+
+
+
+HTTPRouteFilterSpec defines the desired state of HTTPRouteFilter.
+
+_Appears in:_
+- [HTTPRouteFilter](#httproutefilter)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `urlRewrite` | _[HTTPURLRewriteFilter](#httpurlrewritefilter)_ |  false  |  |
+
+
 #### HTTPStatus
 
 _Underlying type:_ _integer_
@@ -1918,6 +1997,20 @@ _Appears in:_
 | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ |  false  | The maximum duration of an HTTP connection.<br />Default: unlimited. |
 
 
+#### HTTPURLRewriteFilter
+
+
+
+HTTPURLRewriteFilter define rewrites of HTTP URL components such as path and host
+
+_Appears in:_
+- [HTTPRouteFilterSpec](#httproutefilterspec)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `path` | _[HTTPPathModifier](#httppathmodifier)_ |  false  | Path defines a path rewrite. |
+
+
 #### HTTPWasmCodeSource
 
 
@@ -3288,6 +3381,21 @@ _Appears in:_
 | `uri` | _string_ |  true  | URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to<br />validate the server certificate. |
 
 
+#### ReplaceRegexMatch
+
+
+
+
+
+_Appears in:_
+- [HTTPPathModifier](#httppathmodifier)
+
+| Field | Type | Required | Description |
+| ---   | ---  | ---      | ---         |
+| `pattern` | _string_ |  true  | Pattern matches a regular expression against the value of the HTTP Path.The regex string must<br />adhere to the syntax documented in https://github.com/google/re2/wiki/Syntax. |
+| `substitution` | _string_ |  true  | Substitution is an expression that replaces the matched portion.The expression may include numbered<br />capture groups that adhere to syntax documented in https://github.com/google/re2/wiki/Syntax. |
+
+
 #### RequestHeaderCustomTag
 
 
diff --git a/test/e2e/tests/authorization_client_ip.go b/test/e2e/tests/authorization_client_ip.go
index 98c447054..8ac95845c 100644
--- a/test/e2e/tests/authorization_client_ip.go
+++ b/test/e2e/tests/authorization_client_ip.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -38,7 +39,7 @@ var AuthorizationClientIPTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
diff --git a/test/e2e/tests/authorization_default_action.go b/test/e2e/tests/authorization_default_action.go
index 820a0e099..7eaed07b3 100644
--- a/test/e2e/tests/authorization_default_action.go
+++ b/test/e2e/tests/authorization_default_action.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -38,7 +39,7 @@ var AuthorizationDefaultActionTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
diff --git a/test/e2e/tests/backend_health_check.go b/test/e2e/tests/backend_health_check.go
index 4936d3720..e2fc3d7d2 100644
--- a/test/e2e/tests/backend_health_check.go
+++ b/test/e2e/tests/backend_health_check.go
@@ -24,6 +24,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/test/utils/prometheus"
 )
 
@@ -46,7 +47,7 @@ var BackendHealthCheckActiveHTTPTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/backendtrafficpolicy_translation_failed.go b/test/e2e/tests/backendtrafficpolicy_translation_failed.go
index 9701596de..f76eee157 100644
--- a/test/e2e/tests/backendtrafficpolicy_translation_failed.go
+++ b/test/e2e/tests/backendtrafficpolicy_translation_failed.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -39,7 +40,7 @@ var FailedBackendTrafficPolicyDirectResponseTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/basic_auth.go b/test/e2e/tests/basic_auth.go
index 20c2e1b6a..bcedeb21d 100644
--- a/test/e2e/tests/basic_auth.go
+++ b/test/e2e/tests/basic_auth.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -38,7 +39,7 @@ var BasicAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -69,7 +70,7 @@ var BasicAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -97,7 +98,7 @@ var BasicAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -128,7 +129,7 @@ var BasicAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -160,7 +161,7 @@ var BasicAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/connection_limit.go b/test/e2e/tests/connection_limit.go
index d27b087ba..fca62d3a9 100644
--- a/test/e2e/tests/connection_limit.go
+++ b/test/e2e/tests/connection_limit.go
@@ -26,6 +26,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 	"github.com/envoyproxy/gateway/test/utils/prometheus"
 )
 
@@ -51,7 +52,7 @@ var ConnectionLimitTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/ext_auth_grpc_service.go b/test/e2e/tests/ext_auth_grpc_service.go
index 0618dc3a3..430496675 100644
--- a/test/e2e/tests/ext_auth_grpc_service.go
+++ b/test/e2e/tests/ext_auth_grpc_service.go
@@ -20,6 +20,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -42,7 +43,7 @@ var GRPCExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -86,7 +87,7 @@ var GRPCExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -127,7 +128,7 @@ var GRPCExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -169,7 +170,7 @@ var GRPCExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/ext_auth_http_backend.go b/test/e2e/tests/ext_auth_http_backend.go
index 7032bdc2a..326d73437 100644
--- a/test/e2e/tests/ext_auth_http_backend.go
+++ b/test/e2e/tests/ext_auth_http_backend.go
@@ -20,6 +20,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -40,7 +41,7 @@ var HTTPBackendExtAuthTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
diff --git a/test/e2e/tests/ext_auth_http_service.go b/test/e2e/tests/ext_auth_http_service.go
index f610898ab..d74155904 100644
--- a/test/e2e/tests/ext_auth_http_service.go
+++ b/test/e2e/tests/ext_auth_http_service.go
@@ -20,6 +20,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -42,7 +43,7 @@ var HTTPExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -89,7 +90,7 @@ var HTTPExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -130,7 +131,7 @@ var HTTPExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -174,7 +175,7 @@ var HTTPExtAuthTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/ext_proc.go b/test/e2e/tests/ext_proc.go
index b4bd96d45..dbbb4defa 100644
--- a/test/e2e/tests/ext_proc.go
+++ b/test/e2e/tests/ext_proc.go
@@ -20,6 +20,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -40,7 +41,7 @@ var ExtProcTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -89,7 +90,7 @@ var ExtProcTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -134,7 +135,7 @@ var ExtProcTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/header_settings.go b/test/e2e/tests/header_settings.go
index 32f0d7310..ee5be4c3d 100644
--- a/test/e2e/tests/header_settings.go
+++ b/test/e2e/tests/header_settings.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -38,7 +39,7 @@ var HeaderSettingsTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/listener_health_check.go b/test/e2e/tests/listener_health_check.go
index 2e640e15b..483a54caa 100644
--- a/test/e2e/tests/listener_health_check.go
+++ b/test/e2e/tests/listener_health_check.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -38,7 +39,7 @@ var ListenerHealthCheckTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/load_balancing.go b/test/e2e/tests/load_balancing.go
index 346a25965..9f368dc01 100644
--- a/test/e2e/tests/load_balancing.go
+++ b/test/e2e/tests/load_balancing.go
@@ -32,6 +32,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -60,7 +61,7 @@ var RoundRobinLoadBalancingTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
@@ -148,7 +149,7 @@ var ConsistentHashSourceIPLoadBalancingTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
@@ -196,7 +197,7 @@ var ConsistentHashHeaderLoadBalancingTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
@@ -243,7 +244,7 @@ var ConsistentHashCookieLoadBalancingTest = suite.ConformanceTest{
 
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 			Name:      gwapiv1.ObjectName(gwNN.Name),
 		}
diff --git a/test/e2e/tests/local_ratelimit.go b/test/e2e/tests/local_ratelimit.go
index 896ecbba5..a4c1accee 100644
--- a/test/e2e/tests/local_ratelimit.go
+++ b/test/e2e/tests/local_ratelimit.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -40,7 +41,7 @@ var LocalRateLimitSpecificUserTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -125,7 +126,7 @@ var LocalRateLimitAllTrafficTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/merge_gateways.go b/test/e2e/tests/merge_gateways.go
index fee4fd718..c00cb3e84 100644
--- a/test/e2e/tests/merge_gateways.go
+++ b/test/e2e/tests/merge_gateways.go
@@ -22,6 +22,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -103,7 +104,7 @@ var MergeGatewaysTest = suite.ConformanceTest{
 			// Create Gateway first to make sure there's no HTTPRoute attach to it.
 			conflictedGateway := gwapiv1.Gateway{
 				TypeMeta: metav1.TypeMeta{
-					Kind:       gatewayapi.KindGateway,
+					Kind:       resource.KindGateway,
 					APIVersion: gwapiv1.GroupVersion.String(),
 				},
 				ObjectMeta: metav1.ObjectMeta{
@@ -136,11 +137,11 @@ var MergeGatewaysTest = suite.ConformanceTest{
 				SupportedKinds: []gwapiv1.RouteGroupKind{
 					{
 						Group: gatewayapi.GroupPtr(gwapiv1.GroupName),
-						Kind:  gatewayapi.KindHTTPRoute,
+						Kind:  resource.KindHTTPRoute,
 					},
 					{
 						Group: gatewayapi.GroupPtr(gwapiv1.GroupName),
-						Kind:  gatewayapi.KindGRPCRoute,
+						Kind:  resource.KindGRPCRoute,
 					},
 				},
 				Conditions: []metav1.Condition{{
@@ -155,7 +156,7 @@ var MergeGatewaysTest = suite.ConformanceTest{
 			// Create HTTPRoute at last to make sure it will be referenced by the conflicted listener in Gateway.
 			conflictedHTTPRoute := gwapiv1.HTTPRoute{
 				TypeMeta: metav1.TypeMeta{
-					Kind:       gatewayapi.KindHTTPRoute,
+					Kind:       resource.KindHTTPRoute,
 					APIVersion: gwapiv1.GroupVersion.String(),
 				},
 				ObjectMeta: metav1.ObjectMeta{
@@ -180,7 +181,7 @@ var MergeGatewaysTest = suite.ConformanceTest{
 									BackendRef: gwapiv1.BackendRef{
 										BackendObjectReference: gwapiv1.BackendObjectReference{
 											Group: gatewayapi.GroupPtr(""),
-											Kind:  gatewayapi.KindPtr(gatewayapi.KindService),
+											Kind:  gatewayapi.KindPtr(resource.KindService),
 											Name:  "infra-backend-v3",
 											Port:  gatewayapi.PortNumPtr(8080),
 										},
diff --git a/test/e2e/tests/oidc.go b/test/e2e/tests/oidc.go
index 2bc40d3eb..4fcbabdc4 100644
--- a/test/e2e/tests/oidc.go
+++ b/test/e2e/tests/oidc.go
@@ -28,6 +28,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 const (
@@ -61,7 +62,7 @@ var OIDCTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -153,7 +154,7 @@ var OIDCTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/securitypolicy_transaltion_failed.go b/test/e2e/tests/securitypolicy_transaltion_failed.go
index 539fd4f72..57cf4c397 100644
--- a/test/e2e/tests/securitypolicy_transaltion_failed.go
+++ b/test/e2e/tests/securitypolicy_transaltion_failed.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -39,7 +40,7 @@ var FailedSecurityPolicyDirectResponseTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/wasm_http.go b/test/e2e/tests/wasm_http.go
index 6ce3078f3..3dee419be 100644
--- a/test/e2e/tests/wasm_http.go
+++ b/test/e2e/tests/wasm_http.go
@@ -19,6 +19,7 @@ import (
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
 
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 func init() {
@@ -39,7 +40,7 @@ var HTTPWasmTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
@@ -85,7 +86,7 @@ var HTTPWasmTest = suite.ConformanceTest{
 
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
 				Name:      gwapiv1.ObjectName(gwNN.Name),
 			}
diff --git a/test/e2e/tests/wasm_oci.go b/test/e2e/tests/wasm_oci.go
index 69c6b0ad6..b0d664469 100644
--- a/test/e2e/tests/wasm_oci.go
+++ b/test/e2e/tests/wasm_oci.go
@@ -41,6 +41,7 @@ import (
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
 	"github.com/envoyproxy/gateway/internal/gatewayapi"
+	"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
 )
 
 const (
@@ -85,7 +86,7 @@ var OCIWasmTest = suite.ConformanceTest{
 		// Wait for the EnvoyExtensionPolicy to be accepted
 		ancestorRef := gwapiv1a2.ParentReference{
 			Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-			Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+			Kind:      gatewayapi.KindPtr(resource.KindGateway),
 			Namespace: gatewayapi.NamespacePtr(testNS),
 			Name:      gwapiv1.ObjectName(testGW),
 		}
@@ -188,7 +189,7 @@ var OCIWasmTest = suite.ConformanceTest{
 			// Wait for the EnvoyExtensionPolicy to be failed due to missing pull secret
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(testNS),
 				Name:      gwapiv1.ObjectName(testGW),
 			}
@@ -223,7 +224,7 @@ var OCIWasmTest = suite.ConformanceTest{
 			// Wait for the EnvoyExtensionPolicy to be failed due to missing pull secret
 			ancestorRef := gwapiv1a2.ParentReference{
 				Group:     gatewayapi.GroupPtr(gwapiv1.GroupName),
-				Kind:      gatewayapi.KindPtr(gatewayapi.KindGateway),
+				Kind:      gatewayapi.KindPtr(resource.KindGateway),
 				Namespace: gatewayapi.NamespacePtr(testNS),
 				Name:      gwapiv1.ObjectName(testGW),
 			}