Repository: Kong/kubernetes-ingress-controller
Pull request #5022 (2023-10-30 19:02:56)

Handle `KongIngress` deprecation in admission webhook and in `KongIngress` validation rules
**What this PR does / why we need it**:

Alternative to https://github.com/Kong/kubernetes-ingress-controller/pull/5015. Deprecates KongIngress in the sense that it's still available for the time being, but results in logs instructing users to migrate rather than removing it immediately.

**Which issue this PR fixes**:

For https://github.com/Kong/kubernetes-ingress-controller/issues/4720 but not using auto-resolve since this isn't targeted to main.

Would need a follow-up "_Remove_ KongIngress support" issue.

**Notes**:

I did leave in the checks for `route` and `service` even though CEL now blocks them. I figure it doesn't really hurt anything to have them there under normal circumstances, and we often had abnormal circumstances because users forget to update CRDs.

Added a Service webhook handler also. I don't really love having that in place for such a common resource, but it is at least only temporary: we'd remove it once we actually remove KongIngress.

**PR Readiness Checklist**:

Complete these before marking the PR as `ready to review`:

- [x] the `CHANGELOG.md` release notes have been updated to reflect any significant (and particularly user-facing) changes introduced by this PR


codecov[bot]: We're currently processing your upload.  This comment will be updated when the results are available.
czeslavo: I've rebased the PR onto main and added CEL validations.
czeslavo: I had to rebase (conflict in go.sum), sorry @pmalek 😞 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ccf6f88f5..79aa91b5c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -130,6 +130,11 @@ Adding a new version? You'll need three changes:
   expected to functionally affect routing, but may affect performance for
   some configurations.
   [#4934](https://github.com/Kong/kubernetes-ingress-controller/pull/4934)
+- `KongIngress` is now entirely deprecated and will be removed in a future release.
+  Its fields that were previously deprecated (`proxy` and `route`) are now not allowed to be set.
+  They must be migrated to annotations. `upstream` field is deprecated - it's recommended
+  to migrate its settings to the new `KongUpstreamPolicy` resource.
+  [#5022](https://github.com/Kong/kubernetes-ingress-controller/pull/5022)
 
 ### Fixed
 
diff --git a/config/crd/bases/configuration.konghq.com_kongingresses.yaml b/config/crd/bases/configuration.konghq.com_kongingresses.yaml
index 1fd2b2373..302eaff0a 100644
--- a/config/crd/bases/configuration.konghq.com_kongingresses.yaml
+++ b/config/crd/bases/configuration.konghq.com_kongingresses.yaml
@@ -351,6 +351,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/go.mod b/go.mod
index 699be9bc2..c6c4d0504 100644
--- a/go.mod
+++ b/go.mod
@@ -82,7 +82,7 @@ require (
 	github.com/moby/sys/sequential v0.5.0 // indirect
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/onsi/ginkgo v1.16.4 // indirect
-	github.com/opencontainers/runc v1.1.5 // indirect
+	github.com/opencontainers/runc v1.1.7 // indirect
 	github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
 	github.com/sergi/go-diff v1.2.0 // indirect
 	github.com/shoenig/go-m1cpu v0.1.6 // indirect
diff --git a/go.sum b/go.sum
index 2e96b3dec..63113eac3 100644
--- a/go.sum
+++ b/go.sum
@@ -58,28 +58,22 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
 github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
-github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
 github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4=
 github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8=
 github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
 github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
-github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
 github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
 github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
-github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -90,7 +84,6 @@ github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig
 github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
@@ -111,7 +104,6 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
 github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
-github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
 github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -147,8 +139,6 @@ github.com/go-task/slim-sprig v2.20.0+incompatible h1:4Xh3bDzO29j4TWNOI+24ubc0vb
 github.com/go-task/slim-sprig v2.20.0+incompatible/go.mod h1:N/mhXZITr/EQAOErEHciKvO1bFei2Lld2Ym6h96pdy0=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -182,7 +172,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -311,7 +300,6 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV
 github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
 github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
 github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
-github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
 github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
 github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
 github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
@@ -327,7 +315,6 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/moul/pb v0.0.0-20220425114252-bca18df4138c h1:1STmblv9zmHLDpru4dbnf1PNL6wrrZNf7yBH+SfQU+s=
 github.com/moul/pb v0.0.0-20220425114252-bca18df4138c/go.mod h1:jE2HT8eoucYyUPBFJMreiVlC3KPHkDMtN8wn+ef7Y64=
-github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -350,10 +337,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
 github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
-github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs=
-github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
-github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
-github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
+github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk=
+github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
 github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -381,14 +366,12 @@ github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9p
 github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
 github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
 github.com/samber/mo v1.11.0 h1:ZOiSkrGGpNhVv/1dxP02risztdMTIwE8KSW9OG4k5bY=
 github.com/samber/mo v1.11.0/go.mod h1:BfkrCPuYzVG3ZljnZB783WIJIGk1mcZr9c9CPf8tAxs=
-github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
 github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
 github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
@@ -401,8 +384,6 @@ github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
 github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
 github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -433,7 +414,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 github.com/testcontainers/testcontainers-go v0.26.0 h1:uqcYdoOHBy1ca7gKODfBd9uTHVK3a7UL848z09MVZ0c=
 github.com/testcontainers/testcontainers-go v0.26.0/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0=
 github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
@@ -447,9 +427,6 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA
 github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
 github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
 github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
-github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
-github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -517,7 +494,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -540,12 +516,9 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -554,16 +527,12 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -643,7 +612,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
 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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/hack/deploy-admission-controller.sh b/hack/deploy-admission-controller.sh
index c6d6e3c97..6146ea93e 100755
--- a/hack/deploy-admission-controller.sh
+++ b/hack/deploy-admission-controller.sh
@@ -68,6 +68,7 @@ webhooks:
     - UPDATE
     resources:
     - secrets
+    - services
   - apiGroups:
     - networking.k8s.io
     apiVersions:
diff --git a/internal/admission/handler.go b/internal/admission/handler.go
index 79257cb0e..507b2a9d9 100644
--- a/internal/admission/handler.go
+++ b/internal/admission/handler.go
@@ -12,6 +12,7 @@ import (
 	netv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
+	"github.com/kong/kubernetes-ingress-controller/v3/internal/annotations"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/gatewayapi"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
 	kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
@@ -95,6 +96,11 @@ var (
 		Version:  netv1.SchemeGroupVersion.Version,
 		Resource: "ingresses",
 	}
+	serviceGVResource = metav1.GroupVersionResource{
+		Group:    corev1.SchemeGroupVersion.Group,
+		Version:  corev1.SchemeGroupVersion.Version,
+		Resource: "services",
+	}
 )
 
 func (h RequestHandler) handleValidation(ctx context.Context, request admissionv1.AdmissionRequest) (
@@ -119,6 +125,8 @@ func (h RequestHandler) handleValidation(ctx context.Context, request admissionv
 		return h.handleHTTPRoute(ctx, request, responseBuilder)
 	case kongIngressGVResource:
 		return h.handleKongIngress(ctx, request, responseBuilder)
+	case serviceGVResource:
+		return h.handleService(ctx, request, responseBuilder)
 	case ingressGVResource:
 		return h.handleIngress(ctx, request, responseBuilder)
 	default:
@@ -289,6 +297,12 @@ func (h RequestHandler) handleHTTPRoute(
 	return responseBuilder.Allowed(ok).WithMessage(message).Build(), nil
 }
 
+const (
+	proxyWarning    = "Support for 'proxy' was removed in 3.0. It will have no effect. Use Service's annotations instead."
+	routeWarning    = "Support for 'route' was removed in 3.0. It will have no effect. Use Ingress' annotations instead."
+	upstreamWarning = "'upstream' is DEPRECATED and will be removed in a future version. Use a KongUpstreamPolicy resource instead."
+)
+
 func (h RequestHandler) handleKongIngress(_ context.Context, request admissionv1.AdmissionRequest, responseBuilder *ResponseBuilder) (*admissionv1.AdmissionResponse, error) {
 	kongIngress := kongv1.KongIngress{}
 	_, _, err := codecs.UniversalDeserializer().Decode(request.Object.Raw, nil, &kongIngress)
@@ -299,13 +313,41 @@ func (h RequestHandler) handleKongIngress(_ context.Context, request admissionv1
 	// KongIngress is always allowed.
 	responseBuilder = responseBuilder.Allowed(true)
 
+	// Proxy and Route fields are now disallowed to be set with the use of CEL rules in the CRD definition.
+	// We still warn about them here only just in case someone doesn't install new CRDs with CEL rules.
 	if kongIngress.Proxy != nil {
-		const warning = "'proxy' is DEPRECATED. It will have no effect. Use Service's annotations instead."
-		responseBuilder = responseBuilder.WithWarning(warning)
+		responseBuilder = responseBuilder.WithWarning(proxyWarning)
 	}
-
 	if kongIngress.Route != nil {
-		const warning = "'route' is DEPRECATED. It will have no effect. Use Ingress' annotations instead."
+		responseBuilder = responseBuilder.WithWarning(routeWarning)
+	}
+
+	if kongIngress.Upstream != nil {
+		responseBuilder = responseBuilder.WithWarning(upstreamWarning)
+	}
+
+	return responseBuilder.Build(), nil
+}
+
+const (
+	serviceWarning = "%s is deprecated and will be removed in a future release. Use Service annotations " +
+		"for the 'proxy' section and %s with a KongUpstreamPolicy resource instead."
+)
+
+func (h RequestHandler) handleService(_ context.Context, request admissionv1.AdmissionRequest, responseBuilder *ResponseBuilder) (*admissionv1.AdmissionResponse, error) {
+	service := corev1.Service{}
+	_, _, err := codecs.UniversalDeserializer().Decode(request.Object.Raw, nil, &service)
+	if err != nil {
+		return nil, err
+	}
+
+	// Service is always allowed.
+	responseBuilder = responseBuilder.Allowed(true)
+
+	if annotations.ExtractConfigurationName(service.Annotations) != "" {
+		warning := fmt.Sprintf(serviceWarning, annotations.AnnotationPrefix+annotations.ConfigurationKey,
+			kongv1beta1.KongUpstreamPolicyAnnotationKey)
+
 		responseBuilder = responseBuilder.WithWarning(warning)
 	}
 
diff --git a/internal/dataplane/kongstate/kongstate.go b/internal/dataplane/kongstate/kongstate.go
index 712e367ec..9482c7890 100644
--- a/internal/dataplane/kongstate/kongstate.go
+++ b/internal/dataplane/kongstate/kongstate.go
@@ -18,6 +18,7 @@ import (
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/failures"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/store"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
+	kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
 )
 
 // KongState holds the configuration that should be applied to Kong.
@@ -203,10 +204,14 @@ func (ks *KongState) FillOverrides(
 		}
 	}
 
-	ks.FillUpstreamOverrides(s, failuresCollector)
+	ks.FillUpstreamOverrides(s, logger, failuresCollector)
 }
 
-func (ks *KongState) FillUpstreamOverrides(s store.Storer, failuresCollector *failures.ResourceFailuresCollector) {
+func (ks *KongState) FillUpstreamOverrides(
+	s store.Storer,
+	logger logr.Logger,
+	failuresCollector *failures.ResourceFailuresCollector,
+) {
 	for i := 0; i < len(ks.Upstreams); i++ {
 		servicesGroup := lo.Values(ks.Upstreams[i].Service.K8sServices)
 		servicesAsObjects := func(svc *corev1.Service, _ int) client.Object { return svc }
@@ -217,6 +222,11 @@ func (ks *KongState) FillUpstreamOverrides(s store.Storer, failuresCollector *fa
 		} else {
 			for _, svc := range ks.Upstreams[i].Service.K8sServices {
 				ks.Upstreams[i].override(kongIngress, svc)
+				logger.Error(nil, fmt.Sprintf(
+					"Service uses deprecated %s annotation and KongIngress, migrate to %s and KongUpstreamPolicy",
+					annotations.AnnotationPrefix+annotations.ConfigurationKey,
+					kongv1beta1.KongUpstreamPolicyAnnotationKey),
+					"namespace", svc.Namespace, "name", svc.Name)
 			}
 		}
 
@@ -225,6 +235,18 @@ func (ks *KongState) FillUpstreamOverrides(s store.Storer, failuresCollector *fa
 			failuresCollector.PushResourceFailure(err.Error(), lo.Map(servicesGroup, servicesAsObjects)...)
 		} else {
 			if kongUpstreamPolicy != nil {
+				if kongIngress != nil {
+					for _, svc := range servicesGroup {
+						logger.Error(nil,
+							fmt.Sprintf("Service uses both %s and %s annotations, should use only %s annotation. Settings "+
+								"from %s will take precedence",
+								annotations.AnnotationPrefix+annotations.ConfigurationKey,
+								kongv1beta1.KongUpstreamPolicyAnnotationKey,
+								kongv1beta1.KongUpstreamPolicyAnnotationKey,
+								kongv1beta1.KongUpstreamPolicyAnnotationKey),
+							"namespace", svc.Namespace, "name", svc.Name)
+					}
+				}
 				ks.Upstreams[i].overrideByKongUpstreamPolicy(kongUpstreamPolicy)
 			}
 		}
diff --git a/pkg/apis/configuration/v1/kongingress_types.go b/pkg/apis/configuration/v1/kongingress_types.go
index 96820bceb..3e171b9fc 100644
--- a/pkg/apis/configuration/v1/kongingress_types.go
+++ b/pkg/apis/configuration/v1/kongingress_types.go
@@ -28,6 +28,8 @@ import (
 // +kubebuilder:storageversion
 // +kubebuilder:resource:shortName=ki,categories=kong-ingress-controller
 // +kubebuilder:validation:Optional
+// +kubebuilder:validation:XValidation:rule="!has(self.proxy)", message="'proxy' field is no longer supported, use Service's annotations instead"
+// +kubebuilder:validation:XValidation:rule="!has(self.route)", message="'route' field is no longer supported, use Ingress' annotations instead"
 
 // KongIngress is the Schema for the kongingresses API.
 type KongIngress struct {
@@ -210,9 +212,6 @@ type KongIngressUpstream struct {
 
 	// HashFallbackURICapture is the "hash_fallback" version of HashOnURICapture.
 	HashFallbackURICapture *string `json:"hash_fallback_uri_capture,omitempty" yaml:"hash_fallback_uri_capture,omitempty"`
-
-	// we need to check this one TODO https://github.com/Kong/kubernetes-ingress-controller/issues/2075
-	// ClientCertificate  *CertificateSecretRef `json:"client_certificate,omitempty" yaml:"client_certificate,omitempty"`
 }
 
 func init() {


Test patch:
diff --git a/internal/admission/handler_test.go b/internal/admission/handler_test.go
new file mode 100644
index 000000000..c99d8e658
--- /dev/null
+++ b/internal/admission/handler_test.go
@@ -0,0 +1,147 @@
+package admission
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"testing"
+
+	"github.com/go-logr/logr"
+	"github.com/stretchr/testify/require"
+	admissionv1 "k8s.io/api/admission/v1"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	k8stypes "k8s.io/apimachinery/pkg/types"
+
+	"github.com/kong/kubernetes-ingress-controller/v3/internal/annotations"
+	kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
+	kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
+)
+
+func TestHandleKongIngress(t *testing.T) {
+	tests := []struct {
+		name         string
+		resource     kongv1.KongIngress
+		wantWarnings []string
+	}{
+		{
+			name: "has proxy",
+			resource: kongv1.KongIngress{
+				Proxy: &kongv1.KongIngressService{},
+			},
+			wantWarnings: []string{proxyWarning},
+		},
+		{
+			name: "has route",
+			resource: kongv1.KongIngress{
+				Route: &kongv1.KongIngressRoute{},
+			},
+			wantWarnings: []string{routeWarning},
+		},
+		{
+			name: "has upstream",
+			resource: kongv1.KongIngress{
+				Upstream: &kongv1.KongIngressUpstream{},
+			},
+			wantWarnings: []string{upstreamWarning},
+		},
+		{
+			name: "has everything",
+			resource: kongv1.KongIngress{
+				Proxy:    &kongv1.KongIngressService{},
+				Route:    &kongv1.KongIngressRoute{},
+				Upstream: &kongv1.KongIngressUpstream{},
+			},
+			wantWarnings: []string{proxyWarning, routeWarning, upstreamWarning},
+		},
+	}
+	for _, tt := range tests {
+		resource := tt.resource
+		t.Run(tt.name, func(t *testing.T) {
+			validator := KongHTTPValidator{}
+			raw, err := json.Marshal(tt.resource)
+			require.NoError(t, err)
+			request := admissionv1.AdmissionRequest{
+				Object: runtime.RawExtension{
+					Object: &resource,
+					Raw:    raw,
+				},
+			}
+
+			handler := RequestHandler{
+				Validator: validator,
+				Logger:    logr.Discard(),
+			}
+
+			responseBuilder := NewResponseBuilder(k8stypes.UID(""))
+
+			got, err := handler.handleKongIngress(context.Background(), request, responseBuilder)
+			require.NoError(t, err)
+			require.True(t, got.Allowed)
+			require.Equal(t, tt.wantWarnings, got.Warnings)
+		})
+	}
+}
+
+func TestHandleService(t *testing.T) {
+	tests := []struct {
+		name         string
+		resource     corev1.Service
+		wantWarnings []string
+	}{
+		{
+			name: "has kongingress annotation",
+			resource: corev1.Service{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "test",
+					Annotations: map[string]string{
+						annotations.AnnotationPrefix + annotations.ConfigurationKey: "test",
+					},
+				},
+			},
+			wantWarnings: []string{
+				fmt.Sprintf(serviceWarning, annotations.AnnotationPrefix+annotations.ConfigurationKey,
+					kongv1beta1.KongUpstreamPolicyAnnotationKey),
+			},
+		},
+		{
+			name: "has upstream policy annotation",
+			resource: corev1.Service{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "test",
+					Annotations: map[string]string{
+						annotations.AnnotationPrefix + kongv1beta1.KongUpstreamPolicyAnnotationKey: "test",
+					},
+				},
+			},
+			wantWarnings: nil,
+		},
+	}
+	for _, tt := range tests {
+		resource := tt.resource
+		t.Run(tt.name, func(t *testing.T) {
+			validator := KongHTTPValidator{}
+			raw, err := json.Marshal(tt.resource)
+			require.NoError(t, err)
+			request := admissionv1.AdmissionRequest{
+				Object: runtime.RawExtension{
+					Object: &resource,
+					Raw:    raw,
+				},
+			}
+
+			handler := RequestHandler{
+				Validator: validator,
+				Logger:    logr.Discard(),
+			}
+
+			responseBuilder := NewResponseBuilder(k8stypes.UID(""))
+
+			got, err := handler.handleService(context.Background(), request, responseBuilder)
+			require.NoError(t, err)
+			require.True(t, got.Allowed)
+			require.Equal(t, tt.wantWarnings, got.Warnings)
+		})
+	}
+}
diff --git a/internal/dataplane/kongstate/kongstate_test.go b/internal/dataplane/kongstate/kongstate_test.go
index 1deff122f..2ef2e8966 100644
--- a/internal/dataplane/kongstate/kongstate_test.go
+++ b/internal/dataplane/kongstate/kongstate_test.go
@@ -1134,7 +1134,7 @@ func TestKongState_FillUpstreamOverrides(t *testing.T) {
 			failuresCollector := failures.NewResourceFailuresCollector(logr.Discard())
 
 			kongState := KongState{Upstreams: []Upstream{tc.upstream}}
-			kongState.FillUpstreamOverrides(s, failuresCollector)
+			kongState.FillUpstreamOverrides(s, logr.Discard(), failuresCollector)
 			require.Equal(t, tc.expectedUpstream, kongState.Upstreams[0].Upstream)
 			require.ElementsMatch(t, tc.expectedFailures, failuresCollector.PopResourceFailures())
 		})
diff --git a/test/e2e/manifests/all-in-one-dbless-k4k8s-enterprise.yaml b/test/e2e/manifests/all-in-one-dbless-k4k8s-enterprise.yaml
index f2aaa8e8f..6fa36e055 100644
--- a/test/e2e/manifests/all-in-one-dbless-k4k8s-enterprise.yaml
+++ b/test/e2e/manifests/all-in-one-dbless-k4k8s-enterprise.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/e2e/manifests/all-in-one-dbless-konnect-enterprise.yaml b/test/e2e/manifests/all-in-one-dbless-konnect-enterprise.yaml
index 9e1788389..1e7c8ad69 100644
--- a/test/e2e/manifests/all-in-one-dbless-konnect-enterprise.yaml
+++ b/test/e2e/manifests/all-in-one-dbless-konnect-enterprise.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/e2e/manifests/all-in-one-dbless-konnect.yaml b/test/e2e/manifests/all-in-one-dbless-konnect.yaml
index 8750affeb..61ae35ca7 100644
--- a/test/e2e/manifests/all-in-one-dbless-konnect.yaml
+++ b/test/e2e/manifests/all-in-one-dbless-konnect.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/e2e/manifests/all-in-one-dbless.yaml b/test/e2e/manifests/all-in-one-dbless.yaml
index 254547d49..a11a8deb1 100644
--- a/test/e2e/manifests/all-in-one-dbless.yaml
+++ b/test/e2e/manifests/all-in-one-dbless.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/e2e/manifests/all-in-one-postgres-enterprise.yaml b/test/e2e/manifests/all-in-one-postgres-enterprise.yaml
index 8e8b97897..816e184c1 100644
--- a/test/e2e/manifests/all-in-one-postgres-enterprise.yaml
+++ b/test/e2e/manifests/all-in-one-postgres-enterprise.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/e2e/manifests/all-in-one-postgres.yaml b/test/e2e/manifests/all-in-one-postgres.yaml
index 3c570281d..55edbb4d5 100644
--- a/test/e2e/manifests/all-in-one-postgres.yaml
+++ b/test/e2e/manifests/all-in-one-postgres.yaml
@@ -953,6 +953,13 @@ spec:
                 type: integer
             type: object
         type: object
+        x-kubernetes-validations:
+        - message: '''proxy'' field is no longer supported, use Service''s annotations
+            instead'
+          rule: '!has(self.proxy)'
+        - message: '''route'' field is no longer supported, use Ingress'' annotations
+            instead'
+          rule: '!has(self.route)'
     served: true
     storage: true
     subresources:
diff --git a/test/envtest/crds_envtest_test.go b/test/envtest/crds_envtest_test.go
index 3cf27d44f..e5390310f 100644
--- a/test/envtest/crds_envtest_test.go
+++ b/test/envtest/crds_envtest_test.go
@@ -24,6 +24,7 @@ import (
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/annotations"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/manager"
 	"github.com/kong/kubernetes-ingress-controller/v3/internal/util"
+	kongv1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1"
 	kongv1beta1 "github.com/kong/kubernetes-ingress-controller/v3/pkg/apis/configuration/v1beta1"
 	"github.com/kong/kubernetes-ingress-controller/v3/pkg/clientset"
 	"github.com/kong/kubernetes-ingress-controller/v3/test/consts"
@@ -457,6 +458,28 @@ func TestCRDValidations(t *testing.T) {
 				require.ErrorContains(t, err, `spec.hashOnFallback must not be set when spec.hashOn.cookie is set.`)
 			},
 		},
+		{
+			name: "KongIngress - proxy is not allowed",
+			scenario: func(ctx context.Context, t *testing.T, ns string) {
+				err := createKongIngress(ctx, ctrlClient, ns, &kongv1.KongIngress{
+					Proxy: &kongv1.KongIngressService{
+						Retries: lo.ToPtr(5),
+					},
+				})
+				require.ErrorContains(t, err, "'proxy' field is no longer supported, use Service's annotations instead")
+			},
+		},
+		{
+			name: "KongIngress - route is not allowed",
+			scenario: func(ctx context.Context, t *testing.T, ns string) {
+				err := createKongIngress(ctx, ctrlClient, ns, &kongv1.KongIngress{
+					Route: &kongv1.KongIngressRoute{
+						PreserveHost: lo.ToPtr(true),
+					},
+				})
+				require.ErrorContains(t, err, "'route' field is no longer supported, use Ingress' annotations instead")
+			},
+		},
 	}
 
 	for _, tc := range testCases {
@@ -598,3 +621,9 @@ func generateInvalidHashOns() []kongv1beta1.KongUpstreamHash {
 		return fmt.Sprintf("%s.%s.%s.%s", optStr(h.Cookie), optStr(h.Header), optStr(h.URICapture), optStr(h.QueryArg))
 	})
 }
+
+func createKongIngress(ctx context.Context, client client.Client, ns string, ingress *kongv1.KongIngress) error {
+	ingress.GenerateName = "test-"
+	ingress.Namespace = ns
+	return client.Create(ctx, ingress)
+}
diff --git a/test/integration/kongingress_webhook_test.go b/test/integration/kongingress_webhook_test.go
index 0566bbbdb..aa7b2cb17 100644
--- a/test/integration/kongingress_webhook_test.go
+++ b/test/integration/kongingress_webhook_test.go
@@ -55,13 +55,9 @@ func TestKongIngressValidationWebhook(t *testing.T) {
 			ObjectMeta: metav1.ObjectMeta{
 				GenerateName: "kong-ingress-validation-",
 			},
-			// Proxy field is deprecated, expecting warning for it.
-			Proxy: &kongv1.KongIngressService{
-				Protocol: lo.ToPtr("tcp"),
-			},
-			// Route field is deprecated, expecting warning for it.
-			Route: &kongv1.KongIngressRoute{
-				Methods: []*string{lo.ToPtr("POST")},
+			// Upstream field is deprecated, expecting warning for it.
+			Upstream: &kongv1.KongIngressUpstream{
+				HashOn: lo.ToPtr("none"),
 			},
 		}
 
@@ -73,10 +69,8 @@ func TestKongIngressValidationWebhook(t *testing.T) {
 			Do(ctx)
 
 		assert.NoError(t, result.Error())
-		require.Len(t, result.Warnings(), 2)
 		expectedWarnings := []string{
-			"'route' is DEPRECATED. It will have no effect. Use Ingress' annotations instead.",
-			"'proxy' is DEPRECATED. It will have no effect. Use Service's annotations instead.",
+			"'upstream' is DEPRECATED and will be removed in a future version. Use a KongUpstreamPolicy resource instead.",
 		}
 		receivedWarnings := lo.Map(result.Warnings(), func(item net.WarningHeader, index int) string {
 			return item.Text