Repository: Kong/kubernetes-ingress-controller
Pull request #2424 (2022-04-19 22:47:20)

feat(controllers) add ReferencePolicy controller
**What this PR does / why we need it**:
Add a controller to watch Gateway ReferencePolicies and associated store functions and RBAC permissions.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: part of #2407 

**Special notes for your reviewer**:
Just controller scaffolding, doesn't actually do anything with the policies we ingest yet.

This controller is simple enough (just ingest everything we can see, no cross-resource validation needed) that it probably could be handled by the generator, but none of the other Gateway resources use it, so I hand-rolled it.

This drops policies into the store for (future PR) evaluation at configuration generation time. It's probably technically possible to filter out Routes based on their BackendRefs and the ReferencePolicy set entirely within the controllers, but we'd need to requeue stuff like crazy on ReferencePolicy changes, so config gen time seems cleaner to implement in our current architecture. May be a reasonable open question which is better, but it's easy to rip out the store parts if we want to handle everything during controller reconciles.

**PR Readiness Checklist**:

Complete these before marking the PR as `ready to review`:

- [ ] ~the `CHANGELOG.md` release notes have been updated to reflect any significant (and particularly user-facing) changes introduced by this PR~ no user-facing change from this yet



Patch:
diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml
index e87048ce3..d83d86c2e 100644
--- a/.github/workflows/codeql.yaml
+++ b/.github/workflows/codeql.yaml
@@ -28,10 +28,10 @@ jobs:
     - name: Checkout repository
       uses: actions/checkout@v3
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
+      uses: github/codeql-action/init@v2
       with:
         languages: ${{ matrix.language }}
     - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      uses: github/codeql-action/autobuild@v2
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml
index 8b19e6e8e..ae4a5bfce 100644
--- a/.github/workflows/nightly.yaml
+++ b/.github/workflows/nightly.yaml
@@ -22,6 +22,8 @@ jobs:
           echo 'type=schedule,pattern=nightly,suffix=-redhat' >> $GITHUB_ENV
           echo "type=schedule,pattern={{date 'YYYY-MM-DD'}},suffix=-redhat" >> $GITHUB_ENV
           echo 'EOF' >> $GITHUB_ENV
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v1
       - name: Cache Docker layers
@@ -38,13 +40,13 @@ jobs:
           password: ${{ secrets.DOCKER_TOKEN }}
       - name: Docker meta
         id: meta
-        uses: docker/metadata-action@v3.7.0
+        uses: docker/metadata-action@v3.8.0
         with:
           images: kong/nightly-ingress-controller
           tags: ${{ env.TAGS_STANDARD }}
       - name: Docker meta (redhat)
         id: meta_redhat
-        uses: docker/metadata-action@v3.7.0
+        uses: docker/metadata-action@v3.8.0
         with:
           images: kong/nightly-ingress-controller
           flavor: |
@@ -59,6 +61,7 @@ jobs:
           cache-from: type=local,src=/tmp/.buildx-cache
           cache-to: type=local,dest=/tmp/.buildx-cache
           target: builder
+          platforms: linux/amd64, linux/arm64
           build-args: |
             TAG=${{ steps.meta.outputs.version }}
             COMMIT=${{ github.sha }}
@@ -72,6 +75,7 @@ jobs:
           tags: ${{ steps.meta.outputs.tags }}
           cache-from: type=local,src=/tmp/.buildx-cache
           target: distroless
+          platforms: linux/amd64, linux/arm64
           build-args: |
             TAG=${{ steps.meta.outputs.version }}
             COMMIT=${{ github.sha }}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 70c5dc062..b6ce8f8a7 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -75,6 +75,8 @@ jobs:
           echo "" >> $GITHUB_ENV
           echo 'type=raw,value=${{ steps.semver_parser.outputs.major }}.${{ steps.semver_parser.outputs.minor }},suffix=-redhat' >> $GITHUB_ENV
           echo 'EOF' >> $GITHUB_ENV
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v1
       - name: Set up Docker Buildx
         uses: docker/setup-buildx-action@v1
       - name: Cache Docker layers
@@ -91,7 +93,7 @@ jobs:
           password: ${{ secrets.DOCKER_TOKEN }}
       - name: Docker meta
         id: meta
-        uses: docker/metadata-action@v3.7.0
+        uses: docker/metadata-action@v3.8.0
         with:
           images: kong/kubernetes-ingress-controller
           flavor: |
@@ -99,7 +101,7 @@ jobs:
           tags: ${{ env.TAGS_STANDARD }}${{ env.TAGS_SUPPLEMENTAL }}
       - name: Docker meta (redhat)
         id: meta_redhat
-        uses: docker/metadata-action@v3.7.0
+        uses: docker/metadata-action@v3.8.0
         with:
           images: kong/kubernetes-ingress-controller
           flavor: |
@@ -114,6 +116,7 @@ jobs:
           cache-from: type=local,src=/tmp/.buildx-cache
           cache-to: type=local,dest=/tmp/.buildx-cache
           target: builder
+          platforms: linux/amd64, linux/arm64
           build-args: |
             TAG=${{ steps.meta.outputs.version }}
             COMMIT=${{ github.sha }}
@@ -127,6 +130,7 @@ jobs:
           tags: ${{ steps.meta.outputs.tags }}
           cache-from: type=local,src=/tmp/.buildx-cache
           target: distroless
+          platforms: linux/amd64, linux/arm64
           build-args: |
             TAG=${{ steps.meta.outputs.version }}
             COMMIT=${{ github.sha }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 715ce012e..2720abf3e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -72,9 +72,16 @@
   `allowedRoutes` filters are merged into generated listeners with the same
   protocol.
   [#2389](https://github.com/Kong/kubernetes-ingress-controller/issues/2389)
+- Added `--skip-ca-certificates` flag to ignore CA certificate resources for
+  [use with multi-workspace environments](https://github.com/Kong/deck/blob/main/CHANGELOG.md#v1120).
+  [#2341](https://github.com/Kong/kubernetes-ingress-controller/issues/2341)
 
 #### Fixed
 
+- Fixed a race condition in the newer Gateway route controllers which could
+  trigger when an object's status was updated shortly after the object was
+  cached in the dataplane client.
+  [#2446](https://github.com/Kong/kubernetes-ingress-controller/issues/2446)
 - Added a mechanism to retry the initial connection to the Kong
   Admin API on controller start to fix an issue where the controller
   pod could crash loop on start when waiting for Gateway readiness 
diff --git a/Dockerfile b/Dockerfile
index b94f10b24..3ee33c025 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,10 @@ COPY internal/ internal/
 ARG TAG
 ARG COMMIT
 ARG REPO_INFO
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager -ldflags "-s -w -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Repo=$REPO_INFO" ./internal/cmd/main.go
+ARG TARGETARCH="amd64"
+
+RUN CGO_ENABLED=0 GOOS=linux GOARCH="${TARGETARCH}" GO111MODULE=on go build -a -o manager -ldflags "-s -w -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Repo=$REPO_INFO" ./internal/cmd/main.go
+
 
 ### FIPS 140-2 binary
 # Build the manager binary
@@ -39,12 +42,16 @@ COPY internal/ internal/
 ARG TAG
 ARG COMMIT
 ARG REPO_INFO
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager -ldflags "-s -w -X github.com/kong/kubernetes-ingress-controller/v2/internal/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/metadata.Repo=$REPO_INFO" ./internal/cmd/fips/main.go
+ARG TARGETARCH="amd64"
+
+RUN CGO_ENABLED=0 GOOS=linux GOARCH="${TARGETARCH}" GO111MODULE=on go build -a -o manager -ldflags "-s -w -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Repo=$REPO_INFO" ./internal/cmd/fips/main.go
 
 # Build a manager binary with debug symbols and download Delve
 FROM builder as builder-delve
 
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager-debug -gcflags=all="-N -l" -ldflags "-X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Repo=$REPO_INFO" ./internal/cmd/main.go
+ARG TARGETARCH="amd64"
+
+RUN CGO_ENABLED=0 GOOS=linux GOARCH="${TARGETARCH}" GO111MODULE=on go build -a -o manager-debug -gcflags=all="-N -l" -ldflags "-X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Release=$TAG -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Commit=$COMMIT -X github.com/kong/kubernetes-ingress-controller/v2/internal/manager/metadata.Repo=$REPO_INFO" ./internal/cmd/main.go
 
 ### Debug
 # Create an image that runs a debug build with a Delve remote server on port 2345
@@ -74,6 +81,8 @@ WORKDIR /
 COPY --from=builder /workspace/manager .
 USER 65532:65532
 
+ARG TARGETARCH="amd64"
+
 ENTRYPOINT ["/manager"]
 
 ### RHEL
diff --git a/PROJECT b/PROJECT
index df781d39e..d89c47a2e 100644
--- a/PROJECT
+++ b/PROJECT
@@ -79,4 +79,9 @@ resources:
   kind: UDPRoute
   path: github.com/kubernetes-sigs/gateway-api/apis/v1alpha2
   version: v1alpha2
+- controller: true
+  domain: networking.k8s.io
+  group: gateway
+  kind: ReferencePolicy
+  version: v1alpha2
 version: "3"
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index 39c907cea..5c6dbc9b4 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -232,6 +232,32 @@ rules:
   verbs:
   - get
   - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - gateway.networking.k8s.io
   resources:
diff --git a/deploy/single/all-in-one-dbless-k4k8s-enterprise.yaml b/deploy/single/all-in-one-dbless-k4k8s-enterprise.yaml
index 90b497725..4ceabc8fa 100644
--- a/deploy/single/all-in-one-dbless-k4k8s-enterprise.yaml
+++ b/deploy/single/all-in-one-dbless-k4k8s-enterprise.yaml
@@ -1182,6 +1182,32 @@ rules:
   verbs:
   - get
   - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - gateway.networking.k8s.io
   resources:
diff --git a/deploy/single/all-in-one-dbless.yaml b/deploy/single/all-in-one-dbless.yaml
index 0f2180492..fc3bf4954 100644
--- a/deploy/single/all-in-one-dbless.yaml
+++ b/deploy/single/all-in-one-dbless.yaml
@@ -1182,6 +1182,32 @@ rules:
   verbs:
   - get
   - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - gateway.networking.k8s.io
   resources:
diff --git a/deploy/single/all-in-one-postgres-enterprise.yaml b/deploy/single/all-in-one-postgres-enterprise.yaml
index 917167e05..e4ec5a474 100644
--- a/deploy/single/all-in-one-postgres-enterprise.yaml
+++ b/deploy/single/all-in-one-postgres-enterprise.yaml
@@ -1182,6 +1182,32 @@ rules:
   verbs:
   - get
   - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - gateway.networking.k8s.io
   resources:
diff --git a/deploy/single/all-in-one-postgres.yaml b/deploy/single/all-in-one-postgres.yaml
index 275451b1c..2fdebae39 100644
--- a/deploy/single/all-in-one-postgres.yaml
+++ b/deploy/single/all-in-one-postgres.yaml
@@ -1182,6 +1182,32 @@ rules:
   verbs:
   - get
   - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - gateway.networking.k8s.io
+  resources:
+  - referencepolicies/status
+  verbs:
+  - get
+  - patch
+  - update
 - apiGroups:
   - gateway.networking.k8s.io
   resources:
diff --git a/go.mod b/go.mod
index b039bde4a..edf9eeead 100644
--- a/go.mod
+++ b/go.mod
@@ -13,28 +13,28 @@ require (
 	github.com/ghodss/yaml v1.0.0
 	github.com/go-logr/logr v1.2.3
 	github.com/google/uuid v1.3.0
-	github.com/kong/deck v1.11.0
+	github.com/kong/deck v1.12.0
 	github.com/kong/go-kong v0.29.0
 	github.com/kong/kubernetes-testing-framework v0.13.3
 	github.com/lithammer/dedent v1.1.0
 	github.com/miekg/dns v1.1.48
-	github.com/mitchellh/mapstructure v1.4.3
+	github.com/mitchellh/mapstructure v1.5.0
 	github.com/prometheus/client_golang v1.12.1
-	github.com/prometheus/common v0.33.0
+	github.com/prometheus/common v0.34.0
 	github.com/sethvargo/go-password v0.2.0
 	github.com/sirupsen/logrus v1.8.1
 	github.com/spf13/cobra v1.4.0
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.7.1
-	github.com/tidwall/gjson v1.14.0
-	golang.org/x/net v0.0.0-20220325170049-de3da57026de
-	google.golang.org/api v0.74.0
-	google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb
-	k8s.io/api v0.23.5
+	github.com/tidwall/gjson v1.14.1
+	golang.org/x/net v0.0.0-20220412020605-290c469a71a5
+	google.golang.org/api v0.77.0
+	google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4
+	k8s.io/api v0.23.6
 	k8s.io/apiextensions-apiserver v0.23.5
-	k8s.io/apimachinery v0.23.5
-	k8s.io/client-go v0.23.5
-	k8s.io/component-base v0.23.5
+	k8s.io/apimachinery v0.23.6
+	k8s.io/client-go v0.23.6
+	k8s.io/component-base v0.23.6
 	knative.dev/networking v0.0.0-20220302134042-e8b2eb995165
 	knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77
 	sigs.k8s.io/controller-runtime v0.11.2
@@ -45,14 +45,14 @@ require (
 )
 
 require (
-	cloud.google.com/go/compute v1.5.0 // indirect
+	cloud.google.com/go/compute v1.6.0 // indirect
 	github.com/Masterminds/goutils v1.1.1 // indirect
 	github.com/Masterminds/semver v1.5.0 // indirect
 	github.com/Microsoft/go-winio v0.5.2 // indirect
 	github.com/PuerkitoBio/purell v1.1.1 // indirect
 	github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
-	github.com/cenkalti/backoff/v4 v4.1.2 // indirect
+	github.com/cenkalti/backoff/v4 v4.1.3 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/containerd/containerd v1.6.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
@@ -76,7 +76,7 @@ require (
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
-	github.com/googleapis/gax-go/v2 v2.2.0 // indirect
+	github.com/googleapis/gax-go/v2 v2.3.0 // indirect
 	github.com/googleapis/gnostic v0.5.5 // indirect
 	github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
 	github.com/hashicorp/go-memdb v1.3.2 // indirect
@@ -106,12 +106,12 @@ require (
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect
 	github.com/sergi/go-diff v1.2.0 // indirect
-	github.com/shirou/gopsutil/v3 v3.22.1 // indirect
+	github.com/shirou/gopsutil/v3 v3.22.3 // indirect
 	github.com/ssgelm/cookiejarparser v1.0.1 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
-	github.com/tklauser/go-sysconf v0.3.9 // indirect
-	github.com/tklauser/numcpus v0.3.0 // indirect
+	github.com/tklauser/go-sysconf v0.3.10 // indirect
+	github.com/tklauser/numcpus v0.4.0 // indirect
 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
@@ -121,20 +121,20 @@ require (
 	github.com/yusufpapurcu/wmi v1.2.2 // indirect
 	go.opencensus.io v0.23.0 // indirect
 	go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
-	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
+	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
 	golang.org/x/mod v0.5.1 // indirect
-	golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
+	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
-	golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect
+	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
 	golang.org/x/tools v0.1.9 // indirect
-	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
 	gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/grpc v1.45.0 // indirect
-	google.golang.org/protobuf v1.27.1 // indirect
+	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
diff --git a/go.sum b/go.sum
index 821438354..dc6875ed4 100644
--- a/go.sum
+++ b/go.sum
@@ -42,8 +42,9 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
 cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
 cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
 cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
-cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM=
 cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
+cloud.google.com/go/compute v1.6.0 h1:XdQIN5mdPTSBVwSIVDuY5e8ZzVAccsHvD3qTEz4zIps=
+cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
 cloud.google.com/go/container v1.2.0 h1:LPKlQa4XfBTWdaBSDx/KQ/v45l8FDRzSV0tDpU6e/38=
 cloud.google.com/go/container v1.2.0/go.mod h1:Cj2AgMsCUfMVfbGh0Fx7u5Ah/qeC0ajLrqqGGiAdCGw=
 cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
@@ -206,8 +207,9 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k
 github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
 github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
 github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
 github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
+github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -672,8 +674,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
 github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
-github.com/googleapis/gax-go/v2 v2.2.0 h1:s7jOdKSaksJVOxE0Y/S32otcfiP+UQ0cL8/GTKaONwE=
 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
+github.com/googleapis/gax-go/v2 v2.3.0 h1:nRJtk3y8Fm770D42QV6T90ZnvFZyk7agSo3Q+Z9p3WI=
+github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
 github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
 github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
 github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
@@ -832,8 +835,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
 github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
 github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/kong/deck v1.11.0 h1:qq21lY1cKuVxqjyc9+k9HL11vLXo7dhopElT5ml06wE=
-github.com/kong/deck v1.11.0/go.mod h1:pt7i/oXWUMs041YKSevCHJIN1fgmcsabJQLSrUpgBqo=
+github.com/kong/deck v1.12.0 h1:ng8jeic8iaqvYRHRa3yE4hZ5zIQKMqOiuEvSKOnwREU=
+github.com/kong/deck v1.12.0/go.mod h1:Mno+qSa9flMG6peFeQPoWOLNFRPuP7amSfuksxPt/3k=
 github.com/kong/go-kong v0.29.0 h1:cD4roBBMt2FWj+jEieDpw5krCJpkdm2TMc4OUVSgSGc=
 github.com/kong/go-kong v0.29.0/go.mod h1:BkSkCmi9wBEX00VRBGqhpnNcXqccm13N0sYP5VDE4n8=
 github.com/kong/kubernetes-testing-framework v0.13.3 h1:b90LCz3VwxbC2S6HNG1YYMEUhrpr1Q6j16ErcyWWO1s=
@@ -941,8 +944,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
 github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
 github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
@@ -1113,8 +1117,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
 github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
 github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
-github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE=
-github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
+github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE=
+github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
 github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -1177,8 +1181,8 @@ github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc
 github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
 github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
 github.com/shirou/gopsutil/v3 v3.21.10/go.mod h1:t75NhzCZ/dYyPQjyQmrAYP6c8+LCdFANeBMdLPCNnew=
-github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w=
-github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
+github.com/shirou/gopsutil/v3 v3.22.3 h1:UebRzEomgMpv61e3hgD1tGooqX5trFbdU/ehphbHd00=
+github.com/shirou/gopsutil/v3 v3.22.3/go.mod h1:D01hZJ4pVHPpCTZ3m3T2+wDF2YAGfd+H4ifUguaQzHM=
 github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
 github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -1260,17 +1264,20 @@ github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0
 github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
 github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
 github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
-github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
 github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
+github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
 github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
 github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
-github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
 github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
-github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
+github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
+github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
+github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
+github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -1438,8 +1445,9 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
+golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1548,8 +1556,9 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
 golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4=
+golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1569,8 +1578,9 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
-golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
 golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1706,13 +1716,13 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q=
 golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1855,8 +1865,9 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
 gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
 google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@@ -1898,8 +1909,9 @@ google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tD
 google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
 google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
 google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
-google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE=
 google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
+google.golang.org/api v0.77.0 h1:msijLTxwkJ7Jub5tv9KBVCKtHOQwnvnvkX7ErFFCVxY=
+google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1992,8 +2004,11 @@ google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2
 google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb h1:0m9wktIpOxGw+SSKmydXWB3Z3GTfcPP6+q75HCQa6HI=
 google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
+google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4 h1:myaecH64R0bIEDjNORIel4iXubqzaHU1K2z8ajBwWcM=
+google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -2046,8 +2061,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2108,8 +2124,9 @@ k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
 k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
 k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
 k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
-k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA=
 k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
+k8s.io/api v0.23.6 h1:yOK34wbYECH4RsJbQ9sfkFK3O7f/DUHRlzFehkqZyVw=
+k8s.io/api v0.23.6/go.mod h1:1kFaYxGCFHYp3qd6a85DAj/yW8aVD6XLZMqJclkoi9g=
 k8s.io/apiextensions-apiserver v0.22.5/go.mod h1:tIXeZ0BrDxUb1PoAz+tgOz43Zi1Bp4BEEqVtUccMJbE=
 k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
 k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
@@ -2118,8 +2135,9 @@ k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp
 k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
 k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
 k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U=
-k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0=
 k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
+k8s.io/apimachinery v0.23.6 h1:RH1UweWJkWNTlFx0D8uxOpaU1tjIOvVVWV/bu5b3/NQ=
+k8s.io/apimachinery v0.23.6/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
 k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
 k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
 k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
@@ -2129,8 +2147,9 @@ k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
 k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
 k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
 k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y=
-k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8=
 k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
+k8s.io/client-go v0.23.6 h1:7h4SctDVQAQbkHQnR4Kzi7EyUyvla5G1pFWf4+Od7hQ=
+k8s.io/client-go v0.23.6/go.mod h1:Umt5icFOMLV/+qbtZ3PR0D+JA6lvvb3syzodv4irpK4=
 k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
 k8s.io/code-generator v0.22.5/go.mod h1:sbdWCOVob+KaQ5O7xs8PNNaCTpbWVqNgA6EPwLOmRNk=
 k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
@@ -2138,8 +2157,9 @@ k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeY
 k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
 k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
 k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI=
-k8s.io/component-base v0.23.5 h1:8qgP5R6jG1BBSXmRYW+dsmitIrpk8F/fPEvgDenMCCE=
 k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
+k8s.io/component-base v0.23.6 h1:8dhVZ4VrRcNdV2EGjl8tj8YOHwX6ysgCGMJ2Oyy0NW8=
+k8s.io/component-base v0.23.6/go.mod h1:FGMPeMrjYu0UZBSAFcfloVDplj9IvU+uRMTOdE23Fj0=
 k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
 k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
 k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
diff --git a/internal/adminapi/client.go b/internal/adminapi/client.go
index 2e96bce6a..1cc92274a 100644
--- a/internal/adminapi/client.go
+++ b/internal/adminapi/client.go
@@ -90,38 +90,45 @@ func MakeHTTPClient(opts *HTTPClientOpts) (*http.Client, error) {
 			"please remove one or the other")
 	}
 
+	// if the caller has supplied either the cert or the key but not both, this is
+	// erroneous input.
+	if opts.TLSClientCert != "" && opts.TLSClientKey == "" {
+		return nil, fmt.Errorf("client certificate was provided, but the client key was not")
+	}
+	if opts.TLSClientKey != "" && opts.TLSClientCert == "" {
+		return nil, fmt.Errorf("client key was provided, but the client certificate was not")
+	}
+
+	var clientCert, clientKey []byte
+	var err error
+
 	// if a path to the certificate or key has been provided, retrieve the file contents
 	if opts.TLSClientCertPath != "" {
 		tlsClientCertPath := opts.TLSClientCertPath
-		tlsClientCert, err := os.ReadFile(tlsClientCertPath)
+		clientCert, err = os.ReadFile(tlsClientCertPath)
 		if err != nil {
 			return nil, fmt.Errorf("failed to read certificate file %s: %w", tlsClientCertPath, err)
 		}
-		opts.TLSClientCert = string(tlsClientCert)
 	}
 	if opts.TLSClientKeyPath != "" {
 		tlsClientKeyPath := opts.TLSClientKeyPath
-		tlsClientKey, err := os.ReadFile(tlsClientKeyPath)
+		clientKey, err = os.ReadFile(tlsClientKeyPath)
 		if err != nil {
 			return nil, fmt.Errorf("failed to read key file %s: %w", tlsClientKeyPath, err)
 		}
-		opts.TLSClientKey = string(tlsClientKey)
 	}
-
-	// if the caller has supplied either the cert or the key but not both, this is
-	// erroneous input.
-	if opts.TLSClientCert != "" && opts.TLSClientKey == "" {
-		return nil, fmt.Errorf("client certificate was provided, but the client key was not")
+	if opts.TLSClientCert != "" {
+		clientCert = []byte(opts.TLSClientCert)
 	}
-	if opts.TLSClientKey != "" && opts.TLSClientCert == "" {
-		return nil, fmt.Errorf("client key was provided, but the client certificate was not")
+	if opts.TLSClientKey != "" {
+		clientKey = []byte(opts.TLSClientKey)
 	}
 
-	if opts.TLSClientCert != "" && opts.TLSClientKey != "" {
+	if len(clientCert) != 0 && len(clientKey) != 0 {
 		// Read the key pair to create certificate
-		cert, err := tls.X509KeyPair([]byte(opts.TLSClientCert), []byte(opts.TLSClientKey))
+		cert, err := tls.X509KeyPair(clientCert, clientKey)
 		if err != nil {
-			return nil, fmt.Errorf("failed to load kong-admin-tls-client-cert and kong-admin-tls-client-key certificate: %w", err)
+			return nil, fmt.Errorf("failed to load client certificate: %w", err)
 		}
 		tlsConfig.Certificates = []tls.Certificate{cert}
 	}
diff --git a/internal/admission/server.go b/internal/admission/server.go
index eb95b24e6..c96af9ca6 100644
--- a/internal/admission/server.go
+++ b/internal/admission/server.go
@@ -123,32 +123,32 @@ func (a RequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 	data, err := io.ReadAll(r.Body)
 	if err != nil {
-		a.Logger.Errorf("failed to read request from client: %v", err)
+		a.Logger.WithError(err).Error("failed to read request from client")
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
 	review := admission.AdmissionReview{}
 	if err := json.Unmarshal(data, &review); err != nil {
-		a.Logger.Errorf("failed to parse AdmissionReview object: %v", err)
+		a.Logger.WithError(err).Error("failed to parse AdmissionReview object")
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
 	response, err := a.handleValidation(r.Context(), *review.Request)
 	if err != nil {
-		a.Logger.Errorf("failed to run validation: %v", err)
+		a.Logger.WithError(err).Error("failed to run validation")
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
 	review.Response = response
 	data, err = json.Marshal(review)
 	if err != nil {
-		a.Logger.Errorf("failed to marshal response: %v", err)
+		a.Logger.WithError(err).Error("failed to marshal response")
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
 	_, err = w.Write(data)
 	if err != nil {
-		a.Logger.Errorf("failed to write response: %v", err)
+		a.Logger.WithError(err).Error("failed to write response")
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
diff --git a/internal/admission/validator.go b/internal/admission/validator.go
index acff8443f..74fd06894 100644
--- a/internal/admission/validator.go
+++ b/internal/admission/validator.go
@@ -89,7 +89,7 @@ func (validator KongHTTPValidator) ValidateConsumer(
 	c, err := validator.ConsumerSvc.Get(ctx, &consumer.Username)
 	if err != nil {
 		if !kong.IsNotFoundErr(err) {
-			validator.Logger.Errorf("failed to fetch consumer from kong: %v", err)
+			validator.Logger.WithError(err).Error("failed to fetch consumer from kong")
 			return false, ErrTextConsumerUnretrievable, err
 		}
 	}
diff --git a/internal/cmd/rootcmd/env.go b/internal/cmd/rootcmd/env.go
index c960d824d..db57e88a1 100644
--- a/internal/cmd/rootcmd/env.go
+++ b/internal/cmd/rootcmd/env.go
@@ -14,14 +14,15 @@ const envKeyPrefix = "CONTROLLER_"
 // bindEnvVars, for each flag defined on `cmd` (local or parent persistent), looks up the corresponding environment
 // variable and (if the flag is unset) takes that environment variable value as the flag value.
 func bindEnvVars(cmd *cobra.Command, _ []string) (err error) {
+	var envKey string
 	defer func() {
 		if r := recover(); r != nil {
-			err = fmt.Errorf("environment binding failed: %v", r)
+			err = fmt.Errorf("environment binding failed for variable %s: %v", envKey, r)
 		}
 	}()
 
 	cmd.Flags().VisitAll(func(f *pflag.Flag) {
-		envKey := fmt.Sprintf("%s%s", envKeyPrefix, strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_")))
+		envKey = fmt.Sprintf("%s%s", envKeyPrefix, strings.ToUpper(strings.ReplaceAll(f.Name, "-", "_")))
 
 		if f.Changed {
 			return // flags take precedence over environment variables
diff --git a/internal/controllers/gateway/referencepolicy_controller.go b/internal/controllers/gateway/referencepolicy_controller.go
new file mode 100644
index 000000000..7eef3b4a6
--- /dev/null
+++ b/internal/controllers/gateway/referencepolicy_controller.go
@@ -0,0 +1,103 @@
+/*
+Copyright 2021 Kong, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package gateway
+
+import (
+	"context"
+
+	"github.com/go-logr/logr"
+	"k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/runtime"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller"
+	"sigs.k8s.io/controller-runtime/pkg/handler"
+	"sigs.k8s.io/controller-runtime/pkg/source"
+	gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
+
+	"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane"
+)
+
+// ReferencePolicyReconciler reconciles a ReferencePolicy object
+type ReferencePolicyReconciler struct {
+	client.Client
+	Log             logr.Logger
+	Scheme          *runtime.Scheme
+	DataplaneClient *dataplane.KongClient
+
+	PublishService  string
+	WatchNamespaces []string
+}
+
+//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=referencepolicies,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=referencepolicies/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=referencepolicies/finalizers,verbs=update
+
+// Reconcile is part of the main kubernetes reconciliation loop which aims to
+// move the current state of the cluster closer to the desired state.
+func (r *ReferencePolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+	log := r.Log.WithValues("NetV1Alpha2ReferencePolicy", req.NamespacedName)
+	policy := new(gatewayv1alpha2.ReferencePolicy)
+	if err := r.Get(ctx, req.NamespacedName, policy); err != nil {
+		// if the queued object is no longer present in the proxy cache we need
+		// to ensure that if it was ever added to the cache, it gets removed.
+		if errors.IsNotFound(err) {
+			debug(log, policy, "object does not exist, ensuring it is not present in the proxy cache")
+			policy.Namespace = req.Namespace
+			policy.Name = req.Name
+			return ctrl.Result{}, r.DataplaneClient.DeleteObject(policy)
+		}
+
+		// for any error other than 404, requeue
+		return ctrl.Result{}, err
+	}
+	debug(log, policy, "processing referencepolicy")
+
+	debug(log, policy, "checking deletion timestamp")
+	if policy.DeletionTimestamp != nil {
+		debug(log, policy, "referencepolicy is being deleted, re-configuring data-plane")
+		if err := r.DataplaneClient.DeleteObject(policy); err != nil {
+			debug(log, policy, "failed to delete object from data-plane, requeuing")
+			return ctrl.Result{}, err
+		}
+		debug(log, policy, "ensured object was removed from the data-plane (if ever present)")
+		return ctrl.Result{}, r.DataplaneClient.DeleteObject(policy)
+	}
+
+	if err := r.DataplaneClient.UpdateObject(policy); err != nil {
+		debug(log, policy, "failed to update object in data-plane, requeueing")
+		return ctrl.Result{}, err
+	}
+	info(log, policy, "referencepolicy has been configured on the data-plane")
+	return ctrl.Result{}, nil
+}
+
+// SetupWithManager sets up the controller with the Manager.
+func (r *ReferencePolicyReconciler) SetupWithManager(mgr ctrl.Manager) error {
+	c, err := controller.New("referencepolicy-controller", mgr, controller.Options{
+		Reconciler: r,
+		Log:        r.Log,
+	})
+	if err != nil {
+		return err
+	}
+
+	return c.Watch(
+		&source.Kind{Type: &gatewayv1alpha2.ReferencePolicy{}},
+		&handler.EnqueueRequestForObject{},
+	)
+}
diff --git a/internal/dataplane/kong_client.go b/internal/dataplane/kong_client.go
index acf3714e8..37fc6fe9b 100644
--- a/internal/dataplane/kong_client.go
+++ b/internal/dataplane/kong_client.go
@@ -41,6 +41,10 @@ type KongClient struct {
 	// updates to the data-plane.
 	enableReverseSync bool
 
+	// skipCACertificates disables CA certificates, to avoid fighting over configuration in multi-workspace
+	// environments. See https://github.com/Kong/deck/pull/617
+	skipCACertificates bool
+
 	// requestTimeout is the maximum amount of time that should be waited for
 	// requests to the data-plane to receive a response.
 	requestTimeout time.Duration
@@ -99,20 +103,22 @@ func NewKongClient(
 	timeout time.Duration,
 	ingressClass string,
 	enableReverseSync bool,
+	skipCACertificates bool,
 	diagnostic util.ConfigDumpDiagnostic,
 	kongConfig sendconfig.Kong,
 ) (*KongClient, error) {
 	// build the client object
 	cache := store.NewCacheStores()
 	c := &KongClient{
-		logger:            logger,
-		ingressClass:      ingressClass,
-		enableReverseSync: enableReverseSync,
-		requestTimeout:    timeout,
-		diagnostic:        diagnostic,
-		prometheusMetrics: metrics.NewCtrlFuncMetrics(),
-		cache:             &cache,
-		kongConfig:        kongConfig,
+		logger:             logger,
+		ingressClass:       ingressClass,
+		enableReverseSync:  enableReverseSync,
+		skipCACertificates: skipCACertificates,
+		requestTimeout:     timeout,
+		diagnostic:         diagnostic,
+		prometheusMetrics:  metrics.NewCtrlFuncMetrics(),
+		cache:              &cache,
+		kongConfig:         kongConfig,
 	}
 
 	// download the kong root configuration (and validate connectivity to the proxy API)
@@ -164,7 +170,9 @@ func NewKongClient(
 // It will be asynchronously converted into the upstream Kong DSL and applied to the Kong Admin API.
 // A status will later be added to the object whether the configuration update succeeds or fails.
 func (c *KongClient) UpdateObject(obj client.Object) error {
-	return c.cache.Add(obj)
+	// we do a deep copy of the object here so that the caller can continue to use
+	// the original object in a threadsafe manner.
+	return c.cache.Add(obj.DeepCopyObject())
 }
 
 // DeleteObject accepts a Kubernetes controller-runtime client.Object and removes it from the configuration cache.
@@ -305,6 +313,7 @@ func (c *KongClient) Update(ctx context.Context) error {
 		&c.kongConfig,
 		c.kongConfig.InMemory,
 		c.enableReverseSync,
+		c.skipCACertificates,
 		targetConfig,
 		c.kongConfig.FilterTags,
 		nil,
diff --git a/internal/dataplane/kongstate/kongstate.go b/internal/dataplane/kongstate/kongstate.go
index f11f8c413..676e9f96f 100644
--- a/internal/dataplane/kongstate/kongstate.go
+++ b/internal/dataplane/kongstate/kongstate.go
@@ -76,7 +76,7 @@ func (ks *KongState) FillConsumersAndCredentials(log logrus.FieldLogger, s store
 			})
 			secret, err := s.GetSecret(consumer.Namespace, cred)
 			if err != nil {
-				log.Errorf("failed to fetch secret: %v", err)
+				log.WithError(err).Error("failed to fetch secret")
 				continue
 			}
 			credConfig := map[string]interface{}{}
@@ -93,7 +93,7 @@ func (ks *KongState) FillConsumersAndCredentials(log logrus.FieldLogger, s store
 				if k == "hash_secret" {
 					boolVal, err := strconv.ParseBool(string(v))
 					if err != nil {
-						log.Errorf("failed to parse hash_secret to bool: %v. defaulting to false", err)
+						log.WithError(err).Errorf("failed to parse hash_secret to bool. defaulting to false")
 						credConfig[k] = false
 					} else {
 						credConfig[k] = boolVal
@@ -104,19 +104,21 @@ func (ks *KongState) FillConsumersAndCredentials(log logrus.FieldLogger, s store
 			}
 			credType, ok := credConfig["kongCredType"].(string)
 			if !ok {
-				log.Errorf("failed to provision credential: invalid credType: %v", credType)
+				err := fmt.Errorf("invalid credType: %v", credType)
+				log.WithError(err).Errorf("failed to provision credential")
 			}
 			if !credentials.SupportedTypes.Has(credType) {
-				log.Errorf("failed to provision credential: invalid credType: %v", credType)
+				err := fmt.Errorf("invalid credType: %v", credType)
+				log.WithError(err).Error("failed to provision credential")
 				continue
 			}
 			if len(credConfig) <= 1 { // 1 key of credType itself
-				log.Errorf("failed to provision credential: empty secret")
+				log.Error("failed to provision credential: empty secret")
 				continue
 			}
 			err = c.SetCredential(credType, credConfig)
 			if err != nil {
-				log.Errorf("failed to provision credential: %v", err)
+				log.WithError(err).Errorf("failed to provision credential")
 				continue
 			}
 		}
@@ -135,7 +137,7 @@ func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) {
 		// Services
 		kongIngress, err := getKongIngressForServices(s, ks.Services[i].K8sServices)
 		if err != nil {
-			log.Errorf("failed to fetch KongIngress resource for Services %s: %v", PrettyPrintServiceList(ks.Services[i].K8sServices), err)
+			log.WithError(err).Errorf("failed to fetch KongIngress resource for Services %s", PrettyPrintServiceList(ks.Services[i].K8sServices))
 			continue
 		}
 
@@ -150,7 +152,7 @@ func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) {
 				log.WithFields(logrus.Fields{
 					"resource_name":      ks.Services[i].Routes[j].Ingress.Name,
 					"resource_namespace": ks.Services[i].Routes[j].Ingress.Namespace,
-				}).Errorf("failed to fetch KongIngress resource: %v", err)
+				}).WithError(err).Errorf("failed to fetch KongIngress resource")
 			}
 
 			ks.Services[i].Routes[j].override(log, kongIngress)
@@ -161,7 +163,7 @@ func (ks *KongState) FillOverrides(log logrus.FieldLogger, s store.Storer) {
 	for i := 0; i < len(ks.Upstreams); i++ {
 		kongIngress, err := getKongIngressForServices(s, ks.Upstreams[i].Service.K8sServices)
 		if err != nil {
-			log.Errorf("failed to fetch KongIngress resource for Services %s: %v", PrettyPrintServiceList(ks.Upstreams[i].Service.K8sServices), err)
+			log.WithError(err).Errorf("failed to fetch KongIngress resource for Services %s", PrettyPrintServiceList(ks.Upstreams[i].Service.K8sServices))
 			continue
 		}
 
@@ -240,7 +242,7 @@ func buildPlugins(log logrus.FieldLogger, s store.Storer, pluginRels map[string]
 			log.WithFields(logrus.Fields{
 				"kongplugin_name":      kongPluginName,
 				"kongplugin_namespace": namespace,
-			}).Errorf("failed to fetch KongPlugin: %v", err)
+			}).WithError(err).Errorf("failed to fetch KongPlugin")
 			continue
 		}
 
@@ -263,7 +265,7 @@ func buildPlugins(log logrus.FieldLogger, s store.Storer, pluginRels map[string]
 
 	globalPlugins, err := globalPlugins(log, s)
 	if err != nil {
-		log.Errorf("failed to fetch global plugins: %v", err)
+		log.WithError(err).Error("failed to fetch global plugins")
 	}
 	plugins = append(plugins, globalPlugins...)
 
@@ -318,7 +320,7 @@ func globalPlugins(log logrus.FieldLogger, s store.Storer) ([]Plugin, error) {
 		} else {
 			log.WithFields(logrus.Fields{
 				"kongclusterplugin_name": k8sPlugin.Name,
-			}).Errorf("failed to generate configuration from KongClusterPlugin: %v ", err)
+			}).WithError(err).Error("failed to generate configuration from KongClusterPlugin")
 		}
 	}
 	for _, plugin := range duplicates {
diff --git a/internal/dataplane/parser/parser.go b/internal/dataplane/parser/parser.go
index 06aa970de..41e22f411 100644
--- a/internal/dataplane/parser/parser.go
+++ b/internal/dataplane/parser/parser.go
@@ -172,11 +172,11 @@ func toCACerts(log logrus.FieldLogger, caCertSecrets []*corev1.Secret) []kong.CA
 		}
 		x509Cert, err := x509.ParseCertificate(pemBlock.Bytes)
 		if err != nil {
-			log.Errorf("invalid CA certificate: failed to parse certificate: %v", err)
+			log.WithError(err).Errorf("invalid CA certificate: failed to parse certificate")
 			continue
 		}
 		if !x509Cert.IsCA {
-			log.Errorf("invalid CA certificate: certificate is missing the 'CA' basic constraint: %v", err)
+			log.WithError(err).Errorf("invalid CA certificate: certificate is missing the 'CA' basic constraint")
 			continue
 		}
 
@@ -387,7 +387,7 @@ func getCerts(log logrus.FieldLogger, s store.Storer, secretsToSNIs map[string][
 			log.WithFields(logrus.Fields{
 				"secret_name":      namespaceName[1],
 				"secret_namespace": namespaceName[0],
-			}).Logger.Errorf("failed to fetch secret: %v", err)
+			}).WithError(err).Error("failed to fetch secret")
 			continue
 		}
 		cert, key, err := getCertFromSecret(secret)
@@ -395,7 +395,7 @@ func getCerts(log logrus.FieldLogger, s store.Storer, secretsToSNIs map[string][
 			log.WithFields(logrus.Fields{
 				"secret_name":      namespaceName[1],
 				"secret_namespace": namespaceName[0],
-			}).Logger.Errorf("failed to construct certificate from secret: %v", err)
+			}).WithError(err).Error("failed to construct certificate from secret")
 			continue
 		}
 		kongCert, ok := certs[cert+key]
@@ -503,7 +503,8 @@ func getEndpoints(
 		targetPort := port.TargetPort.IntValue()
 		// check for invalid port value
 		if targetPort <= 0 {
-			log.Errorf("invalid service: invalid port: %v", targetPort)
+			err := fmt.Errorf("invalid port: %v", targetPort)
+			log.WithError(err).Error("invalid service")
 			return upsServers
 		}
 
@@ -523,7 +524,7 @@ func getEndpoints(
 	log.Debugf("fetching endpoints")
 	ep, err := getEndpoints(s.Namespace, s.Name)
 	if err != nil {
-		log.Errorf("failed to fetch endpoints: %v", err)
+		log.WithError(err).Error("failed to fetch endpoints")
 		return upsServers
 	}
 
diff --git a/internal/dataplane/parser/translate_httproute.go b/internal/dataplane/parser/translate_httproute.go
index 96d94dbc1..b9780f3e1 100644
--- a/internal/dataplane/parser/translate_httproute.go
+++ b/internal/dataplane/parser/translate_httproute.go
@@ -21,7 +21,7 @@ func (p *Parser) ingressRulesFromHTTPRoutes() ingressRules {
 
 	httpRouteList, err := p.storer.ListHTTPRoutes()
 	if err != nil {
-		p.logger.Errorf("failed to list HTTPRoutes: %w", err)
+		p.logger.WithError(err).Error("failed to list HTTPRoutes")
 		return result
 	}
 
diff --git a/internal/dataplane/parser/translate_ingress.go b/internal/dataplane/parser/translate_ingress.go
index a5a6c09ed..ba1a3a19a 100644
--- a/internal/dataplane/parser/translate_ingress.go
+++ b/internal/dataplane/parser/translate_ingress.go
@@ -204,7 +204,7 @@ func (p *Parser) ingressRulesFromIngressV1() ingressRules {
 
 				paths, err := pathsFromK8s(rulePath.Path, pathType)
 				if err != nil {
-					log.Errorf("rule skipped: pathsFromK8s: %v", err)
+					log.WithError(err).Error("rule skipped: pathsFromK8s")
 					continue
 				}
 
diff --git a/internal/dataplane/parser/translate_knative.go b/internal/dataplane/parser/translate_knative.go
index 57d153cf8..b8ce70a3d 100644
--- a/internal/dataplane/parser/translate_knative.go
+++ b/internal/dataplane/parser/translate_knative.go
@@ -16,7 +16,7 @@ func (p *Parser) ingressRulesFromKnativeIngress() ingressRules {
 
 	ingressList, err := p.storer.ListKnativeIngresses()
 	if err != nil {
-		p.logger.Errorf("failed to list Knative Ingresses: %v", err)
+		p.logger.WithError(err).Error("failed to list Knative Ingresses")
 		return result
 	}
 
diff --git a/internal/dataplane/parser/translate_kong_l4.go b/internal/dataplane/parser/translate_kong_l4.go
index 3fc66487e..a4c413f42 100644
--- a/internal/dataplane/parser/translate_kong_l4.go
+++ b/internal/dataplane/parser/translate_kong_l4.go
@@ -17,7 +17,7 @@ func (p *Parser) ingressRulesFromTCPIngressV1beta1() ingressRules {
 
 	ingressList, err := p.storer.ListTCPIngresses()
 	if err != nil {
-		p.logger.Errorf("failed to list TCPIngresses: %v", err)
+		p.logger.WithError(err).Error("failed to list TCPIngresses")
 		return result
 	}
 
@@ -107,7 +107,7 @@ func (p *Parser) ingressRulesFromUDPIngressV1beta1() ingressRules {
 
 	ingressList, err := p.storer.ListUDPIngresses()
 	if err != nil {
-		p.logger.Errorf("failed to list UDPIngresses: %v", err)
+		p.logger.WithError(err).Errorf("failed to list UDPIngresses")
 		return result
 	}
 
diff --git a/internal/dataplane/parser/translate_tcproute.go b/internal/dataplane/parser/translate_tcproute.go
index d4c52dfd9..1fae49243 100644
--- a/internal/dataplane/parser/translate_tcproute.go
+++ b/internal/dataplane/parser/translate_tcproute.go
@@ -21,7 +21,7 @@ func (p *Parser) ingressRulesFromTCPRoutes() ingressRules {
 
 	tcpRouteList, err := p.storer.ListTCPRoutes()
 	if err != nil {
-		p.logger.Errorf("failed to list TCPRoutes: %w", err)
+		p.logger.WithError(err).Error("failed to list TCPRoutes")
 		return result
 	}
 
diff --git a/internal/dataplane/parser/translate_udproute.go b/internal/dataplane/parser/translate_udproute.go
index 503c7d00c..5feb7ddb8 100644
--- a/internal/dataplane/parser/translate_udproute.go
+++ b/internal/dataplane/parser/translate_udproute.go
@@ -21,7 +21,7 @@ func (p *Parser) ingressRulesFromUDPRoutes() ingressRules {
 
 	udpRouteList, err := p.storer.ListUDPRoutes()
 	if err != nil {
-		p.logger.Errorf("failed to list UDPRoutes: %w", err)
+		p.logger.WithError(err).Errorf("failed to list UDPRoutes")
 		return result
 	}
 
diff --git a/internal/dataplane/sendconfig/sendconfig.go b/internal/dataplane/sendconfig/sendconfig.go
index 2f3204e22..c6e346ebb 100644
--- a/internal/dataplane/sendconfig/sendconfig.go
+++ b/internal/dataplane/sendconfig/sendconfig.go
@@ -35,6 +35,7 @@ func PerformUpdate(ctx context.Context,
 	kongConfig *Kong,
 	inMemory bool,
 	reverseSync bool,
+	skipCACertificates bool,
 	targetContent *file.Content,
 	selectorTags []string,
 	customEntities []byte,
@@ -56,7 +57,7 @@ func PerformUpdate(ctx context.Context,
 			ready := true
 			status, err := kongConfig.Client.Status(ctx)
 			if err != nil {
-				log.Errorf("checking config status failed: %w", err)
+				log.WithError(err).Error("checking config status failed")
 				log.Debug("configuration state unknown, skipping sync to kong")
 				return oldSHA, nil
 			}
@@ -77,7 +78,7 @@ func PerformUpdate(ctx context.Context,
 		err = onUpdateInMemoryMode(ctx, log, targetContent, customEntities, kongConfig)
 	} else {
 		metricsProtocol = metrics.ProtocolDeck
-		err = onUpdateDBMode(ctx, targetContent, kongConfig, selectorTags)
+		err = onUpdateDBMode(ctx, targetContent, kongConfig, selectorTags, skipCACertificates)
 	}
 	timeEnd := time.Now()
 
@@ -140,7 +141,7 @@ func renderConfigWithCustomEntities(log logrus.FieldLogger, state *file.Content,
 	err = json.Unmarshal(customEntitiesJSONBytes, &customEntities)
 	if err != nil {
 		// do not error out when custom entities are messed up
-		log.Errorf("failed to unmarshal custom entities from secret data: %v", err)
+		log.WithError(err).Error("failed to unmarshal custom entities from secret data")
 	} else {
 		for k, v := range customEntities {
 			if _, exists := mergeMap[k]; !exists {
@@ -199,8 +200,9 @@ func onUpdateDBMode(ctx context.Context,
 	targetContent *file.Content,
 	kongConfig *Kong,
 	selectorTags []string,
+	skipCACertificates bool,
 ) error {
-	dumpConfig := dump.Config{SelectorTags: selectorTags}
+	dumpConfig := dump.Config{SelectorTags: selectorTags, SkipCACerts: skipCACertificates}
 	// read the current state
 	rawState, err := dump.Get(ctx, kongConfig.Client, dumpConfig)
 	if err != nil {
diff --git a/internal/manager/config.go b/internal/manager/config.go
index b5a7e514b..39f630cc5 100644
--- a/internal/manager/config.go
+++ b/internal/manager/config.go
@@ -40,6 +40,7 @@ type Config struct {
 	AnonymousReports                  bool
 	EnableReverseSync                 bool
 	SyncPeriod                        time.Duration
+	SkipCACertificates                bool
 
 	// Kong Proxy configurations
 	APIServerHost            string
@@ -122,6 +123,7 @@ func (c *Config) FlagSet() *pflag.FlagSet {
 	flagSet.BoolVar(&c.AnonymousReports, "anonymous-reports", true, `Send anonymized usage data to help improve Kong`)
 	flagSet.BoolVar(&c.EnableReverseSync, "enable-reverse-sync", false, `Send configuration to Kong even if the configuration checksum has not changed since previous update.`)
 	flagSet.DurationVar(&c.SyncPeriod, "sync-period", time.Hour*48, `Relist and confirm cloud resources this often`) // 48 hours derived from controller-runtime defaults
+	flagSet.BoolVar(&c.SkipCACertificates, "skip-ca-certificates", false, `disable syncing CA certificate syncing (for use with multi-workspace environments)`)
 
 	flagSet.StringVar(&c.KongAdminAPIConfig.TLSClientCertPath, "kong-admin-tls-client-cert-file", "", "mTLS client certificate file for authentication.")
 	flagSet.StringVar(&c.KongAdminAPIConfig.TLSClientKeyPath, "kong-admin-tls-client-key-file", "", "mTLS client key file for authentication.")
diff --git a/internal/manager/controllerdef.go b/internal/manager/controllerdef.go
index b2f169e52..10919f32a 100644
--- a/internal/manager/controllerdef.go
+++ b/internal/manager/controllerdef.go
@@ -269,6 +269,21 @@ func setupControllers(
 				WatchNamespaces: c.WatchNamespaces,
 			},
 		},
+		{
+			Enabled: featureGates[gatewayFeature],
+			AutoHandler: crdExistsChecker{
+				GVR: schema.GroupVersionResource{
+					Group:    gatewayv1alpha2.SchemeGroupVersion.Group,
+					Version:  gatewayv1alpha2.SchemeGroupVersion.Version,
+					Resource: "referencepolicies",
+				}}.CRDExists,
+			Controller: &gateway.ReferencePolicyReconciler{
+				Client:          mgr.GetClient(),
+				Log:             ctrl.Log.WithName("controllers").WithName("ReferencePolicy"),
+				Scheme:          mgr.GetScheme(),
+				DataplaneClient: dataplaneClient,
+			},
+		},
 		{
 			Enabled: featureGates[gatewayFeature],
 			AutoHandler: crdExistsChecker{
diff --git a/internal/manager/run.go b/internal/manager/run.go
index b4635fa8f..8672af82f 100644
--- a/internal/manager/run.go
+++ b/internal/manager/run.go
@@ -104,6 +104,9 @@ func Run(ctx context.Context, c *Config, diagnostic util.ConfigDumpDiagnostic) e
 	if !ok {
 		return fmt.Errorf("invalid database configuration, expected a string got %T", kongRootConfig["database"])
 	}
+	if dbmode == "off" && c.SkipCACertificates {
+		return fmt.Errorf("--skip-ca-certificates is not available for use with DB-less Kong instances")
+	}
 
 	setupLog.Info("configuring and building the controller manager")
 	controllerOpts, err := setupControllerOptions(setupLog, c, scheme, dbmode)
@@ -125,7 +128,7 @@ func Run(ctx context.Context, c *Config, diagnostic util.ConfigDumpDiagnostic) e
 	if err != nil {
 		return fmt.Errorf("%f is not a valid number of seconds to the timeout config for the kong client: %w", c.ProxyTimeoutSeconds, err)
 	}
-	dataplaneClient, err := dataplane.NewKongClient(deprecatedLogger, timeoutDuration, c.IngressClassName, c.EnableReverseSync, diagnostic, kongConfig)
+	dataplaneClient, err := dataplane.NewKongClient(deprecatedLogger, timeoutDuration, c.IngressClassName, c.EnableReverseSync, c.SkipCACertificates, diagnostic, kongConfig)
 	if err != nil {
 		return fmt.Errorf("failed to initialize kong data-plane client: %w", err)
 	}
diff --git a/internal/store/fake_store.go b/internal/store/fake_store.go
index 785b824ca..e984d07f1 100644
--- a/internal/store/fake_store.go
+++ b/internal/store/fake_store.go
@@ -36,6 +36,7 @@ type FakeObjects struct {
 	HTTPRoutes         []*gatewayv1alpha2.HTTPRoute
 	UDPRoutes          []*gatewayv1alpha2.UDPRoute
 	TCPRoutes          []*gatewayv1alpha2.TCPRoute
+	ReferencePolicies  []*gatewayv1alpha2.ReferencePolicy
 	TCPIngresses       []*configurationv1beta1.TCPIngress
 	UDPIngresses       []*configurationv1beta1.UDPIngress
 	Services           []*apiv1.Service
@@ -94,6 +95,12 @@ func NewFakeStore(
 			return nil, err
 		}
 	}
+	referencepolicyStore := cache.NewStore(keyFunc)
+	for _, referencepolicy := range objects.ReferencePolicies {
+		if err := referencepolicyStore.Add(referencepolicy); err != nil {
+			return nil, err
+		}
+	}
 	tcpIngressStore := cache.NewStore(keyFunc)
 	for _, ingress := range objects.TCPIngresses {
 		err := tcpIngressStore.Add(ingress)
@@ -166,17 +173,18 @@ func NewFakeStore(
 	}
 	s = Store{
 		stores: CacheStores{
-			IngressV1beta1: ingressV1beta1Store,
-			IngressV1:      ingressV1Store,
-			IngressClassV1: ingressClassV1Store,
-			HTTPRoute:      httprouteStore,
-			UDPRoute:       udprouteStore,
-			TCPRoute:       tcprouteStore,
-			TCPIngress:     tcpIngressStore,
-			UDPIngress:     udpIngressStore,
-			Service:        serviceStore,
-			Endpoint:       endpointStore,
-			Secret:         secretsStore,
+			IngressV1beta1:  ingressV1beta1Store,
+			IngressV1:       ingressV1Store,
+			IngressClassV1:  ingressClassV1Store,
+			HTTPRoute:       httprouteStore,
+			UDPRoute:        udprouteStore,
+			TCPRoute:        tcprouteStore,
+			ReferencePolicy: referencepolicyStore,
+			TCPIngress:      tcpIngressStore,
+			UDPIngress:      udpIngressStore,
+			Service:         serviceStore,
+			Endpoint:        endpointStore,
+			Secret:          secretsStore,
 
 			Plugin:        kongPluginsStore,
 			ClusterPlugin: kongClusterPluginsStore,
diff --git a/internal/store/store.go b/internal/store/store.go
index 167c5ad67..f7fd40ac7 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -85,6 +85,7 @@ type Storer interface {
 	ListHTTPRoutes() ([]*gatewayv1alpha2.HTTPRoute, error)
 	ListUDPRoutes() ([]*gatewayv1alpha2.UDPRoute, error)
 	ListTCPRoutes() ([]*gatewayv1alpha2.TCPRoute, error)
+	ListReferencePolicies() ([]*gatewayv1alpha2.ReferencePolicy, error)
 	ListTCPIngresses() ([]*kongv1beta1.TCPIngress, error)
 	ListUDPIngresses() ([]*kongv1beta1.UDPIngress, error)
 	ListKnativeIngresses() ([]*knative.Ingress, error)
@@ -125,9 +126,10 @@ type CacheStores struct {
 	Endpoint       cache.Store
 
 	// Gateway API Stores
-	HTTPRoute cache.Store
-	UDPRoute  cache.Store
-	TCPRoute  cache.Store
+	HTTPRoute       cache.Store
+	UDPRoute        cache.Store
+	TCPRoute        cache.Store
+	ReferencePolicy cache.Store
 
 	// Kong Stores
 	Plugin        cache.Store
@@ -154,6 +156,7 @@ func NewCacheStores() (c CacheStores) {
 	c.HTTPRoute = cache.NewStore(keyFunc)
 	c.UDPRoute = cache.NewStore(keyFunc)
 	c.TCPRoute = cache.NewStore(keyFunc)
+	c.ReferencePolicy = cache.NewStore(keyFunc)
 	c.KnativeIngress = cache.NewStore(keyFunc)
 	c.Plugin = cache.NewStore(keyFunc)
 	c.Secret = cache.NewStore(keyFunc)
@@ -239,6 +242,8 @@ func (c CacheStores) Get(obj runtime.Object) (item interface{}, exists bool, err
 		return c.UDPRoute.Get(obj)
 	case *gatewayv1alpha2.TCPRoute:
 		return c.TCPRoute.Get(obj)
+	case *gatewayv1alpha2.ReferencePolicy:
+		return c.ReferencePolicy.Get(obj)
 	// ----------------------------------------------------------------------------
 	// Kong API Support
 	// ----------------------------------------------------------------------------
@@ -296,6 +301,8 @@ func (c CacheStores) Add(obj runtime.Object) error {
 		return c.UDPRoute.Add(obj)
 	case *gatewayv1alpha2.TCPRoute:
 		return c.TCPRoute.Add(obj)
+	case *gatewayv1alpha2.ReferencePolicy:
+		return c.ReferencePolicy.Add(obj)
 	// ----------------------------------------------------------------------------
 	// Kong API Support
 	// ----------------------------------------------------------------------------
@@ -354,6 +361,8 @@ func (c CacheStores) Delete(obj runtime.Object) error {
 		return c.UDPRoute.Delete(obj)
 	case *gatewayv1alpha2.TCPRoute:
 		return c.TCPRoute.Delete(obj)
+	case *gatewayv1alpha2.ReferencePolicy:
+		return c.ReferencePolicy.Delete(obj)
 	// ----------------------------------------------------------------------------
 	// Kong API Support
 	// ----------------------------------------------------------------------------
@@ -566,6 +575,22 @@ func (s Store) ListTCPRoutes() ([]*gatewayv1alpha2.TCPRoute, error) {
 	return tcproutes, nil
 }
 
+// ListReferencePolicies returns the list of ReferencePolicies in the ReferencePolicy cache store.
+func (s Store) ListReferencePolicies() ([]*gatewayv1alpha2.ReferencePolicy, error) {
+	var policies []*gatewayv1alpha2.ReferencePolicy
+	if err := cache.ListAll(s.stores.ReferencePolicy, labels.NewSelector(),
+		func(ob interface{}) {
+			policy, ok := ob.(*gatewayv1alpha2.ReferencePolicy)
+			if ok {
+				policies = append(policies, policy)
+			}
+		},
+	); err != nil {
+		return nil, err
+	}
+	return policies, nil
+}
+
 // ListTCPIngresses returns the list of TCP Ingresses from
 // configuration.konghq.com group.
 func (s Store) ListTCPIngresses() ([]*kongv1beta1.TCPIngress, error) {


Test patch:
diff --git a/internal/cmd/rootcmd/env_test.go b/internal/cmd/rootcmd/env_test.go
index f784b5ce9..62e379625 100644
--- a/internal/cmd/rootcmd/env_test.go
+++ b/internal/cmd/rootcmd/env_test.go
@@ -68,7 +68,7 @@ func TestBindEnvVarsValidation(t *testing.T) {
 
 	err := cmd.Execute()
 	assert.Error(t, err)
-	assert.True(t, strings.Contains(err.Error(), "bad value for var type testvar"))
+	assert.True(t, strings.Contains(err.Error(), "variable CONTROLLER_VALIDATION_TEST: bad value for var type testvar"))
 }
 
 // -----------------------------------------------------------------------------
diff --git a/internal/store/fake_store_test.go b/internal/store/fake_store_test.go
index 8110a8073..6279dffcf 100644
--- a/internal/store/fake_store_test.go
+++ b/internal/store/fake_store_test.go
@@ -764,3 +764,28 @@ func TestFakeStoreUDPRoute(t *testing.T) {
 	assert.Nil(err)
 	assert.Len(routes, 2, "expect two UDPRoutes")
 }
+
+func TestFakeStoreReferencePolicy(t *testing.T) {
+	assert := assert.New(t)
+
+	policies := []*gatewayv1alpha2.ReferencePolicy{
+		{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "foo",
+			},
+			Spec: gatewayv1alpha2.ReferencePolicySpec{},
+		},
+		{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: "bar",
+			},
+			Spec: gatewayv1alpha2.ReferencePolicySpec{},
+		},
+	}
+	store, err := NewFakeStore(FakeObjects{ReferencePolicies: policies})
+	assert.Nil(err)
+	assert.NotNil(store)
+	routes, err := store.ListReferencePolicies()
+	assert.Nil(err)
+	assert.Len(routes, 2, "expect two ReferencePolicies")
+}