From 4bf30ec3efd2f75efa7a066978ca0e81c35d9a9c Mon Sep 17 00:00:00 2001
From: Ricardo Katz <rikatz@users.noreply.github.com>
Date: Sat, 21 Aug 2021 17:42:00 -0300
Subject: [PATCH] Release v1 (#7470)

* Drop v1beta1 from ingress nginx (#7156)

* Drop v1beta1 from ingress nginx

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix intorstr logic in controller

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* fixing admission

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* more intorstr fixing

* correct template rendering

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix e2e tests for v1 api

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix gofmt errors

* This is finally working...almost there...

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Re-add removed validation of AdmissionReview

* Prepare for v1.0.0-alpha.1 release

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Update changelog and matrix table for v1.0.0-alpha.1 (#7274)

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* add docs for syslog feature (#7219)

* Fix link to e2e-tests.md in developer-guide (#7201)

* Use ENV expansion for namespace in args (#7146)

Update the DaemonSet namespace references to use the `POD_NAMESPACE` environment variable in the same way that the Deployment does.

* chart: using Helm builtin capabilities check (#7190)

Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>

* Update proper default value for HTTP2MaxConcurrentStreams in Docs (#6944)

It should be 128 as documented in https://github.com/kubernetes/ingress-nginx/blob/master/internal/ingress/controller/config/config.go#L780

* Fix MaxWorkerOpenFiles calculation on high cores nodes (#7107)

* Fix MaxWorkerOpenFiles calculation on high cores nodes

* Add e2e test for rlimit_nofile

* Fix doc for max-worker-open-files

* ingress/tcp: add additional error logging on failed (#7208)

* Add file containing stable release (#7313)

* Handle named (non-numeric) ports correctly (#7311)

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* Updated v1beta1 to v1 as its deprecated (#7308)

* remove mercurial from build (#7031)

* Retry to download maxmind DB if it fails (#7242)

* Retry to download maxmind DB if it fails.

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Add retries count arg, move retry logic into DownloadGeoLite2DB function

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Reorder parameters in DownloadGeoLite2DB

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Remove hardcoded value

Signed-off-by: Sergey Shakuto <sshakuto@infoblox.com>

* Release v1.0.0-alpha.1

* Add changelog for v1.0.0-alpha.2

* controller: ignore non-service backends (#7332)

* controller: ignore non-service backends

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* update per feedback

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* fix: allow scope/tcp/udp configmap namespace to altered (#7161)

* Lower webhook timeout for digital ocean (#7319)

* Lower webhook timeout for digital ocean

* Set Digital Ocean value controller.admissionWebhooks.timeoutSeconds to 29

* update OWNERS and aliases files (#7365) (#7366)

Signed-off-by: Carlos Panato <ctadeu@gmail.com>

* Downgrade Lua modules for s390x (#7355)

Downgrade Lua modules to last known working version.

* Fix IngressClass logic for newer releases (#7341)

* Fix IngressClass logic for newer releases

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Change e2e tests for the new IngressClass presence

* Fix chart and admission tests

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix helm chart test

Signed-off-by: Ricardo Pchevuzinske Katz <ricardo.katz@gmail.com>

* Fix reviews

* Remove ingressclass code from admission

* update tag to v1.0.0-beta.1

* update readme and changelog for v1.0.0-beta.1

* Release v1.0.0-beta.1 - helm and manifests (#7422)

* Change the order of annotation just to trigger a new helm release (#7425)

* [cherry-pick] Add dev-v1 branch into helm releaser (#7428)

* Add dev-v1 branch into helm releaser (#7424)

* chore: add link for artifacthub.io/prerelease annotations

Signed-off-by: Jintao Zhang <zhangjintao9020@gmail.com>

Co-authored-by: Ricardo Katz <rikatz@users.noreply.github.com>

* k8s job ci pipeline for dev-v1 br v1.22.0 (#7453)

* k8s job ci pipeline for dev-v1 br v1.22.0

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* k8s job ci pipeline for dev-v1 br v1.21.2

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* remove v1.21.1 version

Signed-off-by: Neha Lohia <nehapithadiya444@gmail.com>

* Add controller.watchIngressWithoutClass config option (#7459)

Signed-off-by: Akshit Grover <akshit.grover2016@gmail.com>

* Release new helm chart with certgen fixed (#7478)

* Update go version, modules and remove ioutil

* Release new helm chart with certgen fixed

* changed appversion, chartversion, TAG, image (#7490)

* Fix CI conflict

* Fix CI conflict

* Fix build.sh from rebase process

* Fix controller_test post rebase

Co-authored-by: Tianhao Guo <rggth09@gmail.com>
Co-authored-by: Ray <61553+rctay@users.noreply.github.com>
Co-authored-by: Bill Cassidy <cassid4@gmail.com>
Co-authored-by: Jintao Zhang <tao12345666333@163.com>
Co-authored-by: Sathish Ramani <rsathishx87@gmail.com>
Co-authored-by: Mansur Marvanov <nanorobocop@gmail.com>
Co-authored-by: Matt1360 <568198+Matt1360@users.noreply.github.com>
Co-authored-by: Carlos Tadeu Panato Junior <ctadeu@gmail.com>
Co-authored-by: Kundan Kumar <kundan.kumar@india.nec.com>
Co-authored-by: Tom Hayward <thayward@infoblox.com>
Co-authored-by: Sergey Shakuto <sshakuto@infoblox.com>
Co-authored-by: Tore <tore.lonoy@gmail.com>
Co-authored-by: Bouke Versteegh <info@boukeversteegh.nl>
Co-authored-by: Shahid <shahid@us.ibm.com>
Co-authored-by: James Strong <strong.james.e@gmail.com>
Co-authored-by: Long Wu Yuan <longwuyuan@gmail.com>
Co-authored-by: Jintao Zhang <zhangjintao9020@gmail.com>
Co-authored-by: Neha Lohia <nehapithadiya444@gmail.com>
Co-authored-by: Akshit Grover <akshit.grover2016@gmail.com>
---
 .github/workflows/ci.yaml                     |  23 +-
 Changelog.md                                  |  76 +++
 README.md                                     |   1 +
 RELEASE.md                                    |   2 +
 TAG                                           |   2 +-
 charts/ingress-nginx/Chart.yaml               |  12 +-
 charts/ingress-nginx/OWNERS                   |   2 +-
 .../controller-custom-ingressclass-flags.yaml |   7 +
 .../ci/daemonset-customconfig-values.yaml     |   4 +
 .../ci/daemonset-customnodeport-values.yaml   |   4 +
 .../ci/daemonset-headers-values.yaml          |   4 +
 .../ci/daemonset-internal-lb-values.yaml      |   4 +
 .../ci/daemonset-nodeport-values.yaml         |   4 +
 .../ci/daemonset-podannotations-values.yaml   |   4 +
 ...set-tcp-udp-configMapNamespace-values.yaml |   4 +
 .../ci/daemonset-tcp-udp-values.yaml          |   4 +
 .../ci/daemonset-tcp-values.yaml              |   4 +
 .../ci/deamonset-default-values.yaml          |   4 +
 .../ci/deamonset-metrics-values.yaml          |   4 +
 .../ci/deamonset-psp-values.yaml              |   4 +
 .../ci/deamonset-webhook-and-psp-values.yaml  |   4 +
 .../ci/deamonset-webhook-values.yaml          |   4 +
 .../ci/deployment-autoscaling-values.yaml     |   4 +
 .../ci/deployment-customconfig-values.yaml    |   4 +
 .../ci/deployment-customnodeport-values.yaml  |   4 +
 .../ci/deployment-default-values.yaml         |   4 +
 .../ci/deployment-headers-values.yaml         |   4 +
 .../ci/deployment-internal-lb-values.yaml     |   4 +
 .../ci/deployment-metrics-values.yaml         |   4 +
 .../ci/deployment-nodeport-values.yaml        |   4 +
 .../ci/deployment-podannotations-values.yaml  |   4 +
 .../ci/deployment-psp-values.yaml             |   4 +
 ...ent-tcp-udp-configMapNamespace-values.yaml |   4 +
 .../ci/deployment-tcp-udp-values.yaml         |   4 +
 .../ci/deployment-tcp-values.yaml             |   4 +
 .../ci/deployment-webhook-and-psp-values.yaml |   4 +
 .../ci/deployment-webhook-values.yaml         |   4 +
 charts/ingress-nginx/templates/NOTES.txt      |   2 +-
 .../validating-webhook.yaml                   |   5 +-
 .../ingress-nginx/templates/clusterrole.yaml  |   8 +-
 .../templates/controller-daemonset.yaml       |  15 +-
 .../templates/controller-deployment.yaml      |  13 +-
 .../templates/controller-ingressclass.yaml    |  12 +-
 .../templates/controller-role.yaml            |  10 +-
 .../templates/controller-servicemonitor.yaml  |   2 +-
 charts/ingress-nginx/values.yaml              |  34 +-
 cmd/nginx/flags.go                            |  35 +-
 cmd/nginx/main.go                             |  36 +-
 cmd/plugin/commands/ingresses/ingresses.go    |  29 +-
 .../commands/ingresses/ingresses_test.go      |  75 +++
 cmd/plugin/commands/lint/main.go              |   2 +-
 cmd/plugin/lints/ingress.go                   |   2 +-
 cmd/plugin/request/request.go                 |   4 +-
 .../provider/aws/deploy-tls-termination.yaml  | 127 ++--
 deploy/static/provider/aws/deploy.yaml        | 125 ++--
 deploy/static/provider/baremetal/deploy.yaml  | 125 ++--
 deploy/static/provider/cloud/deploy.yaml      | 125 ++--
 deploy/static/provider/do/deploy.yaml         | 126 ++--
 deploy/static/provider/exoscale/deploy.yaml   | 127 ++--
 deploy/static/provider/kind/deploy.yaml       | 125 ++--
 deploy/static/provider/scw/deploy.yaml        | 125 ++--
 docs/developer-guide/getting-started.md       |   2 +-
 .../affinity/cookie/ingress-samesite.yaml     |   4 +-
 docs/examples/affinity/cookie/ingress.yaml    |   2 +-
 docs/examples/auth/basic/README.md            |   2 +-
 docs/examples/auth/client-certs/ingress.yaml  |   2 +-
 docs/examples/auth/external-auth/README.md    |   4 +-
 docs/examples/auth/external-auth/ingress.yaml |   2 +-
 .../dashboard-ingress.yaml                    |   4 +-
 docs/examples/chashsubset/deployment.yaml     |   2 +-
 .../configuration-snippets/ingress.yaml       |   2 +-
 .../deploy/echo-service.yaml                  |   4 +-
 .../docker-registry/ingress-with-tls.yaml     |   2 +-
 .../docker-registry/ingress-without-tls.yaml  |   2 +-
 docs/examples/multi-tls/multi-tls.yaml        |   2 +-
 docs/examples/rewrite/README.md               |   4 +-
 docs/examples/static-ip/nginx-ingress.yaml    |   2 +-
 docs/examples/tls-termination/README.md       |   2 +-
 docs/examples/tls-termination/ingress.yaml    |   2 +-
 docs/troubleshooting.md                       |   2 +-
 docs/user-guide/fcgi-services.md              |   2 +-
 docs/user-guide/ingress-path-matching.md      |   8 +-
 .../nginx-configuration/annotations.md        |   2 +-
 .../nginx-configuration/configmap.md          |  19 +-
 .../third-party-addons/opentracing.md         |   2 +-
 go.mod                                        |   2 +-
 hack/generate-deploy-scripts.sh               |   2 +
 images/nginx/rootfs/build.sh                  |  25 +
 internal/admission/controller/convert.go      |  90 ---
 internal/admission/controller/main.go         |  35 +-
 internal/admission/controller/main_test.go    |   4 +-
 internal/admission/controller/server.go       |   2 -
 internal/ingress/annotations/alias/main.go    |   2 +-
 .../ingress/annotations/alias/main_test.go    |   2 +-
 internal/ingress/annotations/annotations.go   |   2 +-
 .../ingress/annotations/annotations_test.go   |  21 +-
 internal/ingress/annotations/auth/main.go     |   2 +-
 .../ingress/annotations/auth/main_test.go     |  21 +-
 internal/ingress/annotations/authreq/main.go  |   2 +-
 .../ingress/annotations/authreq/main_test.go  |  22 +-
 .../ingress/annotations/authreqglobal/main.go |   2 +-
 .../annotations/authreqglobal/main_test.go    |  22 +-
 internal/ingress/annotations/authtls/main.go  |   2 +-
 .../ingress/annotations/authtls/main_test.go  |  21 +-
 .../annotations/backendprotocol/main.go       |   2 +-
 .../annotations/backendprotocol/main_test.go  |  14 +-
 internal/ingress/annotations/canary/main.go   |   2 +-
 .../ingress/annotations/canary/main_test.go   |  21 +-
 internal/ingress/annotations/class/main.go    |  63 --
 .../ingress/annotations/class/main_test.go    | 103 ----
 .../annotations/clientbodybuffersize/main.go  |   2 +-
 .../clientbodybuffersize/main_test.go         |   2 +-
 .../ingress/annotations/connection/main.go    |   2 +-
 .../annotations/connection/main_test.go       |   2 +-
 internal/ingress/annotations/cors/main.go     |   2 +-
 .../ingress/annotations/cors/main_test.go     |  21 +-
 .../annotations/customhttperrors/main.go      |   2 +-
 .../annotations/customhttperrors/main_test.go |  14 +-
 .../annotations/defaultbackend/main.go        |   2 +-
 .../annotations/defaultbackend/main_test.go   |  22 +-
 internal/ingress/annotations/fastcgi/main.go  |   2 +-
 .../ingress/annotations/fastcgi/main_test.go  |  14 +-
 .../annotations/globalratelimit/main.go       |   2 +-
 .../annotations/globalratelimit/main_test.go  |  21 +-
 .../annotations/http2pushpreload/main.go      |   2 +-
 .../annotations/http2pushpreload/main_test.go |   2 +-
 internal/ingress/annotations/influxdb/main.go |   2 +-
 .../ingress/annotations/influxdb/main_test.go |  21 +-
 .../ingress/annotations/ipwhitelist/main.go   |   2 +-
 .../annotations/ipwhitelist/main_test.go      |  21 +-
 .../ingress/annotations/loadbalancing/main.go |   2 +-
 .../annotations/loadbalancing/main_test.go    |   2 +-
 internal/ingress/annotations/log/main.go      |   2 +-
 internal/ingress/annotations/log/main_test.go |  21 +-
 internal/ingress/annotations/mirror/main.go   |   2 +-
 .../ingress/annotations/mirror/main_test.go   |   2 +-
 .../ingress/annotations/modsecurity/main.go   |   2 +-
 .../annotations/modsecurity/main_test.go      |   2 +-
 .../ingress/annotations/opentracing/main.go   |   2 +-
 .../annotations/opentracing/main_test.go      |  21 +-
 internal/ingress/annotations/parser/main.go   |   2 +-
 .../ingress/annotations/parser/main_test.go   |   2 +-
 .../annotations/portinredirect/main.go        |   2 +-
 .../annotations/portinredirect/main_test.go   |  21 +-
 internal/ingress/annotations/proxy/main.go    |   2 +-
 .../ingress/annotations/proxy/main_test.go    |  21 +-
 internal/ingress/annotations/proxyssl/main.go |   2 +-
 .../ingress/annotations/proxyssl/main_test.go |  21 +-
 .../ingress/annotations/ratelimit/main.go     |   2 +-
 .../annotations/ratelimit/main_test.go        |  21 +-
 .../ingress/annotations/redirect/redirect.go  |   2 +-
 .../annotations/redirect/redirect_test.go     |   2 +-
 internal/ingress/annotations/rewrite/main.go  |   2 +-
 .../ingress/annotations/rewrite/main_test.go  |  21 +-
 internal/ingress/annotations/satisfy/main.go  |   2 +-
 .../ingress/annotations/satisfy/main_test.go  |  21 +-
 .../annotations/secureupstream/main.go        |   2 +-
 .../annotations/secureupstream/main_test.go   |  21 +-
 .../ingress/annotations/serversnippet/main.go |   2 +-
 .../annotations/serversnippet/main_test.go    |   2 +-
 .../annotations/serviceupstream/main.go       |   2 +-
 .../annotations/serviceupstream/main_test.go  |  21 +-
 .../annotations/sessionaffinity/main.go       |   2 +-
 .../annotations/sessionaffinity/main_test.go  |  22 +-
 internal/ingress/annotations/snippet/main.go  |   2 +-
 .../ingress/annotations/snippet/main_test.go  |   2 +-
 .../ingress/annotations/sslcipher/main.go     |   2 +-
 .../annotations/sslcipher/main_test.go        |   2 +-
 .../annotations/sslpassthrough/main.go        |   2 +-
 .../annotations/sslpassthrough/main_test.go   |  14 +-
 .../annotations/upstreamhashby/main.go        |   2 +-
 .../annotations/upstreamhashby/main_test.go   |   2 +-
 .../ingress/annotations/upstreamvhost/main.go |   2 +-
 .../annotations/upstreamvhost/main_test.go    |   2 +-
 .../annotations/xforwardedprefix/main.go      |   2 +-
 .../annotations/xforwardedprefix/main_test.go |   2 +-
 internal/ingress/controller/controller.go     | 163 +++--
 .../ingress/controller/controller_test.go     | 339 ++++++----
 .../controller/ingressclass/ingressclass.go   |  45 ++
 internal/ingress/controller/location.go       |   2 +-
 internal/ingress/controller/nginx.go          |  19 +-
 .../ingress/controller/store/backend_ssl.go   |   2 +-
 internal/ingress/controller/store/ingress.go  |   2 +-
 .../ingress/controller/store/ingressclass.go  |  39 ++
 internal/ingress/controller/store/store.go    | 161 ++++-
 .../ingress/controller/store/store_test.go    | 582 ++++++++++++++----
 internal/ingress/controller/tcp.go            |   1 +
 .../ingress/controller/template/template.go   |  25 +-
 .../controller/template/template_test.go      | 157 ++++-
 internal/ingress/controller/util.go           |  27 +-
 internal/ingress/metric/main.go               |  11 +-
 internal/ingress/status/status.go             |   2 +-
 internal/ingress/status/status_test.go        |  12 +-
 internal/ingress/types.go                     |   2 +-
 internal/k8s/main.go                          |  29 +-
 stable.txt                                    |   2 +-
 .../forwarded-port-headers/values.yaml        |   4 +-
 test/e2e/admission/admission.go               |  91 +--
 test/e2e/annotations/affinity.go              |  29 +-
 test/e2e/annotations/auth.go                  |   2 +-
 test/e2e/annotations/canary.go                |  56 +-
 test/e2e/annotations/customhttperrors.go      |   2 +-
 test/e2e/annotations/satisfy.go               |   2 +-
 test/e2e/defaultbackend/with_hosts.go         |  14 +-
 test/e2e/framework/framework.go               |  86 ++-
 test/e2e/framework/k8s.go                     |   8 +-
 test/e2e/framework/util.go                    |  95 ++-
 test/e2e/ingress/multiple_rules.go            |  26 +-
 test/e2e/ingress/pathtype_exact.go            |   7 +-
 test/e2e/ingress/pathtype_mixed.go            |   7 +-
 test/e2e/ingress/without_host.go              |  14 +-
 test/e2e/leaks/lua_ssl.go                     |   2 +-
 test/e2e/lua/dynamic_certificates.go          |  18 +-
 test/e2e/lua/dynamic_configuration.go         |   6 +-
 test/e2e/run-chart-test.sh                    |  24 +-
 test/e2e/run.sh                               |   4 +-
 test/e2e/servicebackend/service_backend.go    |  27 +-
 .../servicebackend/service_externalname.go    |  36 +-
 test/e2e/settings/disable_catch_all.go        |  13 +-
 test/e2e/settings/global_external_auth.go     |   2 +-
 test/e2e/settings/global_options.go           |  58 ++
 test/e2e/settings/ingress_class.go            | 516 ++++++++++------
 test/e2e/settings/no_auth_locations.go        |  27 +-
 test/e2e/settings/server_tokens.go            |  16 +-
 test/e2e/status/update.go                     |   8 +-
 test/e2e/wait-for-nginx.sh                    |   4 +
 226 files changed, 3508 insertions(+), 1889 deletions(-)
 create mode 100644 charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml
 create mode 100644 cmd/plugin/commands/ingresses/ingresses_test.go
 delete mode 100644 internal/admission/controller/convert.go
 delete mode 100644 internal/ingress/annotations/class/main.go
 delete mode 100644 internal/ingress/annotations/class/main_test.go
 create mode 100644 internal/ingress/controller/ingressclass/ingressclass.go
 create mode 100644 internal/ingress/controller/store/ingressclass.go
 mode change 100755 => 100644 test/e2e/settings/global_external_auth.go
 create mode 100644 test/e2e/settings/global_options.go

diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 099d7e2a0b..7470325cc8 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -57,8 +57,6 @@ jobs:
     name: Build
     runs-on: ubuntu-latest
     needs: changes
-    if: |
-      (needs.changes.outputs.go == 'true')
 
     steps:
 
@@ -116,6 +114,7 @@ jobs:
     runs-on: ubuntu-latest
     needs:
       - changes
+      - build
     if: |
       (needs.changes.outputs.charts == 'true')
 
@@ -123,6 +122,11 @@ jobs:
 
       - name: Checkout
         uses: actions/checkout@v2
+    
+      - name: cache
+        uses: actions/download-artifact@v2
+        with:
+          name: docker.tar.gz
 
       - name: Lint
         run: |
@@ -138,12 +142,23 @@ jobs:
         uses: engineerd/setup-kind@v0.5.0
         with:
           version: v0.11.1
-          image: kindest/node:v1.20.2
+          image: kindest/node:v1.21.1
+    
+      - uses: geekyeggo/delete-artifact@v1
+        with:
+          name: docker.tar.gz
+          failOnError: false
+
+      - name: Load images from cache
+        run: |
+          echo "loading docker images..."
+          pigz -dc docker.tar.gz | docker load
 
       - name: Test
         env:
           KIND_CLUSTER_NAME: kind
           SKIP_CLUSTER_CREATION: true
+          SKIP_IMAGE_CREATION: true
         run: |
           kind get kubeconfig > $HOME/.kube/kind-config-kind
           make kind-e2e-chart-tests
@@ -159,7 +174,7 @@ jobs:
 
     strategy:
       matrix:
-        k8s: [v1.16.15, v1.17.17, v1.18.19, v1.19.11, v1.20.7, v1.21.2]
+        k8s: [v1.19.11, v1.20.7, v1.21.2, v1.22.0]
 
     steps:
 
diff --git a/Changelog.md b/Changelog.md
index c92a69301b..23a2a1e3e9 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -81,6 +81,82 @@ _Changes:_
 - [X] [#7216](https://github.com/kubernetes/ingress-nginx/pull/7216) Admission: Skip validation checks if an ingress 
   is marked as deleted #7216
   
+### 1.0.0-beta.3
+** This is a breaking change**
+
+This release only supports Kubernetes versions >= v1.19. The support for Ingress Object in `networking.k8s.io/v1beta` is being dropped and manifests should now use `networking.k8s.io/v1`.
+
+**Image:**
+
+- `k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695`
+
+Changes:
+
+- [X] [#7487](https://github.com/kubernetes/ingress-nginx/pull/7487)[Cherry - Pick] - Fix default backend annotation and tests
+- [X] [#7459](https://github.com/kubernetes/ingress-nginx/pull/7459) Add controller.watchIngressWithoutClass config option 
+- [X] [#7478](https://github.com/kubernetes/ingress-nginx/pull/7478) Release new helm chart with certgen fixed 
+
+### 1.0.0-beta.1
+**THIS IS A BREAKING CHANGE**
+
+This release only supports Kubernetes versions >= v1.19. The support for Ingress Object in `networking.k8s.io/v1beta` is being dropped and manifests should now use `networking.k8s.io/v1`.
+
+**Image:**
+
+- `k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.1@sha256:f058f3fdc940095957695829745956c6acddcaef839907360965e27fd3348e2e`
+
+_ New Features:_
+
+_Changes:_
+
+- [X] [#7341](https://github.com/kubernetes/ingress-nginx/pull/7341) Fix IngressClass logic for newer releases (#7341)
+- [X] [#7355](https://github.com/kubernetes/ingress-nginx/pull/7355) Downgrade Lua modules for s390x (#7355)
+- [X] [#7319](https://github.com/kubernetes/ingress-nginx/pull/7319) Lower webhook timeout for digital ocean (#7319)
+- [X] [#7161](https://github.com/kubernetes/ingress-nginx/pull/7161) fix: allow scope/tcp/udp configmap namespace to altered (#7161)
+- [X] [#7331](https://github.com/kubernetes/ingress-nginx/pull/7331) Fix forwarding of auth-response-headers to gRPC backends (#7331)
+- [X] [#7332](https://github.com/kubernetes/ingress-nginx/pull/7332) controller: ignore non-service backends (#7332)
+
+### 1.0.0-alpha.2
+**THIS IS A BREAKING CHANGE**
+
+This release only supports Kubernetes versions >= v1.19. The support for Ingress Object in `networking.k8s.io/v1beta` is being dropped and manifests should now use `networking.k8s.io/v1`.
+
+**Image:**
+
+- `k8s.gcr.io/ingress-nginx/controller:v1.0.0-alpha.2@sha256:04a0ad3a1279c2a58898e789eed767eafa138ee1e5b9b23a988c6e8485cf958d`
+
+_ New Features:_
+
+- [X] [#7314](https://github.com/kubernetes/ingress-nginx/pull/7314) Add configuration to disable external name service feature
+- [X] [#7313](https://github.com/kubernetes/ingress-nginx/pull/7313) Add file containing stable release 
+- [X] [#7311](https://github.com/kubernetes/ingress-nginx/pull/7311) Handle named (non-numeric) ports correctly
+- [X] [#7308](https://github.com/kubernetes/ingress-nginx/pull/7308) Updated v1beta1 to v1 as its deprecated
+- [X] [#7298](https://github.com/kubernetes/ingress-nginx/pull/7298) Speed up admission hook by eliminating deep copy of Ingresses in CheckIngress 
+- [X] [#7242](https://github.com/kubernetes/ingress-nginx/pull/7242) Retry to download maxmind DB if it fails 
+- [X] [#7228](https://github.com/kubernetes/ingress-nginx/pull/7228) Discover mounted geoip db files
+- [X] [#7208](https://github.com/kubernetes/ingress-nginx/pull/7208) ingress/tcp: add additional error logging on failed
+- [X] [#7190](https://github.com/kubernetes/ingress-nginx/pull/7190) chart: using Helm builtin capabilities check
+- [X] [#7146](https://github.com/kubernetes/ingress-nginx/pull/7146) Use ENV expansion for namespace in args
+- [X] [#7107](https://github.com/kubernetes/ingress-nginx/pull/7107) Fix MaxWorkerOpenFiles calculation on high cores nodes
+- [X] [#7076](https://github.com/kubernetes/ingress-nginx/pull/7076) Rewrite clean-nginx-conf.sh in Go to speed up admission webhook
+- [X] [#7031](https://github.com/kubernetes/ingress-nginx/pull/7031) Remove mercurial from build
+- [X] [#6990](https://github.com/kubernetes/ingress-nginx/pull/6990) Use listen to ensure the port is free
+- [X] [#6944](https://github.com/kubernetes/ingress-nginx/pull/6944) Update proper default value for HTTP2MaxConcurrentStreams in Docs
+- [X] [#6940](https://github.com/kubernetes/ingress-nginx/pull/6940) Fix definition order of modsecurity directives 
+
+### 1.0.0-alpha.1
+**THIS IS A BREAKING CHANGE**
+
+This release only supports Kubernetes versions >= v1.19. The support for Ingress Object in `networking.k8s.io/v1beta` is being dropped and manifests should now use `networking.k8s.io/v1`.
+
+**Image:**
+
+- `k8s.gcr.io/ingress-nginx/controller:v1.0.0-alpha.1@sha256:32f3f02a038c0d7cf33b71a14028c3a4ddee6f4c3fe5fadfa14b915e5e0d9faf`
+
+_ New Features:_
+
+- [X] [#7156] Drops support for Ingress Object v1beta1
+
 ### 0.47.0
 
 **Image:**
diff --git a/README.md b/README.md
index 5d8efeccb1..a955debc11 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ For detailed changes on the `ingress-nginx` helm chart, please check the followi
 
 | Ingress-nginx version | k8s supported version  | Alpine Version | Nginx Version |
 |-----------------------|-------------           |----------------|---------------|
+| v1.0.0-beta.1         | 1.22, 1.21, 1.20, 1.19 | 3.13.5         |  1.20.1       |
 | v1.0.0-alpha.2        | 1.22, 1.21, 1.20, 1.19 | 3.13.5         |  1.20.1       |
 | v1.0.0-alpha.1        | 1.21, 1.20, 1.19       | 3.13.5         |  1.20.1       |
 | v0.49.0               | 1.21, 1.20, 1.19       | 3.13.5         |  1.20.1       |
diff --git a/RELEASE.md b/RELEASE.md
index 1ed6eaef78..659617c10c 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -74,5 +74,7 @@ The sha is available in output from [cloud build](https://console.cloud.google.c
     * Update the version in [docs/deploy/index.md](docs/deploy/index.md)
     * Update Supported versions in the Support Versions table in the README.md 
     * Merge
+
+* Update the stable.txt file to reflect the release to be created
       
 7. Github release
diff --git a/TAG b/TAG
index 9dc0e188ef..cd5e5ef122 100644
--- a/TAG
+++ b/TAG
@@ -1 +1 @@
-v0.49.0
+v1.0.0-beta.3
diff --git a/charts/ingress-nginx/Chart.yaml b/charts/ingress-nginx/Chart.yaml
index 9961606071..e6b8b318a6 100644
--- a/charts/ingress-nginx/Chart.yaml
+++ b/charts/ingress-nginx/Chart.yaml
@@ -2,8 +2,8 @@ apiVersion: v2
 name: ingress-nginx
 # When the version is modified, make sure the artifacthub.io/changes list is updated
 # Also update CHANGELOG.md
-version: 3.36.0
-appVersion: 0.49.0
+version: 4.0.0-beta.3
+appVersion: 1.0.0-beta.3
 home: https://github.com/kubernetes/ingress-nginx
 description: Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer
 icon: https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Nginx_logo.svg/500px-Nginx_logo.svg.png
@@ -16,10 +16,12 @@ type: application
 maintainers:
   - name: ChiefAlexander
 engine: gotpl
-kubeVersion: ">=1.16.0-0"
+kubeVersion: ">=1.19.0-0"
 annotations:
+  # Use this annotation to indicate that this chart version is a pre-release.
+  # https://artifacthub.io/docs/topics/annotations/helm/
+  artifacthub.io/prerelease: "true"
   # List of changes for the release in artifacthub.io
   # https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx?modal=changelog
   artifacthub.io/changes: |
-    - Migrate the webhook-certgen program inside ingress repo.
-    - Fix forwarding of auth-response-headers to gRPC backends
+    - Fix default backend annotation and tests
diff --git a/charts/ingress-nginx/OWNERS b/charts/ingress-nginx/OWNERS
index 392bc92f55..6b7e049ca8 100644
--- a/charts/ingress-nginx/OWNERS
+++ b/charts/ingress-nginx/OWNERS
@@ -7,4 +7,4 @@ reviewers:
 - ingress-nginx-helm-reviewers
 
 labels:
-- area/helm
\ No newline at end of file
+- area/helm
diff --git a/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml b/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml
new file mode 100644
index 0000000000..b28a2326ee
--- /dev/null
+++ b/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml
@@ -0,0 +1,7 @@
+controller:
+  watchIngressWithoutClass: true
+  ingressClassResource:
+    name: custom-nginx
+    enabled: true
+    default: true
+    controllerValue: "k8s.io/custom-nginx"
diff --git a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml b/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml
index e12b53421b..43dd2b2ac9 100644
--- a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   kind: DaemonSet
   admissionWebhooks:
     enabled: false
diff --git a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml
index cfc545f69f..1d94be219b 100644
--- a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
 
diff --git a/charts/ingress-nginx/ci/daemonset-headers-values.yaml b/charts/ingress-nginx/ci/daemonset-headers-values.yaml
index ff82cd9c70..ab7d47bd4d 100644
--- a/charts/ingress-nginx/ci/daemonset-headers-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-headers-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   addHeaders:
diff --git a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml b/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml
index d8948d634b..0a200a7460 100644
--- a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml
index 6d6605f0e1..3b7aa2fcd2 100644
--- a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml b/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml
index 04ac58dbd8..0b55306a10 100644
--- a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   metrics:
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml
index afb5487c57..acd86a77ab 100644
--- a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml
index 7b4d7cbe7d..25ee64d856 100644
--- a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-values.yaml
index a359a6a401..380c8b4b13 100644
--- a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml
+++ b/charts/ingress-nginx/ci/daemonset-tcp-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deamonset-default-values.yaml b/charts/ingress-nginx/ci/deamonset-default-values.yaml
index e63a7f5db3..82fa23e854 100644
--- a/charts/ingress-nginx/ci/deamonset-default-values.yaml
+++ b/charts/ingress-nginx/ci/deamonset-default-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml b/charts/ingress-nginx/ci/deamonset-metrics-values.yaml
index 1e5190afc0..cb3cb54be2 100644
--- a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml
+++ b/charts/ingress-nginx/ci/deamonset-metrics-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   metrics:
diff --git a/charts/ingress-nginx/ci/deamonset-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-psp-values.yaml
index 017b60a9c6..8026a6356f 100644
--- a/charts/ingress-nginx/ci/deamonset-psp-values.yaml
+++ b/charts/ingress-nginx/ci/deamonset-psp-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml
index 88aafc66fd..fccdb134cf 100644
--- a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml
+++ b/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: true
   service:
diff --git a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml b/charts/ingress-nginx/ci/deamonset-webhook-values.yaml
index 6e3b371da6..54d364df11 100644
--- a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml
+++ b/charts/ingress-nginx/ci/deamonset-webhook-values.yaml
@@ -1,5 +1,9 @@
 controller:
   kind: DaemonSet
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: true
   service:
diff --git a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml b/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml
index 5314cecb38..b8b3ac6862 100644
--- a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   autoscaling:
     enabled: true
   admissionWebhooks:
diff --git a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml b/charts/ingress-nginx/ci/deployment-customconfig-values.yaml
index f232531acb..85715ddb76 100644
--- a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-customconfig-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   config:
     use-proxy-protocol: "true"
   admissionWebhooks:
diff --git a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml b/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml
index 9eda282b13..a564eaf931 100644
--- a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deployment-default-values.yaml b/charts/ingress-nginx/ci/deployment-default-values.yaml
index 93a393c975..9f46b4e7e9 100644
--- a/charts/ingress-nginx/ci/deployment-default-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-default-values.yaml
@@ -1,4 +1,8 @@
 # Left blank to test default values
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   service:
     type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-headers-values.yaml b/charts/ingress-nginx/ci/deployment-headers-values.yaml
index 665fd48d35..17a11ac370 100644
--- a/charts/ingress-nginx/ci/deployment-headers-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-headers-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   addHeaders:
diff --git a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml b/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml
index c7f22d636e..fd8df8de5d 100644
--- a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deployment-metrics-values.yaml b/charts/ingress-nginx/ci/deployment-metrics-values.yaml
index 887ed0f620..9209ad5a6f 100644
--- a/charts/ingress-nginx/ci/deployment-metrics-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-metrics-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   metrics:
diff --git a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml b/charts/ingress-nginx/ci/deployment-nodeport-values.yaml
index 84f1f7582e..cd9b323528 100644
--- a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-nodeport-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml b/charts/ingress-nginx/ci/deployment-podannotations-values.yaml
index b65a0910b3..b48d93c46a 100644
--- a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-podannotations-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   metrics:
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/deployment-psp-values.yaml
index e339c69c32..2f332a7b20 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-psp-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   service:
     type: ClusterIP
 
diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml
index 141e06b687..c51a4e91fa 100644
--- a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml
index bc29abeba7..5b45b69dcc 100644
--- a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: false
   service:
diff --git a/charts/ingress-nginx/ci/deployment-tcp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-values.yaml
index b7f54c09fa..ac0b6e60eb 100644
--- a/charts/ingress-nginx/ci/deployment-tcp-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-tcp-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   service:
     type: ClusterIP
 
diff --git a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml
index a829c36144..6195bb3391 100644
--- a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: true
   service:
diff --git a/charts/ingress-nginx/ci/deployment-webhook-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-values.yaml
index 4f18a70b9f..76669a5300 100644
--- a/charts/ingress-nginx/ci/deployment-webhook-values.yaml
+++ b/charts/ingress-nginx/ci/deployment-webhook-values.yaml
@@ -1,4 +1,8 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
   admissionWebhooks:
     enabled: true
   service:
diff --git a/charts/ingress-nginx/templates/NOTES.txt b/charts/ingress-nginx/templates/NOTES.txt
index 60fb2c1f62..2eebba3686 100644
--- a/charts/ingress-nginx/templates/NOTES.txt
+++ b/charts/ingress-nginx/templates/NOTES.txt
@@ -29,7 +29,7 @@ Get the application URL by running these commands:
 
 An example Ingress that makes use of the controller:
 
-  apiVersion: networking.k8s.io/v1beta1
+  apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     annotations:
diff --git a/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml b/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
index 2f3dd77848..712f74fdd3 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
@@ -18,7 +18,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -28,12 +28,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: {{ .Release.Namespace | quote }}
         name: {{ include "ingress-nginx.controller.fullname" . }}-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
     {{- if .Values.controller.admissionWebhooks.timeoutSeconds }}
     timeoutSeconds: {{ .Values.controller.admissionWebhooks.timeoutSeconds }}
     {{- end }}
diff --git a/charts/ingress-nginx/templates/clusterrole.yaml b/charts/ingress-nginx/templates/clusterrole.yaml
index b546aaea28..c1f901d50c 100644
--- a/charts/ingress-nginx/templates/clusterrole.yaml
+++ b/charts/ingress-nginx/templates/clusterrole.yaml
@@ -48,8 +48,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -64,14 +63,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
diff --git a/charts/ingress-nginx/templates/controller-daemonset.yaml b/charts/ingress-nginx/templates/controller-daemonset.yaml
index 0c94fcdd4c..34986e568e 100644
--- a/charts/ingress-nginx/templates/controller-daemonset.yaml
+++ b/charts/ingress-nginx/templates/controller-daemonset.yaml
@@ -77,22 +77,22 @@ spec:
           args:
             - /nginx-ingress-controller
           {{- if .Values.defaultBackend.enabled }}
-            - --default-backend-service={{ .Release.Namespace }}/{{ include "ingress-nginx.defaultBackend.fullname" . }}
+            - --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
           {{- end }}
           {{- if .Values.controller.publishService.enabled }}
             - --publish-service={{ template "ingress-nginx.controller.publishServicePath" . }}
           {{- end }}
             - --election-id={{ .Values.controller.electionID }}
-            - --ingress-class={{ .Values.controller.ingressClass }}
-            - --configmap={{ .Release.Namespace }}/{{ include "ingress-nginx.controller.fullname" . }}
+            - --controller-class={{ .Values.controller.ingressClassResource.controllerValue }}
+            - --configmap={{ default "$(POD_NAMESPACE)" .Values.controller.configMapNamespace }}/{{ include "ingress-nginx.controller.fullname" . }}
           {{- if .Values.tcp }}
-            - --tcp-services-configmap={{ .Release.Namespace }}/{{ include "ingress-nginx.fullname" . }}-tcp
+            - --tcp-services-configmap={{ default "$(POD_NAMESPACE)" .Values.controller.tcp.configMapNamespace }}/{{ include "ingress-nginx.fullname" . }}-tcp
           {{- end }}
           {{- if .Values.udp }}
-            - --udp-services-configmap={{ .Release.Namespace }}/{{ include "ingress-nginx.fullname" . }}-udp
+            - --udp-services-configmap={{ default "$(POD_NAMESPACE)" .Values.controller.udp.configMapNamespace }}/{{ include "ingress-nginx.fullname" . }}-udp
           {{- end }}
           {{- if .Values.controller.scope.enabled }}
-            - --watch-namespace={{ default .Release.Namespace .Values.controller.scope.namespace }}
+            - --watch-namespace={{ default "$(POD_NAMESPACE)" .Values.controller.scope.namespace }}
           {{- end }}
           {{- if and .Values.controller.reportNodeInternalIp .Values.controller.hostNetwork }}
             - --report-node-internal-ip-address={{ .Values.controller.reportNodeInternalIp }}
@@ -111,6 +111,9 @@ spec:
           {{- if not (eq .Values.controller.healthCheckPath "/healthz") }}
             - --health-check-path={{ .Values.controller.healthCheckPath }}
           {{- end }}
+          {{- if .Values.controller.watchIngressWithoutClass }}
+            - --watch-ingress-without-class=true
+          {{- end }}
           {{- range $key, $value := .Values.controller.extraArgs }}
             {{- /* Accept keys without values or with false as value */}}
             {{- if eq ($value | quote | len) 2 }}
diff --git a/charts/ingress-nginx/templates/controller-deployment.yaml b/charts/ingress-nginx/templates/controller-deployment.yaml
index d90f76b320..f17975de33 100644
--- a/charts/ingress-nginx/templates/controller-deployment.yaml
+++ b/charts/ingress-nginx/templates/controller-deployment.yaml
@@ -87,13 +87,13 @@ spec:
             - --publish-service={{ template "ingress-nginx.controller.publishServicePath" . }}
           {{- end }}
             - --election-id={{ .Values.controller.electionID }}
-            - --ingress-class={{ .Values.controller.ingressClass }}
-            - --configmap=$(POD_NAMESPACE)/{{ include "ingress-nginx.controller.fullname" . }}
+            - --controller-class={{ .Values.controller.ingressClassResource.controllerValue }}
+            - --configmap={{ default "$(POD_NAMESPACE)" .Values.controller.configMapNamespace }}/{{ include "ingress-nginx.controller.fullname" . }}
           {{- if .Values.tcp }}
-            - --tcp-services-configmap=$(POD_NAMESPACE)/{{ include "ingress-nginx.fullname" . }}-tcp
+            - --tcp-services-configmap={{ default "$(POD_NAMESPACE)" .Values.controller.tcp.configMapNamespace }}/{{ include "ingress-nginx.fullname" . }}-tcp
           {{- end }}
           {{- if .Values.udp }}
-            - --udp-services-configmap=$(POD_NAMESPACE)/{{ include "ingress-nginx.fullname" . }}-udp
+            - --udp-services-configmap={{ default "$(POD_NAMESPACE)" .Values.controller.udp.configMapNamespace }}/{{ include "ingress-nginx.fullname" . }}-udp
           {{- end }}
           {{- if .Values.controller.scope.enabled }}
             - --watch-namespace={{ default "$(POD_NAMESPACE)" .Values.controller.scope.namespace }}
@@ -112,6 +112,9 @@ spec:
           {{- if not (eq .Values.controller.healthCheckPath "/healthz") }}
             - --health-check-path={{ .Values.controller.healthCheckPath }}
           {{- end }}
+          {{- if .Values.controller.watchIngressWithoutClass }}
+            - --watch-ingress-without-class=true
+          {{- end }}
           {{- range $key, $value := .Values.controller.extraArgs }}
             {{- /* Accept keys without values or with false as value */}}
             {{- if eq ($value | quote | len) 2 }}
@@ -143,7 +146,7 @@ spec:
           {{- end }}
           {{- if .Values.controller.extraEnvs }}
             {{- toYaml .Values.controller.extraEnvs | nindent 12 }}
-          {{- end }}          
+          {{- end }}
           {{- if .Values.controller.startupProbe }}
           startupProbe: {{ toYaml .Values.controller.startupProbe | nindent 12 }}
           {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-ingressclass.yaml b/charts/ingress-nginx/templates/controller-ingressclass.yaml
index f94b9590de..9492784a28 100644
--- a/charts/ingress-nginx/templates/controller-ingressclass.yaml
+++ b/charts/ingress-nginx/templates/controller-ingressclass.yaml
@@ -1,9 +1,7 @@
-{{- if and (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) (.Values.controller.ingressClassResource.enabled) -}}
-{{- if and (semverCompare "=1.18-0" .Capabilities.KubeVersion.GitVersion)  }}
-apiVersion: networking.k8s.io/v1beta1
-{{- else }}
+{{- if .Values.controller.ingressClassResource.enabled -}}
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
 apiVersion: networking.k8s.io/v1
-{{- end }}
 kind: IngressClass
 metadata:
   labels:
@@ -12,12 +10,12 @@ metadata:
     {{- with .Values.controller.labels }}
     {{- toYaml . | nindent 4 }}
     {{- end }}
-  name: {{ .Values.controller.ingressClass }}
+  name: {{ .Values.controller.ingressClassResource.name }}
 {{- if .Values.controller.ingressClassResource.default }}
   annotations:
     ingressclass.kubernetes.io/is-default-class: "true"
 {{- end }}
 spec:
-  controller: k8s.io/ingress-nginx
+  controller: {{ .Values.controller.ingressClassResource.controllerValue }}
   {{ template "ingressClass.parameters" . }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-role.yaml b/charts/ingress-nginx/templates/controller-role.yaml
index 1a5ccd29bf..97c627dacb 100644
--- a/charts/ingress-nginx/templates/controller-role.yaml
+++ b/charts/ingress-nginx/templates/controller-role.yaml
@@ -34,8 +34,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -43,14 +42,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - "networking.k8s.io" # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -62,7 +60,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - {{ .Values.controller.electionID }}-{{ .Values.controller.ingressClass }}
+      - {{ .Values.controller.electionID }}
     verbs:
       - get
       - update
diff --git a/charts/ingress-nginx/templates/controller-servicemonitor.yaml b/charts/ingress-nginx/templates/controller-servicemonitor.yaml
index 066488a040..17894c8be2 100644
--- a/charts/ingress-nginx/templates/controller-servicemonitor.yaml
+++ b/charts/ingress-nginx/templates/controller-servicemonitor.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.serviceMonitor.enabled -}}
+{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) .Values.controller.metrics.enabled .Values.controller.metrics.serviceMonitor.enabled -}}
 apiVersion: monitoring.coreos.com/v1
 kind: ServiceMonitor
 metadata:
diff --git a/charts/ingress-nginx/values.yaml b/charts/ingress-nginx/values.yaml
index 54ee795e69..1c3c1e0215 100644
--- a/charts/ingress-nginx/values.yaml
+++ b/charts/ingress-nginx/values.yaml
@@ -15,8 +15,8 @@ controller:
     # for backwards compatibility consider setting the full image url via the repository value below
     # use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
     # repository:
-    tag: "v0.49.0"
-    digest: sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+    tag: "v1.0.0-beta.3"
+    digest: sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
     pullPolicy: IfNotPresent
     # www-data -> uid 101
     runAsUser: 101
@@ -61,6 +61,11 @@ controller:
   # Ingress status was blank because there is no Service exposing the NGINX Ingress controller in a configuration using the host network, the default --publish-service flag used in standard cloud setups does not apply
   reportNodeInternalIp: false
 
+  # Process Ingress objects without ingressClass annotation/ingressClassName field
+  # Overrides value for --watch-ingress-without-class flag of the controller binary
+  # Defaults to false
+  watchIngressWithoutClass: false
+
   # Required for use with CNI based kubernetes installations (such as ones set up by kubeadm),
   # since CNI and hostport don't mix yet. Can be deprecated once https://github.com/kubernetes/kubernetes/issues/23920
   # is merged
@@ -79,15 +84,13 @@ controller:
   ##
   electionID: ingress-controller-leader
 
-  ## Name of the ingress class to route through this controller
-  ##
-  ingressClass: nginx
-
   # This section refers to the creation of the IngressClass resource
-  # IngressClass resources are supported since k8s >= 1.18
+  # IngressClass resources are supported since k8s >= 1.18 and required since k8s >= 1.19
   ingressClassResource:
-    enabled: false
+    name: nginx
+    enabled: true
     default: false
+    controllerValue: "k8s.io/ingress-nginx"
 
     # Parameters is a link to a custom resource containing additional
     # configuration for the controller. This is optional if the controller
@@ -124,23 +127,23 @@ controller:
   ##
   scope:
     enabled: false
-    namespace: ""   # defaults to .Release.Namespace
+    namespace: ""   # defaults to $(POD_NAMESPACE)
 
   ## Allows customization of the configmap / nginx-configmap namespace
   ##
-  configMapNamespace: ""   # defaults to .Release.Namespace
+  configMapNamespace: ""   # defaults to $(POD_NAMESPACE)
 
   ## Allows customization of the tcp-services-configmap
   ##
   tcp:
-    configMapNamespace: ""   # defaults to .Release.Namespace
+    configMapNamespace: ""   # defaults to $(POD_NAMESPACE)
     ## Annotations to be added to the tcp config configmap
     annotations: {}
 
   ## Allows customization of the udp-services-configmap
   ##
   udp:
-    configMapNamespace: ""   # defaults to .Release.Namespace
+    configMapNamespace: ""   # defaults to $(POD_NAMESPACE)
     ## Annotations to be added to the udp config configmap
     annotations: {}
 
@@ -544,12 +547,13 @@ controller:
     patch:
       enabled: true
       image:
-        registry: docker.io
-        image: jettech/kube-webhook-certgen
+        registry: k8s.gcr.io
+        image: ingress-nginx/kube-webhook-certgen
         # for backwards compatibility consider setting the full image url via the repository value below
         # use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
         # repository:
-        tag: v1.5.1
+        tag: v1.0
+        digest: sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
         pullPolicy: IfNotPresent
       ## Provide a priority class name to the webhook patching job
       ##
diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go
index b125719fdb..aabade07e9 100644
--- a/cmd/nginx/flags.go
+++ b/cmd/nginx/flags.go
@@ -24,10 +24,10 @@ import (
 
 	"github.com/spf13/pflag"
 	apiv1 "k8s.io/api/core/v1"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/controller"
 	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	"k8s.io/ingress-nginx/internal/ingress/status"
 	ing_net "k8s.io/ingress-nginx/internal/net"
 	"k8s.io/ingress-nginx/internal/nginx"
@@ -55,10 +55,18 @@ only when the flag --apiserver-host is specified.`)
 Takes the form "namespace/name". The controller configures NGINX to forward
 requests to the first port of this Service.`)
 
-		ingressClass = flags.String("ingress-class", "",
-			`Name of the ingress class this controller satisfies.
-The class of an Ingress object is set using the field IngressClassName in Kubernetes clusters version v1.18.0 or higher or the annotation "kubernetes.io/ingress.class" (deprecated).
-If this parameter is not set, or set to the default value of "nginx", it will handle ingresses with either an empty or "nginx" class name.`)
+		ingressClassAnnotation = flags.String("ingress-class", ingressclass.DefaultAnnotationValue,
+			`[IN DEPRECATION] Name of the ingress class this controller satisfies.
+The class of an Ingress object is set using the annotation "kubernetes.io/ingress.class" (deprecated).
+The parameter --controller-class has precedence over this.`)
+
+		ingressClassController = flags.String("controller-class", ingressclass.DefaultControllerName,
+			`Ingress Class Controller value this Ingress satisfies.
+The class of an Ingress object is set using the field IngressClassName in Kubernetes clusters version v1.19.0 or higher. The .spec.controller value of the IngressClass 
+referenced in an Ingress Object should be the same value specified here to make this object be watched.`)
+
+		watchWithoutClass = flags.Bool("watch-ingress-without-class", false,
+			`Define if Ingress Controller should also watch for Ingresses without an IngressClass or the annotation specified`)
 
 		configMap = flags.String("configmap", "",
 			`Name of the ConfigMap containing custom global configurations for the controller.`)
@@ -207,18 +215,6 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
 		status.UpdateInterval = *statusUpdateInterval
 	}
 
-	if *ingressClass != "" {
-		klog.InfoS("Watching for Ingress", "class", *ingressClass)
-
-		if *ingressClass != class.DefaultClass {
-			klog.Warningf("Only Ingresses with class %q will be processed by this Ingress controller", *ingressClass)
-		} else {
-			klog.Warning("Ingresses with an empty class will also be processed by this Ingress controller")
-		}
-
-		class.IngressClass = *ingressClass
-	}
-
 	parser.AnnotationsPrefix = *annotationsPrefix
 
 	// check port collisions
@@ -297,6 +293,11 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
 			HTTPS:    *httpsPort,
 			SSLProxy: *sslProxyPort,
 		},
+		IngressClassConfiguration: &ingressclass.IngressClassConfiguration{
+			Controller:        *ingressClassController,
+			AnnotationValue:   *ingressClassAnnotation,
+			WatchWithoutClass: *watchWithoutClass,
+		},
 		DisableCatchAll:           *disableCatchAll,
 		ValidationWebhook:         *validationWebhook,
 		ValidationWebhookCertPath: *validationWebhookCert,
diff --git a/cmd/nginx/main.go b/cmd/nginx/main.go
index 9c245baa12..b21e1012ef 100644
--- a/cmd/nginx/main.go
+++ b/cmd/nginx/main.go
@@ -43,7 +43,6 @@ import (
 	"k8s.io/klog/v2"
 
 	"k8s.io/ingress-nginx/internal/file"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/controller"
 	"k8s.io/ingress-nginx/internal/ingress/metric"
 	"k8s.io/ingress-nginx/internal/k8s"
@@ -104,35 +103,16 @@ func main() {
 	conf.FakeCertificate = ssl.GetFakeSSLCert()
 	klog.InfoS("SSL fake certificate created", "file", conf.FakeCertificate.PemFileName)
 
-	var isNetworkingIngressAvailable bool
-
-	isNetworkingIngressAvailable, k8s.IsIngressV1Beta1Ready, _ = k8s.NetworkingIngressAvailable(kubeClient)
-	if !isNetworkingIngressAvailable {
-		klog.Fatalf("ingress-nginx requires Kubernetes v1.14.0 or higher")
+	if !k8s.NetworkingIngressAvailable(kubeClient) {
+		klog.Fatalf("ingress-nginx requires Kubernetes v1.19.0 or higher")
 	}
 
-	if k8s.IsIngressV1Beta1Ready {
-		klog.InfoS("Enabling new Ingress features available since Kubernetes v1.18")
-		k8s.IngressClass, err = kubeClient.NetworkingV1beta1().IngressClasses().
-			Get(context.TODO(), class.IngressClass, metav1.GetOptions{})
-		if err != nil {
-			if !errors.IsNotFound(err) {
-				if !errors.IsUnauthorized(err) && !errors.IsForbidden(err) {
-					klog.Fatalf("Error searching IngressClass: %v", err)
-				}
-
-				klog.ErrorS(err, "Searching IngressClass", "class", class.IngressClass)
+	_, err = kubeClient.NetworkingV1().IngressClasses().List(context.TODO(), metav1.ListOptions{})
+	if err != nil {
+		if !errors.IsNotFound(err) {
+			if errors.IsUnauthorized(err) || !errors.IsForbidden(err) {
+				klog.Fatalf("Error searching IngressClass: Please verify your RBAC and allow Ingress Controller to list and get Ingress Classes: %v", err)
 			}
-
-			klog.Warningf("No IngressClass resource with name %v found. Only annotation will be used.", class.IngressClass)
-
-			// TODO: remove once this is fixed in client-go
-			k8s.IngressClass = nil
-		}
-
-		if k8s.IngressClass != nil && k8s.IngressClass.Spec.Controller != k8s.IngressNGINXController {
-			klog.Errorf(`Invalid IngressClass (Spec.Controller) value "%v". Should be "%v"`, k8s.IngressClass.Spec.Controller, k8s.IngressNGINXController)
-			klog.Fatalf("IngressClass with name %v is not valid for ingress-nginx (invalid Spec.Controller)", class.IngressClass)
 		}
 	}
 
@@ -153,7 +133,7 @@ func main() {
 
 	mc := metric.NewDummyCollector()
 	if conf.EnableMetrics {
-		mc, err = metric.NewCollector(conf.MetricsPerHost, reg)
+		mc, err = metric.NewCollector(conf.MetricsPerHost, reg, conf.IngressClassConfiguration.Controller)
 		if err != nil {
 			klog.Fatalf("Error creating prometheus collector:  %v", err)
 		}
diff --git a/cmd/plugin/commands/ingresses/ingresses.go b/cmd/plugin/commands/ingresses/ingresses.go
index 38da629302..dff9671038 100644
--- a/cmd/plugin/commands/ingresses/ingresses.go
+++ b/cmd/plugin/commands/ingresses/ingresses.go
@@ -22,7 +22,8 @@ import (
 	"text/tabwriter"
 
 	"github.com/spf13/cobra"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 
 	"k8s.io/ingress-nginx/cmd/plugin/request"
@@ -157,9 +158,10 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
 
 		defaultBackendService := ""
 		defaultBackendPort := ""
-		if ing.Spec.Backend != nil {
-			defaultBackendService = ing.Spec.Backend.ServiceName
-			defaultBackendPort = ing.Spec.Backend.ServicePort.String()
+		if ing.Spec.DefaultBackend != nil {
+			name, port := serviceToNameAndPort(ing.Spec.DefaultBackend.Service)
+			defaultBackendService = name
+			defaultBackendPort = port.String()
 		}
 
 		// Handle catch-all ingress
@@ -197,14 +199,15 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
 			}
 
 			for _, path := range rule.HTTP.Paths {
+				svcName, svcPort := serviceToNameAndPort(path.Backend.Service)
 				row := ingressRow{
 					Namespace:   ing.Namespace,
 					IngressName: ing.Name,
 					Host:        rule.Host,
 					Path:        path.Path,
 					TLS:         hasTLS,
-					ServiceName: path.Backend.ServiceName,
-					ServicePort: path.Backend.ServicePort.String(),
+					ServiceName: svcName,
+					ServicePort: svcPort.String(),
 					Address:     address,
 				}
 
@@ -215,3 +218,17 @@ func getIngressRows(ingresses *[]networking.Ingress) []ingressRow {
 
 	return rows
 }
+
+func serviceToNameAndPort(svc *networking.IngressServiceBackend) (string, intstr.IntOrString) {
+	var svcName string
+	if svc != nil {
+		svcName = svc.Name
+		if svc.Port.Number > 0 {
+			return svcName, intstr.FromInt(int(svc.Port.Number))
+		}
+		if svc.Port.Name != "" {
+			return svcName, intstr.FromString(svc.Port.Name)
+		}
+	}
+	return "", intstr.IntOrString{}
+}
diff --git a/cmd/plugin/commands/ingresses/ingresses_test.go b/cmd/plugin/commands/ingresses/ingresses_test.go
new file mode 100644
index 0000000000..6a8d8837ff
--- /dev/null
+++ b/cmd/plugin/commands/ingresses/ingresses_test.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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 ingresses
+
+import (
+	"testing"
+
+	networking "k8s.io/api/networking/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
+)
+
+func TestGetIngressInformation(t *testing.T) {
+
+	testcases := map[string]struct {
+		ServiceBackend *networking.IngressServiceBackend
+		wantName       string
+		wantPort       intstr.IntOrString
+	}{
+		"empty ingressServiceBackend": {
+			ServiceBackend: &networking.IngressServiceBackend{},
+			wantName:       "",
+			wantPort:       intstr.IntOrString{},
+		},
+		"ingressServiceBackend with port 8080": {
+			ServiceBackend: &networking.IngressServiceBackend{
+				Name: "test",
+				Port: networking.ServiceBackendPort{
+					Number: 8080,
+				},
+			},
+			wantName: "test",
+			wantPort: intstr.IntOrString{
+				Type:   intstr.Int,
+				IntVal: 8080,
+			},
+		},
+		"ingressServiceBackend with port name a-svc": {
+			ServiceBackend: &networking.IngressServiceBackend{
+				Name: "test",
+				Port: networking.ServiceBackendPort{
+					Name: "a-svc",
+				},
+			},
+			wantName: "test",
+			wantPort: intstr.IntOrString{
+				Type:   intstr.String,
+				StrVal: "a-svc",
+			},
+		},
+	}
+
+	for title, testCase := range testcases {
+		gotName, gotPort := serviceToNameAndPort(testCase.ServiceBackend)
+		if gotName != testCase.wantName {
+			t.Fatalf("%s: expected '%v' but returned %v", title, testCase.wantName, gotName)
+		}
+		if gotPort != testCase.wantPort {
+			t.Fatalf("%s: expected '%v' but returned %v", title, testCase.wantPort, gotPort)
+		}
+	}
+}
diff --git a/cmd/plugin/commands/lint/main.go b/cmd/plugin/commands/lint/main.go
index d120e93114..2daf8eb870 100644
--- a/cmd/plugin/commands/lint/main.go
+++ b/cmd/plugin/commands/lint/main.go
@@ -22,7 +22,7 @@ import (
 	"github.com/spf13/cobra"
 
 	appsv1 "k8s.io/api/apps/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	kmeta "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 
diff --git a/cmd/plugin/lints/ingress.go b/cmd/plugin/lints/ingress.go
index 0de4661f4e..ea08bfd8bc 100644
--- a/cmd/plugin/lints/ingress.go
+++ b/cmd/plugin/lints/ingress.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	kmeta "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/cmd/plugin/util"
 )
diff --git a/cmd/plugin/request/request.go b/cmd/plugin/request/request.go
index b8bc4eaae5..cae90e9d2d 100644
--- a/cmd/plugin/request/request.go
+++ b/cmd/plugin/request/request.go
@@ -22,12 +22,12 @@ import (
 
 	appsv1 "k8s.io/api/apps/v1"
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 	appsv1client "k8s.io/client-go/kubernetes/typed/apps/v1"
 	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
-	typednetworking "k8s.io/client-go/kubernetes/typed/networking/v1beta1"
+	typednetworking "k8s.io/client-go/kubernetes/typed/networking/v1"
 
 	"k8s.io/ingress-nginx/cmd/plugin/util"
 )
diff --git a/deploy/static/provider/aws/deploy-tls-termination.yaml b/deploy/static/provider/aws/deploy-tls-termination.yaml
index 2d4ad3ab77..99b4de04df 100644
--- a/deploy/static/provider/aws/deploy-tls-termination.yaml
+++ b/deploy/static/provider/aws/deploy-tls-termination.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,16 +28,16 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
   namespace: ingress-nginx
 data:
-  http-snippet: |
+  http-snippet:|
     server{
       listen 2443;
       return 308 https://$host$request_uri;
@@ -50,10 +50,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -83,8 +83,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -99,14 +98,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -119,10 +117,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -139,10 +137,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -174,8 +172,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -183,14 +180,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -202,7 +198,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -225,10 +221,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -247,10 +243,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -278,10 +274,10 @@ metadata:
     service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
     service.beta.kubernetes.io/aws-load-balancer-type: elb
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -308,10 +304,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -334,7 +330,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -345,7 +341,7 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -419,6 +415,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -426,10 +440,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -440,7 +454,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -450,12 +464,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -467,10 +480,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -483,10 +496,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -507,10 +520,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -532,10 +545,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -557,10 +570,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -582,10 +595,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -593,16 +606,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -632,10 +645,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -643,16 +656,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/aws/deploy.yaml b/deploy/static/provider/aws/deploy.yaml
index acd8fd604d..a9a528a4a0 100644
--- a/deploy/static/provider/aws/deploy.yaml
+++ b/deploy/static/provider/aws/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -43,10 +43,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -76,8 +76,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -92,14 +91,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -112,10 +110,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -132,10 +130,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -167,8 +165,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -176,14 +173,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -195,7 +191,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -218,10 +214,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -240,10 +236,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -268,10 +264,10 @@ metadata:
     service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true'
     service.beta.kubernetes.io/aws-load-balancer-type: nlb
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -298,10 +294,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -324,7 +320,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -335,7 +331,7 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -406,6 +402,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -413,10 +427,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -427,7 +441,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -437,12 +451,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -454,10 +467,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -470,10 +483,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -494,10 +507,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -519,10 +532,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -544,10 +557,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -569,10 +582,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -580,16 +593,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -619,10 +632,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -630,16 +643,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/baremetal/deploy.yaml b/deploy/static/provider/baremetal/deploy.yaml
index 55c2dc5ae5..12d990353d 100644
--- a/deploy/static/provider/baremetal/deploy.yaml
+++ b/deploy/static/provider/baremetal/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -43,10 +43,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -76,8 +76,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -92,14 +91,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -112,10 +110,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -132,10 +130,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -167,8 +165,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -176,14 +173,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -195,7 +191,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -218,10 +214,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -240,10 +236,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -265,10 +261,10 @@ kind: Service
 metadata:
   annotations:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -294,10 +290,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -320,7 +316,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -330,7 +326,7 @@ spec:
           args:
             - /nginx-ingress-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -401,6 +397,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -408,10 +422,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -422,7 +436,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -432,12 +446,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -449,10 +462,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -465,10 +478,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -489,10 +502,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -514,10 +527,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -539,10 +552,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -564,10 +577,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -575,16 +588,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -614,10 +627,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -625,16 +638,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/cloud/deploy.yaml b/deploy/static/provider/cloud/deploy.yaml
index be69bee733..80e89b1650 100644
--- a/deploy/static/provider/cloud/deploy.yaml
+++ b/deploy/static/provider/cloud/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -43,10 +43,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -76,8 +76,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -92,14 +91,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -112,10 +110,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -132,10 +130,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -167,8 +165,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -176,14 +173,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -195,7 +191,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -218,10 +214,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -240,10 +236,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -265,10 +261,10 @@ kind: Service
 metadata:
   annotations:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -295,10 +291,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -321,7 +317,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -332,7 +328,7 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -403,6 +399,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -410,10 +424,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -424,7 +438,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -434,12 +448,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -451,10 +464,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -467,10 +480,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -491,10 +504,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -516,10 +529,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -541,10 +554,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -566,10 +579,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -577,16 +590,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -616,10 +629,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -627,16 +640,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/do/deploy.yaml b/deploy/static/provider/do/deploy.yaml
index 95be9c1e4a..81c0fffdb8 100644
--- a/deploy/static/provider/do/deploy.yaml
+++ b/deploy/static/provider/do/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -44,10 +44,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -77,8 +77,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -93,14 +92,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -113,10 +111,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -133,10 +131,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -168,8 +166,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -177,14 +174,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -196,7 +192,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -219,10 +215,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -241,10 +237,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -267,10 +263,10 @@ metadata:
   annotations:
     service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: 'true'
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -297,10 +293,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -323,7 +319,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -334,7 +330,7 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -405,6 +401,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -412,10 +426,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -426,7 +440,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -436,12 +450,12 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
+    timeoutSeconds: 29
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -453,10 +467,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -469,10 +483,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -493,10 +507,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -518,10 +532,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -543,10 +557,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -568,10 +582,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -579,16 +593,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -618,10 +632,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -629,16 +643,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/exoscale/deploy.yaml b/deploy/static/provider/exoscale/deploy.yaml
index 47b86b9b06..7603d947ff 100644
--- a/deploy/static/provider/exoscale/deploy.yaml
+++ b/deploy/static/provider/exoscale/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -43,10 +43,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -76,8 +76,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -92,14 +91,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -112,10 +110,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -132,10 +130,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -167,8 +165,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -176,14 +173,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -195,7 +191,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -218,10 +214,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -240,10 +236,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -273,10 +269,10 @@ metadata:
     service.beta.kubernetes.io/exoscale-loadbalancer-service-healthcheck-timeout: 3s
     service.beta.kubernetes.io/exoscale-loadbalancer-service-strategy: source-hash
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -303,10 +299,10 @@ apiVersion: apps/v1
 kind: DaemonSet
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -329,7 +325,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -340,8 +336,8 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
-            - --configmap=ingress-nginx/ingress-nginx-controller
+            - --controller-class=k8s.io/ingress-nginx
+            - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
             - --validating-webhook-key=/usr/local/certificates/key
@@ -411,6 +407,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -418,10 +432,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -432,7 +446,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -442,12 +456,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -459,10 +472,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -475,10 +488,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -499,10 +512,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -524,10 +537,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -549,10 +562,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -574,10 +587,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -585,16 +598,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -624,10 +637,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -635,16 +648,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/kind/deploy.yaml b/deploy/static/provider/kind/deploy.yaml
index c53e2ae1b8..f5ed6a2174 100644
--- a/deploy/static/provider/kind/deploy.yaml
+++ b/deploy/static/provider/kind/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -43,10 +43,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -76,8 +76,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -92,14 +91,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -112,10 +110,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -132,10 +130,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -167,8 +165,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -176,14 +173,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -195,7 +191,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -218,10 +214,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -240,10 +236,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -265,10 +261,10 @@ kind: Service
 metadata:
   annotations:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -294,10 +290,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -324,7 +320,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -334,7 +330,7 @@ spec:
           args:
             - /nginx-ingress-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -413,6 +409,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -420,10 +434,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -434,7 +448,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -444,12 +458,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -461,10 +474,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -477,10 +490,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -501,10 +514,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -526,10 +539,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -551,10 +564,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -576,10 +589,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -587,16 +600,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -626,10 +639,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -637,16 +650,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/deploy/static/provider/scw/deploy.yaml b/deploy/static/provider/scw/deploy.yaml
index 2fd0154d5a..2dce4a583e 100644
--- a/deploy/static/provider/scw/deploy.yaml
+++ b/deploy/static/provider/scw/deploy.yaml
@@ -13,10 +13,10 @@ apiVersion: v1
 kind: ServiceAccount
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -28,10 +28,10 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -44,10 +44,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 rules:
@@ -77,8 +77,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -93,14 +92,13 @@ rules:
       - create
       - patch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -113,10 +111,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
   name: ingress-nginx
 roleRef:
@@ -133,10 +131,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -168,8 +166,7 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses
     verbs:
@@ -177,14 +174,13 @@ rules:
       - list
       - watch
   - apiGroups:
-      - extensions
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingresses/status
     verbs:
       - update
   - apiGroups:
-      - networking.k8s.io   # k8s 1.14+
+      - networking.k8s.io
     resources:
       - ingressclasses
     verbs:
@@ -196,7 +192,7 @@ rules:
     resources:
       - configmaps
     resourceNames:
-      - ingress-controller-leader-nginx
+      - ingress-controller-leader
     verbs:
       - get
       - update
@@ -219,10 +215,10 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx
@@ -241,10 +237,10 @@ apiVersion: v1
 kind: Service
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller-admission
@@ -267,10 +263,10 @@ metadata:
   annotations:
     service.beta.kubernetes.io/scw-loadbalancer-proxy-protocol-v2: 'true'
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -297,10 +293,10 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: controller
   name: ingress-nginx-controller
@@ -323,7 +319,7 @@ spec:
       dnsPolicy: ClusterFirst
       containers:
         - name: controller
-          image: k8s.gcr.io/ingress-nginx/controller:v0.49.0@sha256:e9707504ad0d4c119036b6d41ace4a33596139d3feb9ccb6617813ce48c3eeef
+          image: k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3@sha256:44a7a06b71187a4529b0a9edee5cc22bdf71b414470eff696c3869ea8d90a695
           imagePullPolicy: IfNotPresent
           lifecycle:
             preStop:
@@ -334,7 +330,7 @@ spec:
             - /nginx-ingress-controller
             - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
             - --election-id=ingress-controller-leader
-            - --ingress-class=nginx
+            - --controller-class=k8s.io/ingress-nginx
             - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
             - --validating-webhook=:8443
             - --validating-webhook-certificate=/usr/local/certificates/cert
@@ -405,6 +401,24 @@ spec:
           secret:
             secretName: ingress-nginx-admission
 ---
+# Source: ingress-nginx/templates/controller-ingressclass.yaml
+# We don't support namespaced ingressClass yet
+# So a ClusterRole and a ClusterRoleBinding is required
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
+    app.kubernetes.io/name: ingress-nginx
+    app.kubernetes.io/instance: ingress-nginx
+    app.kubernetes.io/version: 1.0.0-beta.3
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/component: controller
+  name: nginx
+  namespace: ingress-nginx
+spec:
+  controller: k8s.io/ingress-nginx
+---
 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
 # before changing this value, check the required kubernetes version
 # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
@@ -412,10 +426,10 @@ apiVersion: admissionregistration.k8s.io/v1
 kind: ValidatingWebhookConfiguration
 metadata:
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
   name: ingress-nginx-admission
@@ -426,7 +440,7 @@ webhooks:
       - apiGroups:
           - networking.k8s.io
         apiVersions:
-          - v1beta1
+          - v1
         operations:
           - CREATE
           - UPDATE
@@ -436,12 +450,11 @@ webhooks:
     sideEffects: None
     admissionReviewVersions:
       - v1
-      - v1beta1
     clientConfig:
       service:
         namespace: ingress-nginx
         name: ingress-nginx-controller-admission
-        path: /networking/v1beta1/ingresses
+        path: /networking/v1/ingresses
 ---
 # Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
 apiVersion: v1
@@ -453,10 +466,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 ---
@@ -469,10 +482,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -493,10 +506,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -518,10 +531,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 rules:
@@ -543,10 +556,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade,post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 roleRef:
@@ -568,10 +581,10 @@ metadata:
     helm.sh/hook: pre-install,pre-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -579,16 +592,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-create
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: create
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - create
@@ -618,10 +631,10 @@ metadata:
     helm.sh/hook: post-install,post-upgrade
     helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
   labels:
-    helm.sh/chart: ingress-nginx-3.36.0
+    helm.sh/chart: ingress-nginx-4.0.0-beta.3
     app.kubernetes.io/name: ingress-nginx
     app.kubernetes.io/instance: ingress-nginx
-    app.kubernetes.io/version: 0.49.0
+    app.kubernetes.io/version: 1.0.0-beta.3
     app.kubernetes.io/managed-by: Helm
     app.kubernetes.io/component: admission-webhook
 spec:
@@ -629,16 +642,16 @@ spec:
     metadata:
       name: ingress-nginx-admission-patch
       labels:
-        helm.sh/chart: ingress-nginx-3.36.0
+        helm.sh/chart: ingress-nginx-4.0.0-beta.3
         app.kubernetes.io/name: ingress-nginx
         app.kubernetes.io/instance: ingress-nginx
-        app.kubernetes.io/version: 0.49.0
+        app.kubernetes.io/version: 1.0.0-beta.3
         app.kubernetes.io/managed-by: Helm
         app.kubernetes.io/component: admission-webhook
     spec:
       containers:
         - name: patch
-          image: docker.io/jettech/kube-webhook-certgen:v1.5.1
+          image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0@sha256:f3b6b39a6062328c095337b4cadcefd1612348fdd5190b1dcbcb9b9e90bd8068
           imagePullPolicy: IfNotPresent
           args:
             - patch
diff --git a/docs/developer-guide/getting-started.md b/docs/developer-guide/getting-started.md
index f6a9fdbe0f..d63f6e6e8a 100644
--- a/docs/developer-guide/getting-started.md
+++ b/docs/developer-guide/getting-started.md
@@ -68,7 +68,7 @@ FOCUS="no-auth-locations" make kind-e2e-test
 
 Valid values are defined in the describe definition of the e2e tests like [Default Backend](https://github.com/kubernetes/ingress-nginx/blob/main/test/e2e/defaultbackend/default_backend.go#L29)
 
-The complete list of tests can be found [here](e2e-tests.md)
+The complete list of tests can be found [here](../e2e-tests.md)
 
 ### Custom docker image
 
diff --git a/docs/examples/affinity/cookie/ingress-samesite.yaml b/docs/examples/affinity/cookie/ingress-samesite.yaml
index 42d1c2e2df..b3f8f4b20c 100644
--- a/docs/examples/affinity/cookie/ingress-samesite.yaml
+++ b/docs/examples/affinity/cookie/ingress-samesite.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: cookie-samesite-none
@@ -19,7 +19,7 @@ spec:
           servicePort: 80
         path: /
 ---
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: cookie-samesite-strict
diff --git a/docs/examples/affinity/cookie/ingress.yaml b/docs/examples/affinity/cookie/ingress.yaml
index 57edbdbd3e..eac973fde2 100644
--- a/docs/examples/affinity/cookie/ingress.yaml
+++ b/docs/examples/affinity/cookie/ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: nginx-test
diff --git a/docs/examples/auth/basic/README.md b/docs/examples/auth/basic/README.md
index 194bacb3bf..a5fa579e00 100644
--- a/docs/examples/auth/basic/README.md
+++ b/docs/examples/auth/basic/README.md
@@ -30,7 +30,7 @@ type: Opaque
 
 ```console
 echo "
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: ingress-with-auth
diff --git a/docs/examples/auth/client-certs/ingress.yaml b/docs/examples/auth/client-certs/ingress.yaml
index cf5f701b2a..7172081b46 100644
--- a/docs/examples/auth/client-certs/ingress.yaml
+++ b/docs/examples/auth/client-certs/ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/auth/external-auth/README.md b/docs/examples/auth/external-auth/README.md
index a081383731..235cca9cbb 100644
--- a/docs/examples/auth/external-auth/README.md
+++ b/docs/examples/auth/external-auth/README.md
@@ -13,7 +13,7 @@ NAME            HOSTS                         ADDRESS       PORTS     AGE
 external-auth   external-auth-01.sample.com   172.17.4.99   80        13s
 
 $ kubectl get ing external-auth -o yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
@@ -23,7 +23,7 @@ metadata:
   name: external-auth
   namespace: default
   resourceVersion: "2068378"
-  selfLink: /apis/networking/v1beta1/namespaces/default/ingresses/external-auth
+  selfLink: /apis/networking/v1/namespaces/default/ingresses/external-auth
   uid: 5c388f1d-8970-11e6-9004-080027d2dc94
 spec:
   rules:
diff --git a/docs/examples/auth/external-auth/ingress.yaml b/docs/examples/auth/external-auth/ingress.yaml
index c7a87a240f..2a58ca2e30 100644
--- a/docs/examples/auth/external-auth/ingress.yaml
+++ b/docs/examples/auth/external-auth/ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/auth/oauth-external-auth/dashboard-ingress.yaml b/docs/examples/auth/oauth-external-auth/dashboard-ingress.yaml
index ade56a9e63..725bf1dc5e 100644
--- a/docs/examples/auth/oauth-external-auth/dashboard-ingress.yaml
+++ b/docs/examples/auth/oauth-external-auth/dashboard-ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
@@ -18,7 +18,7 @@ spec:
 
 ---
 
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: oauth2-proxy
diff --git a/docs/examples/chashsubset/deployment.yaml b/docs/examples/chashsubset/deployment.yaml
index 9b1bafcb17..82fdc7ac00 100644
--- a/docs/examples/chashsubset/deployment.yaml
+++ b/docs/examples/chashsubset/deployment.yaml
@@ -54,7 +54,7 @@ spec:
       targetPort: 8080
 
 ---
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/customization/configuration-snippets/ingress.yaml b/docs/examples/customization/configuration-snippets/ingress.yaml
index 07af3552f9..70d9042c7d 100644
--- a/docs/examples/customization/configuration-snippets/ingress.yaml
+++ b/docs/examples/customization/configuration-snippets/ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: nginx-configuration-snippet
diff --git a/docs/examples/customization/external-auth-headers/deploy/echo-service.yaml b/docs/examples/customization/external-auth-headers/deploy/echo-service.yaml
index 1c3667c7c1..075421807b 100644
--- a/docs/examples/customization/external-auth-headers/deploy/echo-service.yaml
+++ b/docs/examples/customization/external-auth-headers/deploy/echo-service.yaml
@@ -43,7 +43,7 @@ spec:
   selector:
     k8s-app: demo-echo-service
 ---
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: public-demo-echo-service
@@ -61,7 +61,7 @@ spec:
           servicePort: 80
         path: /
 ---
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: secure-demo-echo-service
diff --git a/docs/examples/docker-registry/ingress-with-tls.yaml b/docs/examples/docker-registry/ingress-with-tls.yaml
index fc277b20f1..11ccf66277 100644
--- a/docs/examples/docker-registry/ingress-with-tls.yaml
+++ b/docs/examples/docker-registry/ingress-with-tls.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/docker-registry/ingress-without-tls.yaml b/docs/examples/docker-registry/ingress-without-tls.yaml
index 1ce1b98fb0..2d713cb8c2 100644
--- a/docs/examples/docker-registry/ingress-without-tls.yaml
+++ b/docs/examples/docker-registry/ingress-without-tls.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/multi-tls/multi-tls.yaml b/docs/examples/multi-tls/multi-tls.yaml
index 7dda9267e4..32f5932c1e 100644
--- a/docs/examples/multi-tls/multi-tls.yaml
+++ b/docs/examples/multi-tls/multi-tls.yaml
@@ -92,7 +92,7 @@ spec:
                 fieldPath: status.podIP
 
 ---
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: foo-tls
diff --git a/docs/examples/rewrite/README.md b/docs/examples/rewrite/README.md
index 3ad5e4fcdd..824b0966f4 100644
--- a/docs/examples/rewrite/README.md
+++ b/docs/examples/rewrite/README.md
@@ -34,7 +34,7 @@ Create an Ingress rule with a rewrite annotation:
 
 ```console
 $ echo '
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
@@ -66,7 +66,7 @@ For example, the ingress definition above will result in the following rewrites:
 Create an Ingress rule with an app-root annotation:
 ```
 $ echo "
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/examples/static-ip/nginx-ingress.yaml b/docs/examples/static-ip/nginx-ingress.yaml
index aa4877e56f..358942f5c5 100644
--- a/docs/examples/static-ip/nginx-ingress.yaml
+++ b/docs/examples/static-ip/nginx-ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: ingress-nginx
diff --git a/docs/examples/tls-termination/README.md b/docs/examples/tls-termination/README.md
index 1a17d6d218..f3096db2ee 100644
--- a/docs/examples/tls-termination/README.md
+++ b/docs/examples/tls-termination/README.md
@@ -11,7 +11,7 @@ You need a [TLS cert](../PREREQUISITES.md#tls-certificates) and a [test HTTP ser
 Create a `ingress.yaml` file.
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: nginx-test
diff --git a/docs/examples/tls-termination/ingress.yaml b/docs/examples/tls-termination/ingress.yaml
index fc97b3707e..2e989d1b03 100644
--- a/docs/examples/tls-termination/ingress.yaml
+++ b/docs/examples/tls-termination/ingress.yaml
@@ -1,4 +1,4 @@
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: nginx-test
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 67d111f5e9..6a29638d4b 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -32,7 +32,7 @@ Rules:
             /tea      tea-svc:80 (<none>)
             /coffee   coffee-svc:80 (<none>)
 Annotations:
-  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"cafe-ingress","namespace":"default","selfLink":"/apis/networking/v1beta1/namespaces/default/ingresses/cafe-ingress"},"spec":{"rules":[{"host":"cafe.com","http":{"paths":[{"backend":{"serviceName":"tea-svc","servicePort":80},"path":"/tea"},{"backend":{"serviceName":"coffee-svc","servicePort":80},"path":"/coffee"}]}}]},"status":{"loadBalancer":{"ingress":[{"ip":"169.48.142.110"}]}}}
+  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{},"name":"cafe-ingress","namespace":"default","selfLink":"/apis/networking/v1/namespaces/default/ingresses/cafe-ingress"},"spec":{"rules":[{"host":"cafe.com","http":{"paths":[{"backend":{"serviceName":"tea-svc","servicePort":80},"path":"/tea"},{"backend":{"serviceName":"coffee-svc","servicePort":80},"path":"/coffee"}]}}]},"status":{"loadBalancer":{"ingress":[{"ip":"169.48.142.110"}]}}}
 
 Events:
   Type    Reason  Age   From                      Message
diff --git a/docs/user-guide/fcgi-services.md b/docs/user-guide/fcgi-services.md
index 7c9dd6138b..62271c2cef 100644
--- a/docs/user-guide/fcgi-services.md
+++ b/docs/user-guide/fcgi-services.md
@@ -60,7 +60,7 @@ data:
 
 ---
 
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/user-guide/ingress-path-matching.md b/docs/user-guide/ingress-path-matching.md
index 092cf9264f..6812e2cb5d 100644
--- a/docs/user-guide/ingress-path-matching.md
+++ b/docs/user-guide/ingress-path-matching.md
@@ -15,7 +15,7 @@ This can be enabled by setting the `nginx.ingress.kubernetes.io/use-regex` annot
 See the [description](./nginx-configuration/annotations.md#use-regex) of the `use-regex` annotation for more details.
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: test-ingress
@@ -51,7 +51,7 @@ In NGINX, regular expressions follow a **first match** policy. In order to enabl
 Let the following two ingress definitions be created:
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: test-ingress-1
@@ -71,7 +71,7 @@ spec:
 ```
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: test-ingress-2
@@ -125,7 +125,7 @@ This case is expected and a result of NGINX's a first match policy for paths tha
 Let the following ingress be defined:
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: test-ingress-3
diff --git a/docs/user-guide/nginx-configuration/annotations.md b/docs/user-guide/nginx-configuration/annotations.md
index ef9a4e5ef5..c6d3767025 100755
--- a/docs/user-guide/nginx-configuration/annotations.md
+++ b/docs/user-guide/nginx-configuration/annotations.md
@@ -394,7 +394,7 @@ For more information please see [the `server_name` documentation](http://nginx.o
 Using the annotation `nginx.ingress.kubernetes.io/server-snippet` it is possible to add custom configuration in the server configuration block.
 
 ```yaml
-apiVersion: networking.k8s.io/v1beta1
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
diff --git a/docs/user-guide/nginx-configuration/configmap.md b/docs/user-guide/nginx-configuration/configmap.md
index 850354105d..575a51afc4 100755
--- a/docs/user-guide/nginx-configuration/configmap.md
+++ b/docs/user-guide/nginx-configuration/configmap.md
@@ -54,7 +54,7 @@ The following table shows a configuration option's name, type, and the default v
 |[http2-max-field-size](#http2-max-field-size)|string|"4k"|
 |[http2-max-header-size](#http2-max-header-size)|string|"16k"|
 |[http2-max-requests](#http2-max-requests)|int|1000|
-|[http2-max-concurrent-streams](#http2-max-concurrent-streams)|int|1000|
+|[http2-max-concurrent-streams](#http2-max-concurrent-streams)|int|128|
 |[hsts](#hsts)|bool|"true"|
 |[hsts-include-subdomains](#hsts-include-subdomains)|bool|"true"|
 |[hsts-max-age](#hsts-max-age)|string|"15724800"|
@@ -178,6 +178,9 @@ The following table shows a configuration option's name, type, and the default v
 |[proxy-buffering](#proxy-buffering)|string|"off"|
 |[limit-req-status-code](#limit-req-status-code)|int|503|
 |[limit-conn-status-code](#limit-conn-status-code)|int|503|
+|[enable-syslog](#enable-syslog)|bool|false|
+|[syslog-host](#syslog-host)|string|""|
+|[syslog-port](#syslog-port)|int|514|
 |[no-tls-redirect-locations](#no-tls-redirect-locations)|string|"/.well-known/acme-challenge"|
 |[global-auth-url](#global-auth-url)|string|""|
 |[global-auth-method](#global-auth-method)|string|""|
@@ -451,7 +454,7 @@ _**default:**_ 16384
 ## max-worker-open-files
 
 Sets the [maximum number of files](http://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile) that can be opened by each worker process.
-The default of 0 means "max open files (system's limit) / [worker-processes](#worker-processes) - 1024".
+The default of 0 means "max open files (system's limit) - 1024".
 _**default:**_ 0
 
 ## map-hash-bucket-size
@@ -1077,6 +1080,18 @@ Sets the [status code to return in response to rejected requests](http://nginx.o
 
 Sets the [status code to return in response to rejected connections](http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_conn_status). _**default:**_ 503
 
+## enable-syslog
+
+Enable [syslog](http://nginx.org/en/docs/syslog.html) feature for access log and error log. _**default:**_ false
+
+## syslog-host
+
+Sets the address of syslog server. The address can be specified as a domain name or IP address.
+
+## syslog-port
+
+Sets the port of syslog server. _**default:**_ 514
+
 ## no-tls-redirect-locations
 
 A comma-separated list of locations on which http requests will never get redirected to their https counterpart.
diff --git a/docs/user-guide/third-party-addons/opentracing.md b/docs/user-guide/third-party-addons/opentracing.md
index 3bef8332c7..916b296373 100644
--- a/docs/user-guide/third-party-addons/opentracing.md
+++ b/docs/user-guide/third-party-addons/opentracing.md
@@ -168,7 +168,7 @@ In the Zipkin interface we can see the details:
 
     # Apply the Ingress Resource
     $ echo '
-      apiVersion: networking.k8s.io/v1beta1
+      apiVersion: networking.k8s.io/v1
       kind: Ingress
       metadata:
         name: echo-ingress
diff --git a/go.mod b/go.mod
index c0e2b350b3..302b451a68 100644
--- a/go.mod
+++ b/go.mod
@@ -41,7 +41,7 @@ require (
 	k8s.io/code-generator v0.21.3
 	k8s.io/component-base v0.21.3
 	k8s.io/klog/v2 v2.10.0
-	k8s.io/utils v0.0.0-20210802155522-efc7438f0176
+	k8s.io/utils v0.0.0-20210802155522-efc7438f0176 // indirect
 	pault.ag/go/sniff v0.0.0-20200207005214-cf7e4d167732
 	sigs.k8s.io/controller-runtime v0.9.5
 	sigs.k8s.io/mdtoc v1.0.1
diff --git a/hack/generate-deploy-scripts.sh b/hack/generate-deploy-scripts.sh
index e20596c1dd..a4872c6d80 100755
--- a/hack/generate-deploy-scripts.sh
+++ b/hack/generate-deploy-scripts.sh
@@ -163,6 +163,8 @@ controller:
       service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true"
   config:
     use-proxy-protocol: "true"
+  admissionWebhooks:
+    timeoutSeconds: 29
 
 EOF
 
diff --git a/images/nginx/rootfs/build.sh b/images/nginx/rootfs/build.sh
index 42add23b54..46f304ea53 100755
--- a/images/nginx/rootfs/build.sh
+++ b/images/nginx/rootfs/build.sh
@@ -131,6 +131,13 @@ export BUILD_PATH=/tmp/build
 
 ARCH=$(uname -m)
 
+if [[ ${ARCH} == "s390x" ]]; then
+  export LUAJIT_VERSION=9d5750d28478abfdcaefdfdc408f87752a21e431
+  export LUA_RESTY_CORE=0.1.17
+  export LUA_NGX_VERSION=0.10.15
+  export LUA_STREAM_NGX_VERSION=0.0.7
+fi
+
 get_src()
 {
   hash="$1"
@@ -229,17 +236,30 @@ get_src 3a3a03060bf5e3fef52c9a2de02e6035cb557f389453d8f3b0c1d3d570636994 \
 get_src 754c3ace499a63e45b77ef4bcab4ee602c2c414f58403bce826b76ffc2f77d0b \
         "https://github.com/msgpack/msgpack-c/archive/cpp-$MSGPACK_VERSION.tar.gz"
 
+if [[ ${ARCH} == "s390x" ]]; then
+get_src 7d5f3439c8df56046d0564b5857fd8a30296ab1bd6df0f048aed7afb56a0a4c2 \
+        "https://github.com/openresty/lua-nginx-module/archive/v$LUA_NGX_VERSION.tar.gz"
+get_src 99c47c75c159795c9faf76bbb9fa58e5a50b75286c86565ffcec8514b1c74bf9 \
+        "https://github.com/openresty/stream-lua-nginx-module/archive/v$LUA_STREAM_NGX_VERSION.tar.gz"
+else
 get_src 085a9fb2bf9c4466977595a5fe5156d76f3a2d9a2a81be3cacaff2021773393e \
         "https://github.com/openresty/lua-nginx-module/archive/$LUA_NGX_VERSION.tar.gz"
 
 get_src ba38c9f8e4265836ba7f2ac559ddf140693ff2f5ae33ab1e384f51f3992151ab \
         "https://github.com/openresty/stream-lua-nginx-module/archive/$LUA_STREAM_NGX_VERSION.tar.gz"
 
+fi
+
 get_src a92c9ee6682567605ece55d4eed5d1d54446ba6fba748cff0a2482aea5713d5f \
         "https://github.com/openresty/lua-upstream-nginx-module/archive/$LUA_UPSTREAM_VERSION.tar.gz"
 
+if [[ ${ARCH} == "s390x" ]]; then
+get_src 266ed1abb70a9806d97cb958537a44b67db6afb33d3b32292a2d68a2acedea75 \
+        "https://github.com/openresty/luajit2/archive/$LUAJIT_VERSION.tar.gz"
+else
 get_src 1ee6dad809a5bb22efb45e6dac767f7ce544ad652d353a93d7f26b605f69fe3f \
         "https://github.com/openresty/luajit2/archive/v$LUAJIT_VERSION.tar.gz"
+fi
 
 get_src f29393f2cd9288105a0029a6a324fe1f7558a9e7e852d59a6355f7581bb90e30 \
         "https://github.com/DataDog/dd-opentracing-cpp/archive/$DATADOG_CPP_VERSION.tar.gz"
@@ -262,8 +282,13 @@ get_src 462c6b38792bab4ca8212bdfd3f2e38f6883bb45c8fb8a03474ea813e0fab853 \
 get_src b3d28adac2acee1e5904e9f65d6e80e0553b01647fa0701b812bc7e464de74ad \
         "https://github.com/openresty/lua-resty-balancer/archive/$LUA_RESTY_BALANCER.tar.gz"
 
+if [[ ${ARCH} == "s390x" ]]; then
+get_src 8f5f76d2689a3f6b0782f0a009c56a65e4c7a4382be86422c9b3549fe95b0dc4 \
+        "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
+else
 get_src 4d971f711fad48c097070457c128ca36053835d8a3ba25a937e9991547d55d4d \
         "https://github.com/openresty/lua-resty-core/archive/v$LUA_RESTY_CORE.tar.gz"
+fi
 
 get_src 8d602af2669fb386931760916a39f6c9034f2363c4965f215042c086b8215238 \
         "https://github.com/openresty/lua-cjson/archive/$LUA_CJSON_VERSION.tar.gz"
diff --git a/internal/admission/controller/convert.go b/internal/admission/controller/convert.go
deleted file mode 100644
index 004e5d057f..0000000000
--- a/internal/admission/controller/convert.go
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-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 controller
-
-import (
-	"unsafe"
-
-	admissionv1 "k8s.io/api/admission/v1"
-	admissionv1beta1 "k8s.io/api/admission/v1beta1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/types"
-)
-
-// these conversions are copied from https://github.com/kubernetes/kubernetes/blob/4db3a096ce8ac730b2280494422e1c4cf5fe875e/pkg/apis/admission/v1beta1/zz_generated.conversion.go
-// to avoid copying in kubernetes/kubernetes
-// they are sightly modified to remove complexity
-
-func convertV1beta1AdmissionReviewToAdmissionAdmissionReview(in *admissionv1beta1.AdmissionReview, out *admissionv1.AdmissionReview) {
-	if in.Request != nil {
-		if out.Request == nil {
-			out.Request = &admissionv1.AdmissionRequest{}
-		}
-		in, out := &in.Request, &out.Request
-		*out = new(admissionv1.AdmissionRequest)
-		convertV1beta1AdmissionRequestToAdmissionAdmissionRequest(*in, *out)
-	} else {
-		out.Request = nil
-	}
-	out.Response = (*admissionv1.AdmissionResponse)(unsafe.Pointer(in.Response)) // #nosec
-}
-
-func convertV1beta1AdmissionRequestToAdmissionAdmissionRequest(in *admissionv1beta1.AdmissionRequest, out *admissionv1.AdmissionRequest) {
-	out.UID = types.UID(in.UID)
-	out.Kind = in.Kind
-	out.Resource = in.Resource
-	out.SubResource = in.SubResource
-	out.RequestKind = (*metav1.GroupVersionKind)(unsafe.Pointer(in.RequestKind))             // #nosec
-	out.RequestResource = (*metav1.GroupVersionResource)(unsafe.Pointer(in.RequestResource)) // #nosec
-	out.RequestSubResource = in.RequestSubResource
-	out.Name = in.Name
-	out.Namespace = in.Namespace
-	out.Operation = admissionv1.Operation(in.Operation)
-	out.Object = in.Object
-	out.OldObject = in.OldObject
-	out.Options = in.Options
-}
-
-func convertAdmissionAdmissionReviewToV1beta1AdmissionReview(in *admissionv1.AdmissionReview, out *admissionv1beta1.AdmissionReview) {
-	if in.Request != nil {
-		if out.Request == nil {
-			out.Request = &admissionv1beta1.AdmissionRequest{}
-		}
-		in, out := &in.Request, &out.Request
-		*out = new(admissionv1beta1.AdmissionRequest)
-		convertAdmissionAdmissionRequestToV1beta1AdmissionRequest(*in, *out)
-	} else {
-		out.Request = nil
-	}
-	out.Response = (*admissionv1beta1.AdmissionResponse)(unsafe.Pointer(in.Response)) // #nosec
-}
-
-func convertAdmissionAdmissionRequestToV1beta1AdmissionRequest(in *admissionv1.AdmissionRequest, out *admissionv1beta1.AdmissionRequest) {
-	out.UID = types.UID(in.UID)
-	out.Kind = in.Kind
-	out.Resource = in.Resource
-	out.SubResource = in.SubResource
-	out.RequestKind = (*metav1.GroupVersionKind)(unsafe.Pointer(in.RequestKind))             // #nosec
-	out.RequestResource = (*metav1.GroupVersionResource)(unsafe.Pointer(in.RequestResource)) // #nosec
-	out.RequestSubResource = in.RequestSubResource
-	out.Name = in.Name
-	out.Namespace = in.Namespace
-	out.Operation = admissionv1beta1.Operation(in.Operation)
-	out.Object = in.Object
-	out.OldObject = in.OldObject
-	out.Options = in.Options
-}
diff --git a/internal/admission/controller/main.go b/internal/admission/controller/main.go
index 3781c80d77..8645756fd8 100644
--- a/internal/admission/controller/main.go
+++ b/internal/admission/controller/main.go
@@ -21,12 +21,10 @@ import (
 	"net/http"
 
 	admissionv1 "k8s.io/api/admission/v1"
-	admissionv1beta1 "k8s.io/api/admission/v1beta1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	apiequality "k8s.io/apimachinery/pkg/api/equality"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/apimachinery/pkg/runtime/serializer/json"
 	"k8s.io/klog/v2"
 )
@@ -46,7 +44,7 @@ type IngressAdmission struct {
 var (
 	ingressResource = metav1.GroupVersionKind{
 		Group:   networking.GroupName,
-		Version: "v1beta1",
+		Version: "v1",
 		Kind:    "Ingress",
 	}
 )
@@ -55,19 +53,10 @@ var (
 // with Allowed=false if the Object is an ingress that would prevent nginx to reload the configuration
 // with Allowed=true otherwise
 func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object, error) {
-	outputVersion := admissionv1.SchemeGroupVersion
 
 	review, isV1 := obj.(*admissionv1.AdmissionReview)
-
 	if !isV1 {
-		outputVersion = admissionv1beta1.SchemeGroupVersion
-		reviewv1beta1, isv1beta1 := obj.(*admissionv1beta1.AdmissionReview)
-		if !isv1beta1 {
-			return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")
-		}
-
-		review = &admissionv1.AdmissionReview{}
-		convertV1beta1AdmissionReviewToAdmissionAdmissionReview(reviewv1beta1, review)
+		return nil, fmt.Errorf("request is not of type AdmissionReview v1 or v1beta1")
 	}
 
 	if !apiequality.Semantic.DeepEqual(review.Request.Kind, ingressResource) {
@@ -94,7 +83,7 @@ func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object,
 		}
 
 		review.Response = status
-		return convertResponse(review, outputVersion), nil
+		return review, nil
 	}
 
 	if err := ia.Checker.CheckIngress(&ingress); err != nil {
@@ -106,24 +95,12 @@ func (ia *IngressAdmission) HandleAdmission(obj runtime.Object) (runtime.Object,
 		}
 
 		review.Response = status
-		return convertResponse(review, outputVersion), nil
+		return review, nil
 	}
 
 	klog.InfoS("successfully validated configuration, accepting", "ingress", fmt.Sprintf("%v/%v", review.Request.Namespace, review.Request.Name))
 	status.Allowed = true
 	review.Response = status
 
-	return convertResponse(review, outputVersion), nil
-}
-
-func convertResponse(review *admissionv1.AdmissionReview, outputVersion schema.GroupVersion) runtime.Object {
-	// reply v1
-	if outputVersion.Version == admissionv1.SchemeGroupVersion.Version {
-		return review
-	}
-
-	// reply v1beta1
-	reviewv1beta1 := &admissionv1beta1.AdmissionReview{}
-	convertAdmissionAdmissionReviewToV1beta1AdmissionReview(review, reviewv1beta1)
-	return review
+	return review, nil
 }
diff --git a/internal/admission/controller/main_test.go b/internal/admission/controller/main_test.go
index b745c14a2d..7cc3cd7b43 100644
--- a/internal/admission/controller/main_test.go
+++ b/internal/admission/controller/main_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	admissionv1 "k8s.io/api/admission/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/json"
@@ -71,7 +71,7 @@ func TestHandleAdmission(t *testing.T) {
 
 	result, err = adm.HandleAdmission(&admissionv1.AdmissionReview{
 		Request: &admissionv1.AdmissionRequest{
-			Kind: v1.GroupVersionKind{Group: networking.GroupName, Version: "v1beta1", Kind: "Ingress"},
+			Kind: v1.GroupVersionKind{Group: networking.GroupName, Version: "v1", Kind: "Ingress"},
 			Object: runtime.RawExtension{
 				Raw: []byte{0xff},
 			},
diff --git a/internal/admission/controller/server.go b/internal/admission/controller/server.go
index 513d812a4e..29449de50d 100644
--- a/internal/admission/controller/server.go
+++ b/internal/admission/controller/server.go
@@ -21,7 +21,6 @@ import (
 	"net/http"
 
 	admissionv1 "k8s.io/api/admission/v1"
-	admissionv1beta1 "k8s.io/api/admission/v1beta1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/serializer/json"
 	"k8s.io/klog/v2"
@@ -32,7 +31,6 @@ var (
 )
 
 func init() {
-	admissionv1beta1.AddToScheme(scheme)
 	admissionv1.AddToScheme(scheme)
 }
 
diff --git a/internal/ingress/annotations/alias/main.go b/internal/ingress/annotations/alias/main.go
index 6cbe4c6dce..bd2067c9f6 100644
--- a/internal/ingress/annotations/alias/main.go
+++ b/internal/ingress/annotations/alias/main.go
@@ -20,7 +20,7 @@ import (
 	"sort"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/alias/main_test.go b/internal/ingress/annotations/alias/main_test.go
index a482fc7c1c..8e6fca4470 100644
--- a/internal/ingress/annotations/alias/main_test.go
+++ b/internal/ingress/annotations/alias/main_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/annotations.go b/internal/ingress/annotations/annotations.go
index 2c3b3c1cf2..9fb53dd1e6 100644
--- a/internal/ingress/annotations/annotations.go
+++ b/internal/ingress/annotations/annotations.go
@@ -25,7 +25,7 @@ import (
 	"k8s.io/klog/v2"
 
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/alias"
diff --git a/internal/ingress/annotations/annotations_test.go b/internal/ingress/annotations/annotations_test.go
index de02a8a16b..ada81117d5 100644
--- a/internal/ingress/annotations/annotations_test.go
+++ b/internal/ingress/annotations/annotations_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
@@ -77,8 +76,12 @@ func (m mockCfg) GetAuthCertificate(name string) (*resolver.AuthSSLCert, error)
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -87,9 +90,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: apiv1.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/auth/main.go b/internal/ingress/annotations/auth/main.go
index 84425a95c5..0a642f99f6 100644
--- a/internal/ingress/annotations/auth/main.go
+++ b/internal/ingress/annotations/auth/main.go
@@ -24,7 +24,7 @@ import (
 
 	"github.com/pkg/errors"
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/client-go/tools/cache"
 
 	"k8s.io/ingress-nginx/internal/file"
diff --git a/internal/ingress/annotations/auth/main_test.go b/internal/ingress/annotations/auth/main_test.go
index d018a8ddc7..bffb8e0a8f 100644
--- a/internal/ingress/annotations/auth/main_test.go
+++ b/internal/ingress/annotations/auth/main_test.go
@@ -25,9 +25,8 @@ import (
 	"github.com/pkg/errors"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -35,8 +34,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -45,9 +48,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/authreq/main.go b/internal/ingress/annotations/authreq/main.go
index afcd84a65f..6cfcc383d4 100644
--- a/internal/ingress/annotations/authreq/main.go
+++ b/internal/ingress/annotations/authreq/main.go
@@ -23,7 +23,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/authreq/main_test.go b/internal/ingress/annotations/authreq/main_test.go
index 276779c1c0..da903fe301 100644
--- a/internal/ingress/annotations/authreq/main_test.go
+++ b/internal/ingress/annotations/authreq/main_test.go
@@ -22,18 +22,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -42,9 +44,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/authreqglobal/main.go b/internal/ingress/annotations/authreqglobal/main.go
index 170f6957db..78dd7d6a57 100644
--- a/internal/ingress/annotations/authreqglobal/main.go
+++ b/internal/ingress/annotations/authreqglobal/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package authreqglobal
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/authreqglobal/main_test.go b/internal/ingress/annotations/authreqglobal/main_test.go
index a4096f7da9..0313edcf5e 100644
--- a/internal/ingress/annotations/authreqglobal/main_test.go
+++ b/internal/ingress/annotations/authreqglobal/main_test.go
@@ -20,18 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -40,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/authtls/main.go b/internal/ingress/annotations/authtls/main.go
index 16e218d333..dd89df4f36 100644
--- a/internal/ingress/annotations/authtls/main.go
+++ b/internal/ingress/annotations/authtls/main.go
@@ -18,7 +18,7 @@ package authtls
 
 import (
 	"github.com/pkg/errors"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"regexp"
 
diff --git a/internal/ingress/annotations/authtls/main_test.go b/internal/ingress/annotations/authtls/main_test.go
index d1a54ad70e..b2c915d187 100644
--- a/internal/ingress/annotations/authtls/main_test.go
+++ b/internal/ingress/annotations/authtls/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -30,8 +29,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -40,9 +43,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/backendprotocol/main.go b/internal/ingress/annotations/backendprotocol/main.go
index 65566d6e98..d8ea72386f 100644
--- a/internal/ingress/annotations/backendprotocol/main.go
+++ b/internal/ingress/annotations/backendprotocol/main.go
@@ -20,7 +20,7 @@ import (
 	"regexp"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/klog/v2"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/backendprotocol/main_test.go b/internal/ingress/annotations/backendprotocol/main_test.go
index 4a1c1bf31f..e8c018998c 100644
--- a/internal/ingress/annotations/backendprotocol/main_test.go
+++ b/internal/ingress/annotations/backendprotocol/main_test.go
@@ -20,12 +20,10 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
@@ -35,9 +33,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 		},
 	}
diff --git a/internal/ingress/annotations/canary/main.go b/internal/ingress/annotations/canary/main.go
index 2cc88021be..3930b84d77 100644
--- a/internal/ingress/annotations/canary/main.go
+++ b/internal/ingress/annotations/canary/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package canary
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/canary/main_test.go b/internal/ingress/annotations/canary/main_test.go
index f755fe8656..ddfc0a9c4e 100644
--- a/internal/ingress/annotations/canary/main_test.go
+++ b/internal/ingress/annotations/canary/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 
 	"strconv"
@@ -32,8 +31,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -42,9 +45,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/class/main.go b/internal/ingress/annotations/class/main.go
deleted file mode 100644
index 8db995ba57..0000000000
--- a/internal/ingress/annotations/class/main.go
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-Copyright 2015 The Kubernetes Authors.
-
-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 class
-
-import (
-	networking "k8s.io/api/networking/v1beta1"
-	"k8s.io/ingress-nginx/internal/k8s"
-)
-
-const (
-	// IngressKey picks a specific "class" for the Ingress.
-	// The controller only processes Ingresses with this annotation either
-	// unset, or set to either the configured value or the empty string.
-	IngressKey = "kubernetes.io/ingress.class"
-)
-
-var (
-	// DefaultClass defines the default class used in the nginx ingress controller
-	DefaultClass = "nginx"
-
-	// IngressClass sets the runtime ingress class to use
-	// An empty string means accept all ingresses without
-	// annotation and the ones configured with class nginx
-	IngressClass = "nginx"
-)
-
-// IsValid returns true if the given Ingress specify the ingress.class
-// annotation or IngressClassName resource for Kubernetes >= v1.18
-func IsValid(ing *networking.Ingress) bool {
-	// 1. with annotation or IngressClass
-	ingress, ok := ing.GetAnnotations()[IngressKey]
-	if !ok && ing.Spec.IngressClassName != nil {
-		ingress = *ing.Spec.IngressClassName
-	}
-
-	if len(ingress) == 0 && IngressClass == DefaultClass {
-		return true
-	}
-
-	// k8s > v1.18.
-	// Processing may be redundant because k8s.IngressClass is obtained by IngressClass
-	// 3. without annotation and IngressClass. Check IngressClass
-	if k8s.IngressClass != nil {
-		return ingress == k8s.IngressClass.Name
-	}
-
-	// 4. with IngressClass
-	return ingress == IngressClass
-}
diff --git a/internal/ingress/annotations/class/main_test.go b/internal/ingress/annotations/class/main_test.go
deleted file mode 100644
index 2d863f072c..0000000000
--- a/internal/ingress/annotations/class/main_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-Copyright 2017 The Kubernetes Authors.
-
-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 class
-
-import (
-	"testing"
-
-	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
-	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/ingress-nginx/internal/k8s"
-)
-
-func TestIsValidClass(t *testing.T) {
-	dc := DefaultClass
-	ic := IngressClass
-	k8sic := k8s.IngressClass
-	v1Ready := k8s.IsIngressV1Ready
-	// restore original values after the tests
-	defer func() {
-		DefaultClass = dc
-		IngressClass = ic
-		k8s.IngressClass = k8sic
-		k8s.IsIngressV1Ready = v1Ready
-	}()
-
-	tests := []struct {
-		ingress          string
-		controller       string
-		defClass         string
-		annotation       bool
-		ingressClassName bool
-		k8sClass         *networking.IngressClass
-		v1Ready          bool
-		isValid          bool
-	}{
-		{"", "", "nginx", true, false, nil, false, true},
-		{"", "nginx", "nginx", true, false, nil, false, true},
-		{"nginx", "nginx", "nginx", true, false, nil, false, true},
-		{"custom", "custom", "nginx", true, false, nil, false, true},
-		{"", "killer", "nginx", true, false, nil, false, false},
-		{"custom", "nginx", "nginx", true, false, nil, false, false},
-		{"nginx", "nginx", "nginx", false, true, nil, false, true},
-		{"custom", "nginx", "nginx", false, true, nil, true, false},
-		{"nginx", "nginx", "nginx", false, true, nil, true, true},
-		{"", "custom", "nginx", false, false,
-			&networking.IngressClass{
-				ObjectMeta: meta_v1.ObjectMeta{
-					Name: "custom",
-				},
-			},
-			false, false},
-		{"", "custom", "nginx", false, false,
-			&networking.IngressClass{
-				ObjectMeta: meta_v1.ObjectMeta{
-					Name: "custom",
-				},
-			},
-			true, false},
-	}
-
-	for _, test := range tests {
-		ing := &networking.Ingress{
-			ObjectMeta: meta_v1.ObjectMeta{
-				Name:      "foo",
-				Namespace: api.NamespaceDefault,
-			},
-		}
-
-		data := map[string]string{}
-		ing.SetAnnotations(data)
-		if test.annotation {
-			ing.Annotations[IngressKey] = test.ingress
-		}
-		if test.ingressClassName {
-			ing.Spec.IngressClassName = &[]string{test.ingress}[0]
-		}
-
-		IngressClass = test.controller
-		DefaultClass = test.defClass
-		k8s.IngressClass = test.k8sClass
-		k8s.IsIngressV1Ready = test.v1Ready
-
-		b := IsValid(ing)
-		if b != test.isValid {
-			t.Errorf("test %v - expected %v but %v was returned", test, test.isValid, b)
-		}
-	}
-}
diff --git a/internal/ingress/annotations/clientbodybuffersize/main.go b/internal/ingress/annotations/clientbodybuffersize/main.go
index 924ceecd17..9020ee594f 100644
--- a/internal/ingress/annotations/clientbodybuffersize/main.go
+++ b/internal/ingress/annotations/clientbodybuffersize/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package clientbodybuffersize
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/clientbodybuffersize/main_test.go b/internal/ingress/annotations/clientbodybuffersize/main_test.go
index 56f64083c4..9932f83143 100644
--- a/internal/ingress/annotations/clientbodybuffersize/main_test.go
+++ b/internal/ingress/annotations/clientbodybuffersize/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/connection/main.go b/internal/ingress/annotations/connection/main.go
index 7d45fdc364..e9b0c1865d 100644
--- a/internal/ingress/annotations/connection/main.go
+++ b/internal/ingress/annotations/connection/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package connection
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/connection/main_test.go b/internal/ingress/annotations/connection/main_test.go
index d86aeb16a2..011a2948cf 100644
--- a/internal/ingress/annotations/connection/main_test.go
+++ b/internal/ingress/annotations/connection/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/cors/main.go b/internal/ingress/annotations/cors/main.go
index 2f1a0a37b5..44947a014e 100644
--- a/internal/ingress/annotations/cors/main.go
+++ b/internal/ingress/annotations/cors/main.go
@@ -19,7 +19,7 @@ package cors
 import (
 	"regexp"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/cors/main_test.go b/internal/ingress/annotations/cors/main_test.go
index 6f75ce6a76..a65bf12cde 100644
--- a/internal/ingress/annotations/cors/main_test.go
+++ b/internal/ingress/annotations/cors/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/customhttperrors/main.go b/internal/ingress/annotations/customhttperrors/main.go
index 3c5fbf077b..a05fb16c86 100644
--- a/internal/ingress/annotations/customhttperrors/main.go
+++ b/internal/ingress/annotations/customhttperrors/main.go
@@ -20,7 +20,7 @@ import (
 	"strconv"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/customhttperrors/main_test.go b/internal/ingress/annotations/customhttperrors/main_test.go
index 3827d197fd..1f87247ed9 100644
--- a/internal/ingress/annotations/customhttperrors/main_test.go
+++ b/internal/ingress/annotations/customhttperrors/main_test.go
@@ -22,12 +22,10 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
@@ -37,9 +35,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 		},
 	}
diff --git a/internal/ingress/annotations/defaultbackend/main.go b/internal/ingress/annotations/defaultbackend/main.go
index ff4f41ce3f..7b239497d3 100644
--- a/internal/ingress/annotations/defaultbackend/main.go
+++ b/internal/ingress/annotations/defaultbackend/main.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 
 	"github.com/pkg/errors"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/defaultbackend/main_test.go b/internal/ingress/annotations/defaultbackend/main_test.go
index 9278602157..ec23d32c2a 100644
--- a/internal/ingress/annotations/defaultbackend/main_test.go
+++ b/internal/ingress/annotations/defaultbackend/main_test.go
@@ -20,19 +20,21 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -41,9 +43,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/fastcgi/main.go b/internal/ingress/annotations/fastcgi/main.go
index 174a2716c5..a7e96a0141 100644
--- a/internal/ingress/annotations/fastcgi/main.go
+++ b/internal/ingress/annotations/fastcgi/main.go
@@ -21,7 +21,7 @@ import (
 	"reflect"
 
 	"github.com/pkg/errors"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/client-go/tools/cache"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/fastcgi/main_test.go b/internal/ingress/annotations/fastcgi/main_test.go
index 6802a41c20..26d85e7cee 100644
--- a/internal/ingress/annotations/fastcgi/main_test.go
+++ b/internal/ingress/annotations/fastcgi/main_test.go
@@ -20,13 +20,11 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
@@ -36,9 +34,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "fastcgi",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 		},
 	}
diff --git a/internal/ingress/annotations/globalratelimit/main.go b/internal/ingress/annotations/globalratelimit/main.go
index e4b18bd662..02a7328472 100644
--- a/internal/ingress/annotations/globalratelimit/main.go
+++ b/internal/ingress/annotations/globalratelimit/main.go
@@ -21,7 +21,7 @@ import (
 	"time"
 
 	"github.com/pkg/errors"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/globalratelimit/main_test.go b/internal/ingress/annotations/globalratelimit/main_test.go
index 38da8f4a9c..341a9883c8 100644
--- a/internal/ingress/annotations/globalratelimit/main_test.go
+++ b/internal/ingress/annotations/globalratelimit/main_test.go
@@ -23,10 +23,9 @@ import (
 
 	"github.com/pkg/errors"
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -37,8 +36,12 @@ const expectedUID = "31285d47b1504dcfbd6f12c46d769f6e"
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -48,9 +51,13 @@ func buildIngress() *networking.Ingress {
 			UID:       UID,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/http2pushpreload/main.go b/internal/ingress/annotations/http2pushpreload/main.go
index c542f03cf5..27d3368f43 100644
--- a/internal/ingress/annotations/http2pushpreload/main.go
+++ b/internal/ingress/annotations/http2pushpreload/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package http2pushpreload
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/http2pushpreload/main_test.go b/internal/ingress/annotations/http2pushpreload/main_test.go
index 6b24ecfaee..bb98af93f3 100644
--- a/internal/ingress/annotations/http2pushpreload/main_test.go
+++ b/internal/ingress/annotations/http2pushpreload/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/influxdb/main.go b/internal/ingress/annotations/influxdb/main.go
index cec014b897..1aee91f331 100644
--- a/internal/ingress/annotations/influxdb/main.go
+++ b/internal/ingress/annotations/influxdb/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package influxdb
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/influxdb/main_test.go b/internal/ingress/annotations/influxdb/main_test.go
index 97ba149638..13d6815096 100644
--- a/internal/ingress/annotations/influxdb/main_test.go
+++ b/internal/ingress/annotations/influxdb/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/ipwhitelist/main.go b/internal/ingress/annotations/ipwhitelist/main.go
index 42d424873b..4fd40ee2be 100644
--- a/internal/ingress/annotations/ipwhitelist/main.go
+++ b/internal/ingress/annotations/ipwhitelist/main.go
@@ -22,7 +22,7 @@ import (
 
 	"github.com/pkg/errors"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/internal/net"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/ipwhitelist/main_test.go b/internal/ingress/annotations/ipwhitelist/main_test.go
index 43aef75735..5042bb2003 100644
--- a/internal/ingress/annotations/ipwhitelist/main_test.go
+++ b/internal/ingress/annotations/ipwhitelist/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -30,8 +29,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -40,9 +43,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/loadbalancing/main.go b/internal/ingress/annotations/loadbalancing/main.go
index ddae0ccbe5..a8b4335e6f 100644
--- a/internal/ingress/annotations/loadbalancing/main.go
+++ b/internal/ingress/annotations/loadbalancing/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package loadbalancing
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/loadbalancing/main_test.go b/internal/ingress/annotations/loadbalancing/main_test.go
index bbda797154..e2be5c0ae4 100644
--- a/internal/ingress/annotations/loadbalancing/main_test.go
+++ b/internal/ingress/annotations/loadbalancing/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/log/main.go b/internal/ingress/annotations/log/main.go
index 6cf99d9c8b..4bc76dcf7a 100644
--- a/internal/ingress/annotations/log/main.go
+++ b/internal/ingress/annotations/log/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package log
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/log/main_test.go b/internal/ingress/annotations/log/main_test.go
index 068b1be16c..c4632b0104 100644
--- a/internal/ingress/annotations/log/main_test.go
+++ b/internal/ingress/annotations/log/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/mirror/main.go b/internal/ingress/annotations/mirror/main.go
index b2591347e0..e11d4b4fb5 100644
--- a/internal/ingress/annotations/mirror/main.go
+++ b/internal/ingress/annotations/mirror/main.go
@@ -19,7 +19,7 @@ package mirror
 import (
 	"fmt"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/mirror/main_test.go b/internal/ingress/annotations/mirror/main_test.go
index 1ecaef3b9c..af7ed1b1fa 100644
--- a/internal/ingress/annotations/mirror/main_test.go
+++ b/internal/ingress/annotations/mirror/main_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/modsecurity/main.go b/internal/ingress/annotations/modsecurity/main.go
index 91a0a5a947..c537394413 100644
--- a/internal/ingress/annotations/modsecurity/main.go
+++ b/internal/ingress/annotations/modsecurity/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package modsecurity
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
diff --git a/internal/ingress/annotations/modsecurity/main_test.go b/internal/ingress/annotations/modsecurity/main_test.go
index 34d92533dc..2ddbdf7e3a 100644
--- a/internal/ingress/annotations/modsecurity/main_test.go
+++ b/internal/ingress/annotations/modsecurity/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/opentracing/main.go b/internal/ingress/annotations/opentracing/main.go
index 875d695f70..2ed4a2182c 100644
--- a/internal/ingress/annotations/opentracing/main.go
+++ b/internal/ingress/annotations/opentracing/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package opentracing
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/opentracing/main_test.go b/internal/ingress/annotations/opentracing/main_test.go
index f1e06b087c..77e29cb5d4 100644
--- a/internal/ingress/annotations/opentracing/main_test.go
+++ b/internal/ingress/annotations/opentracing/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/parser/main.go b/internal/ingress/annotations/parser/main.go
index 3fae804dac..b39e409b9c 100644
--- a/internal/ingress/annotations/parser/main.go
+++ b/internal/ingress/annotations/parser/main.go
@@ -22,7 +22,7 @@ import (
 	"strconv"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 
 	"k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/parser/main_test.go b/internal/ingress/annotations/parser/main_test.go
index 2185651831..f63560ca34 100644
--- a/internal/ingress/annotations/parser/main_test.go
+++ b/internal/ingress/annotations/parser/main_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
diff --git a/internal/ingress/annotations/portinredirect/main.go b/internal/ingress/annotations/portinredirect/main.go
index bb5925c31b..25d6655587 100644
--- a/internal/ingress/annotations/portinredirect/main.go
+++ b/internal/ingress/annotations/portinredirect/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package portinredirect
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/portinredirect/main_test.go b/internal/ingress/annotations/portinredirect/main_test.go
index 7087ddcd3f..71afd4cdf0 100644
--- a/internal/ingress/annotations/portinredirect/main_test.go
+++ b/internal/ingress/annotations/portinredirect/main_test.go
@@ -21,9 +21,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
@@ -32,8 +31,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -42,9 +45,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/proxy/main.go b/internal/ingress/annotations/proxy/main.go
index f5c2252583..3a89b88557 100644
--- a/internal/ingress/annotations/proxy/main.go
+++ b/internal/ingress/annotations/proxy/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package proxy
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/proxy/main_test.go b/internal/ingress/annotations/proxy/main_test.go
index 418db922e9..e377ccb195 100644
--- a/internal/ingress/annotations/proxy/main_test.go
+++ b/internal/ingress/annotations/proxy/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
@@ -31,8 +30,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -41,9 +44,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/proxyssl/main.go b/internal/ingress/annotations/proxyssl/main.go
index da3bbecc08..2452d90da8 100644
--- a/internal/ingress/annotations/proxyssl/main.go
+++ b/internal/ingress/annotations/proxyssl/main.go
@@ -22,7 +22,7 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/proxyssl/main_test.go b/internal/ingress/annotations/proxyssl/main_test.go
index a52fcb98a1..29949796c8 100644
--- a/internal/ingress/annotations/proxyssl/main_test.go
+++ b/internal/ingress/annotations/proxyssl/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -30,8 +29,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -40,9 +43,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/ratelimit/main.go b/internal/ingress/annotations/ratelimit/main.go
index 7b7d6f4dbe..4011c25429 100644
--- a/internal/ingress/annotations/ratelimit/main.go
+++ b/internal/ingress/annotations/ratelimit/main.go
@@ -21,7 +21,7 @@ import (
 	"fmt"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/ratelimit/main_test.go b/internal/ingress/annotations/ratelimit/main_test.go
index 7ffbac3ff6..9f101cc3b9 100644
--- a/internal/ingress/annotations/ratelimit/main_test.go
+++ b/internal/ingress/annotations/ratelimit/main_test.go
@@ -20,10 +20,9 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
@@ -31,8 +30,12 @@ import (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -41,9 +44,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/redirect/redirect.go b/internal/ingress/annotations/redirect/redirect.go
index 02ee1d522c..11b08a4a29 100644
--- a/internal/ingress/annotations/redirect/redirect.go
+++ b/internal/ingress/annotations/redirect/redirect.go
@@ -21,7 +21,7 @@ import (
 	"net/url"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/redirect/redirect_test.go b/internal/ingress/annotations/redirect/redirect_test.go
index b9bda6688f..b5a87a5d38 100644
--- a/internal/ingress/annotations/redirect/redirect_test.go
+++ b/internal/ingress/annotations/redirect/redirect_test.go
@@ -23,7 +23,7 @@ import (
 	"strconv"
 	"testing"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/rewrite/main.go b/internal/ingress/annotations/rewrite/main.go
index 902f00f4c3..f92d508dc3 100644
--- a/internal/ingress/annotations/rewrite/main.go
+++ b/internal/ingress/annotations/rewrite/main.go
@@ -19,7 +19,7 @@ package rewrite
 import (
 	"net/url"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/klog/v2"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/rewrite/main_test.go b/internal/ingress/annotations/rewrite/main_test.go
index beece494a4..c2cb42c78f 100644
--- a/internal/ingress/annotations/rewrite/main_test.go
+++ b/internal/ingress/annotations/rewrite/main_test.go
@@ -20,9 +20,8 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
@@ -35,8 +34,12 @@ const (
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -46,9 +49,13 @@ func buildIngress() *networking.Ingress {
 			Annotations: map[string]string{},
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/satisfy/main.go b/internal/ingress/annotations/satisfy/main.go
index a064bdf96f..0d4fd4ff6b 100644
--- a/internal/ingress/annotations/satisfy/main.go
+++ b/internal/ingress/annotations/satisfy/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package satisfy
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/satisfy/main_test.go b/internal/ingress/annotations/satisfy/main_test.go
index a3475316ae..b45205d9f0 100644
--- a/internal/ingress/annotations/satisfy/main_test.go
+++ b/internal/ingress/annotations/satisfy/main_test.go
@@ -20,18 +20,21 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -40,9 +43,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/secureupstream/main.go b/internal/ingress/annotations/secureupstream/main.go
index 6318044644..ebaea20588 100644
--- a/internal/ingress/annotations/secureupstream/main.go
+++ b/internal/ingress/annotations/secureupstream/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package secureupstream
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/klog/v2"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/secureupstream/main_test.go b/internal/ingress/annotations/secureupstream/main_test.go
index 508d54a84d..7546cb5cf3 100644
--- a/internal/ingress/annotations/secureupstream/main_test.go
+++ b/internal/ingress/annotations/secureupstream/main_test.go
@@ -21,18 +21,21 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -41,9 +44,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/serversnippet/main.go b/internal/ingress/annotations/serversnippet/main.go
index 33a672650f..70f0af8e5d 100644
--- a/internal/ingress/annotations/serversnippet/main.go
+++ b/internal/ingress/annotations/serversnippet/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package serversnippet
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/serversnippet/main_test.go b/internal/ingress/annotations/serversnippet/main_test.go
index 066334f69b..c9e0979ad2 100644
--- a/internal/ingress/annotations/serversnippet/main_test.go
+++ b/internal/ingress/annotations/serversnippet/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/serviceupstream/main.go b/internal/ingress/annotations/serviceupstream/main.go
index ff90f8160d..4c44356d66 100644
--- a/internal/ingress/annotations/serviceupstream/main.go
+++ b/internal/ingress/annotations/serviceupstream/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package serviceupstream
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/serviceupstream/main_test.go b/internal/ingress/annotations/serviceupstream/main_test.go
index c7f44598e6..3fbdb57854 100644
--- a/internal/ingress/annotations/serviceupstream/main_test.go
+++ b/internal/ingress/annotations/serviceupstream/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
diff --git a/internal/ingress/annotations/sessionaffinity/main.go b/internal/ingress/annotations/sessionaffinity/main.go
index 80b24f13bf..358be14422 100644
--- a/internal/ingress/annotations/sessionaffinity/main.go
+++ b/internal/ingress/annotations/sessionaffinity/main.go
@@ -19,7 +19,7 @@ package sessionaffinity
 import (
 	"regexp"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/klog/v2"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
diff --git a/internal/ingress/annotations/sessionaffinity/main_test.go b/internal/ingress/annotations/sessionaffinity/main_test.go
index 51d92ffb07..98f0a1eb61 100644
--- a/internal/ingress/annotations/sessionaffinity/main_test.go
+++ b/internal/ingress/annotations/sessionaffinity/main_test.go
@@ -20,17 +20,20 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
 )
 
 func buildIngress() *networking.Ingress {
 	defaultBackend := networking.IngressBackend{
-		ServiceName: "default-backend",
-		ServicePort: intstr.FromInt(80),
+		Service: &networking.IngressServiceBackend{
+			Name: "default-backend",
+			Port: networking.ServiceBackendPort{
+				Number: 80,
+			},
+		},
 	}
 
 	return &networking.Ingress{
@@ -39,9 +42,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 			Rules: []networking.IngressRule{
 				{
@@ -64,7 +71,6 @@ func buildIngress() *networking.Ingress {
 
 func TestIngressAffinityCookieConfig(t *testing.T) {
 	ing := buildIngress()
-
 	data := map[string]string{}
 	data[parser.GetAnnotationWithPrefix(annotationAffinityType)] = "cookie"
 	data[parser.GetAnnotationWithPrefix(annotationAffinityMode)] = "balanced"
diff --git a/internal/ingress/annotations/snippet/main.go b/internal/ingress/annotations/snippet/main.go
index 9a3878603c..93ec70cf97 100644
--- a/internal/ingress/annotations/snippet/main.go
+++ b/internal/ingress/annotations/snippet/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package snippet
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/snippet/main_test.go b/internal/ingress/annotations/snippet/main_test.go
index 0abeaed8a0..0defc3c1f8 100644
--- a/internal/ingress/annotations/snippet/main_test.go
+++ b/internal/ingress/annotations/snippet/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/sslcipher/main.go b/internal/ingress/annotations/sslcipher/main.go
index d100a0da4b..e4e5baad20 100644
--- a/internal/ingress/annotations/sslcipher/main.go
+++ b/internal/ingress/annotations/sslcipher/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package sslcipher
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/sslcipher/main_test.go b/internal/ingress/annotations/sslcipher/main_test.go
index 8110697dcd..6eb9ec0c2c 100644
--- a/internal/ingress/annotations/sslcipher/main_test.go
+++ b/internal/ingress/annotations/sslcipher/main_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/sslpassthrough/main.go b/internal/ingress/annotations/sslpassthrough/main.go
index 20ff1a010d..d1def7172a 100644
--- a/internal/ingress/annotations/sslpassthrough/main.go
+++ b/internal/ingress/annotations/sslpassthrough/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package sslpassthrough
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ing_errors "k8s.io/ingress-nginx/internal/ingress/errors"
diff --git a/internal/ingress/annotations/sslpassthrough/main_test.go b/internal/ingress/annotations/sslpassthrough/main_test.go
index d5e54b2e2f..5cf2f979ad 100644
--- a/internal/ingress/annotations/sslpassthrough/main_test.go
+++ b/internal/ingress/annotations/sslpassthrough/main_test.go
@@ -20,12 +20,10 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
-
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 func buildIngress() *networking.Ingress {
@@ -35,9 +33,13 @@ func buildIngress() *networking.Ingress {
 			Namespace: api.NamespaceDefault,
 		},
 		Spec: networking.IngressSpec{
-			Backend: &networking.IngressBackend{
-				ServiceName: "default-backend",
-				ServicePort: intstr.FromInt(80),
+			DefaultBackend: &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "default-backend",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
+				},
 			},
 		},
 	}
diff --git a/internal/ingress/annotations/upstreamhashby/main.go b/internal/ingress/annotations/upstreamhashby/main.go
index bb202f1b05..e6bbca6c33 100644
--- a/internal/ingress/annotations/upstreamhashby/main.go
+++ b/internal/ingress/annotations/upstreamhashby/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package upstreamhashby
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/upstreamhashby/main_test.go b/internal/ingress/annotations/upstreamhashby/main_test.go
index 5a71be56f5..d2c2644cac 100644
--- a/internal/ingress/annotations/upstreamhashby/main_test.go
+++ b/internal/ingress/annotations/upstreamhashby/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/upstreamvhost/main.go b/internal/ingress/annotations/upstreamvhost/main.go
index bf761a70f8..2eed5607e0 100644
--- a/internal/ingress/annotations/upstreamvhost/main.go
+++ b/internal/ingress/annotations/upstreamvhost/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package upstreamvhost
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/upstreamvhost/main_test.go b/internal/ingress/annotations/upstreamvhost/main_test.go
index 1506c4f7fb..130d745ee3 100644
--- a/internal/ingress/annotations/upstreamvhost/main_test.go
+++ b/internal/ingress/annotations/upstreamvhost/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/xforwardedprefix/main.go b/internal/ingress/annotations/xforwardedprefix/main.go
index 2071b64113..60eed8773b 100644
--- a/internal/ingress/annotations/xforwardedprefix/main.go
+++ b/internal/ingress/annotations/xforwardedprefix/main.go
@@ -17,7 +17,7 @@ limitations under the License.
 package xforwardedprefix
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/annotations/xforwardedprefix/main_test.go b/internal/ingress/annotations/xforwardedprefix/main_test.go
index c94df3ab2d..a78c63d049 100644
--- a/internal/ingress/annotations/xforwardedprefix/main_test.go
+++ b/internal/ingress/annotations/xforwardedprefix/main_test.go
@@ -20,7 +20,7 @@ import (
 	"testing"
 
 	api "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/resolver"
diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go
index 20cca4696b..8d9465b9ed 100644
--- a/internal/ingress/controller/controller.go
+++ b/internal/ingress/controller/controller.go
@@ -25,7 +25,7 @@ import (
 
 	"github.com/mitchellh/hashstructure"
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	apiequality "k8s.io/apimachinery/pkg/api/equality"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/apimachinery/pkg/util/sets"
@@ -33,11 +33,12 @@ import (
 	clientset "k8s.io/client-go/kubernetes"
 	"k8s.io/ingress-nginx/internal/ingress"
 	"k8s.io/ingress-nginx/internal/ingress/annotations"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/log"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/proxy"
 	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
+	"k8s.io/ingress-nginx/internal/ingress/controller/store"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
 	"k8s.io/ingress-nginx/internal/k8s"
 	"k8s.io/ingress-nginx/internal/nginx"
@@ -99,6 +100,8 @@ type Configuration struct {
 
 	DisableCatchAll bool
 
+	IngressClassConfiguration *ingressclass.IngressClassConfiguration
+
 	ValidationWebhook         string
 	ValidationWebhookCertPath string
 	ValidationWebhookKeyPath  string
@@ -132,27 +135,27 @@ func (n *NGINXController) syncIngress(interface{}) error {
 	}
 
 	ings := n.store.ListIngresses()
-	hosts, servers, newCfg := n.getConfiguration(ings)
+	hosts, servers, pcfg := n.getConfiguration(ings)
 
 	n.metricCollector.SetSSLExpireTime(servers)
 
-	if n.runningConfig.Equal(newCfg) {
+	if n.runningConfig.Equal(pcfg) {
 		klog.V(3).Infof("No configuration change detected, skipping backend reload")
 		return nil
 	}
 
 	n.metricCollector.SetHosts(hosts)
 
-	if !n.IsDynamicConfigurationEnough(newCfg) {
+	if !n.IsDynamicConfigurationEnough(pcfg) {
 		klog.InfoS("Configuration changes detected, backend reload required")
 
-		hash, _ := hashstructure.Hash(newCfg, &hashstructure.HashOptions{
+		hash, _ := hashstructure.Hash(pcfg, &hashstructure.HashOptions{
 			TagName: "json",
 		})
 
-		newCfg.ConfigurationChecksum = fmt.Sprintf("%v", hash)
+		pcfg.ConfigurationChecksum = fmt.Sprintf("%v", hash)
 
-		err := n.OnUpdate(*newCfg)
+		err := n.OnUpdate(*pcfg)
 		if err != nil {
 			n.metricCollector.IncReloadErrorCount()
 			n.metricCollector.ConfigSuccess(hash, false)
@@ -184,7 +187,7 @@ func (n *NGINXController) syncIngress(interface{}) error {
 	}
 
 	err := wait.ExponentialBackoff(retry, func() (bool, error) {
-		err := n.configureDynamically(newCfg)
+		err := n.configureDynamically(pcfg)
 		if err == nil {
 			klog.V(2).Infof("Dynamic reconfiguration succeeded.")
 			return true, nil
@@ -198,11 +201,11 @@ func (n *NGINXController) syncIngress(interface{}) error {
 		return err
 	}
 
-	ri := getRemovedIngresses(n.runningConfig, newCfg)
-	re := getRemovedHosts(n.runningConfig, newCfg)
+	ri := getRemovedIngresses(n.runningConfig, pcfg)
+	re := getRemovedHosts(n.runningConfig, pcfg)
 	n.metricCollector.RemoveMetrics(ri, re)
 
-	n.runningConfig = newCfg
+	n.runningConfig = pcfg
 
 	return nil
 }
@@ -220,17 +223,12 @@ func (n *NGINXController) CheckIngress(ing *networking.Ingress) error {
 		return nil
 	}
 
-	if !class.IsValid(ing) {
-		klog.Warningf("ignoring ingress %v in %v based on annotation %v", ing.Name, ing.ObjectMeta.Namespace, class.IngressKey)
-		return nil
-	}
-
 	if n.cfg.Namespace != "" && ing.ObjectMeta.Namespace != n.cfg.Namespace {
 		klog.Warningf("ignoring ingress %v in namespace %v different from the namespace watched %s", ing.Name, ing.ObjectMeta.Namespace, n.cfg.Namespace)
 		return nil
 	}
 
-	if n.cfg.DisableCatchAll && ing.Spec.Backend != nil {
+	if n.cfg.DisableCatchAll && ing.Spec.DefaultBackend != nil {
 		return fmt.Errorf("This deployment is trying to create a catch-all ingress while DisableCatchAll flag is set to true. Remove '.spec.backend' or set DisableCatchAll flag to false.")
 	}
 
@@ -255,6 +253,40 @@ func (n *NGINXController) CheckIngress(ing *networking.Ingress) error {
 		}
 	}
 
+	allIngresses := n.store.ListIngresses()
+
+	filter := func(toCheck *ingress.Ingress) bool {
+		return toCheck.ObjectMeta.Namespace == ing.ObjectMeta.Namespace &&
+			toCheck.ObjectMeta.Name == ing.ObjectMeta.Name
+	}
+	ings := store.FilterIngresses(allIngresses, filter)
+	ings = append(ings, &ingress.Ingress{
+		Ingress:           *ing,
+		ParsedAnnotations: annotations.NewAnnotationExtractor(n.store).Extract(ing),
+	})
+
+	_, servers, pcfg := n.getConfiguration(ings)
+
+	err := checkOverlap(ing, allIngresses, servers)
+	if err != nil {
+		n.metricCollector.IncCheckErrorCount(ing.ObjectMeta.Namespace, ing.Name)
+		return err
+	}
+
+	content, err := n.generateTemplate(cfg, *pcfg)
+	if err != nil {
+		n.metricCollector.IncCheckErrorCount(ing.ObjectMeta.Namespace, ing.Name)
+		return err
+	}
+
+	err = n.testTemplate(content)
+	if err != nil {
+		n.metricCollector.IncCheckErrorCount(ing.ObjectMeta.Namespace, ing.Name)
+		return err
+	}
+
+	n.metricCollector.IncCheckCount(ing.ObjectMeta.Namespace, ing.Name)
+
 	klog.Info("starting validation of ingress ", fmt.Sprintf("%v/%v", ing.Namespace, ing.Name))
 	return n.admissionBatcher.ValidateIngress(ing)
 }
@@ -552,7 +584,13 @@ func (n *NGINXController) getBackendServers(ingresses []*ingress.Ingress) ([]*in
 			}
 
 			for _, path := range rule.HTTP.Paths {
-				upsName := upstreamName(ing.Namespace, path.Backend.ServiceName, path.Backend.ServicePort)
+				if path.Backend.Service == nil {
+					// skip non-service backends
+					klog.V(3).Infof("Ingress %q and path %q does not contain a service backend, using default backend", ingKey, path.Path)
+					continue
+				}
+
+				upsName := upstreamName(ing.Namespace, path.Backend.Service)
 
 				ups := upstreams[upsName]
 
@@ -762,16 +800,17 @@ func (n *NGINXController) getBackendServers(ingresses []*ingress.Ingress) ([]*in
 
 // createUpstreams creates the NGINX upstreams (Endpoints) for each Service
 // referenced in Ingress rules.
-func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingress.Backend) map[string]*ingress.Backend {
+func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.Backend) map[string]*ingress.Backend {
 	upstreams := make(map[string]*ingress.Backend)
 	upstreams[defUpstreamName] = du
 
-	for _, ing := range ingresses {
+	for _, ing := range data {
+		ingKey := k8s.MetaNamespaceKey(ing)
 		anns := ing.ParsedAnnotations
 
 		var defBackend string
-		if ing.Spec.Backend != nil {
-			defBackend = upstreamName(ing.Namespace, ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort)
+		if ing.Spec.DefaultBackend != nil && ing.Spec.DefaultBackend.Service != nil {
+			defBackend = upstreamName(ing.Namespace, ing.Spec.DefaultBackend.Service)
 
 			klog.V(3).Infof("Creating upstream %q", defBackend)
 			upstreams[defBackend] = newUpstream(defBackend)
@@ -785,11 +824,11 @@ func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingr
 				upstreams[defBackend].LoadBalancing = n.store.GetBackendConfiguration().LoadBalancing
 			}
 
-			svcKey := fmt.Sprintf("%v/%v", ing.Namespace, ing.Spec.Backend.ServiceName)
+			svcKey := fmt.Sprintf("%v/%v", ing.Namespace, ing.Spec.DefaultBackend.Service.Name)
 
 			// add the service ClusterIP as a single Endpoint instead of individual Endpoints
 			if anns.ServiceUpstream {
-				endpoint, err := n.getServiceClusterEndpoint(svcKey, ing.Spec.Backend)
+				endpoint, err := n.getServiceClusterEndpoint(svcKey, ing.Spec.DefaultBackend)
 				if err != nil {
 					klog.Errorf("Failed to determine a suitable ClusterIP Endpoint for Service %q: %v", svcKey, err)
 				} else {
@@ -810,7 +849,8 @@ func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingr
 			}
 
 			if len(upstreams[defBackend].Endpoints) == 0 {
-				endps, err := n.serviceEndpoints(svcKey, ing.Spec.Backend.ServicePort.String())
+				_, port := upstreamServiceNameAndPort(ing.Spec.DefaultBackend.Service)
+				endps, err := n.serviceEndpoints(svcKey, port.String())
 				upstreams[defBackend].Endpoints = append(upstreams[defBackend].Endpoints, endps...)
 				if err != nil {
 					klog.Warningf("Error creating upstream %q: %v", defBackend, err)
@@ -830,15 +870,21 @@ func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingr
 			}
 
 			for _, path := range rule.HTTP.Paths {
-				name := upstreamName(ing.Namespace, path.Backend.ServiceName, path.Backend.ServicePort)
+				if path.Backend.Service == nil {
+					// skip non-service backends
+					klog.V(3).Infof("Ingress %q and path %q does not contain a service backend, using default backend", ingKey, path.Path)
+					continue
+				}
 
+				name := upstreamName(ing.Namespace, path.Backend.Service)
+				svcName, svcPort := upstreamServiceNameAndPort(path.Backend.Service)
 				if _, ok := upstreams[name]; ok {
 					continue
 				}
 
 				klog.V(3).Infof("Creating upstream %q", name)
 				upstreams[name] = newUpstream(name)
-				upstreams[name].Port = path.Backend.ServicePort
+				upstreams[name].Port = svcPort
 
 				upstreams[name].UpstreamHashBy.UpstreamHashBy = anns.UpstreamHashBy.UpstreamHashBy
 				upstreams[name].UpstreamHashBy.UpstreamHashBySubset = anns.UpstreamHashBy.UpstreamHashBySubset
@@ -849,7 +895,7 @@ func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingr
 					upstreams[name].LoadBalancing = n.store.GetBackendConfiguration().LoadBalancing
 				}
 
-				svcKey := fmt.Sprintf("%v/%v", ing.Namespace, path.Backend.ServiceName)
+				svcKey := fmt.Sprintf("%v/%v", ing.Namespace, svcName)
 
 				// add the service ClusterIP as a single Endpoint instead of individual Endpoints
 				if anns.ServiceUpstream {
@@ -874,7 +920,8 @@ func (n *NGINXController) createUpstreams(ingresses []*ingress.Ingress, du *ingr
 				}
 
 				if len(upstreams[name].Endpoints) == 0 {
-					endp, err := n.serviceEndpoints(svcKey, path.Backend.ServicePort.String())
+					_, port := upstreamServiceNameAndPort(path.Backend.Service)
+					endp, err := n.serviceEndpoints(svcKey, port.String())
 					if err != nil {
 						klog.Warningf("Error obtaining Endpoints for Service %q: %v", svcKey, err)
 						continue
@@ -912,20 +959,23 @@ func (n *NGINXController) getServiceClusterEndpoint(svcKey string, backend *netw
 
 	// if the Service port is referenced by name in the Ingress, lookup the
 	// actual port in the service spec
-	if backend.ServicePort.Type == intstr.String {
-		var port int32 = -1
-		for _, svcPort := range svc.Spec.Ports {
-			if svcPort.Name == backend.ServicePort.String() {
-				port = svcPort.Port
-				break
+	if backend.Service != nil {
+		_, svcportintorstr := upstreamServiceNameAndPort(backend.Service)
+		if svcportintorstr.Type == intstr.String {
+			var port int32 = -1
+			for _, svcPort := range svc.Spec.Ports {
+				if svcPort.Name == svcportintorstr.String() {
+					port = svcPort.Port
+					break
+				}
 			}
+			if port == -1 {
+				return endpoint, fmt.Errorf("service %q does not have a port named %q", svc.Name, svcportintorstr.String())
+			}
+			endpoint.Port = fmt.Sprintf("%d", port)
+		} else {
+			endpoint.Port = svcportintorstr.String()
 		}
-		if port == -1 {
-			return endpoint, fmt.Errorf("service %q does not have a port named %q", svc.Name, backend.ServicePort)
-		}
-		endpoint.Port = fmt.Sprintf("%d", port)
-	} else {
-		endpoint.Port = backend.ServicePort.String()
 	}
 
 	return endpoint, err
@@ -1056,8 +1106,8 @@ func (n *NGINXController) createServers(data []*ingress.Ingress,
 			continue
 		}
 
-		if ing.Spec.Backend != nil {
-			defUpstream := upstreamName(ing.Namespace, ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort)
+		if ing.Spec.DefaultBackend != nil && ing.Spec.DefaultBackend.Service != nil {
+			defUpstream := upstreamName(ing.Namespace, ing.Spec.DefaultBackend.Service)
 
 			if backendUpstream, ok := upstreams[defUpstream]; ok {
 				// use backend specified in Ingress as the default backend for all its rules
@@ -1326,8 +1376,8 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
 	servers map[string]*ingress.Server) {
 
 	// merge catch-all alternative backends
-	if ing.Spec.Backend != nil {
-		upsName := upstreamName(ing.Namespace, ing.Spec.Backend.ServiceName, ing.Spec.Backend.ServicePort)
+	if ing.Spec.DefaultBackend != nil {
+		upsName := upstreamName(ing.Namespace, ing.Spec.DefaultBackend.Service)
 
 		altUps := upstreams[upsName]
 
@@ -1369,7 +1419,13 @@ func mergeAlternativeBackends(ing *ingress.Ingress, upstreams map[string]*ingres
 		}
 
 		for _, path := range rule.HTTP.Paths {
-			upsName := upstreamName(ing.Namespace, path.Backend.ServiceName, path.Backend.ServicePort)
+			if path.Backend.Service == nil {
+				// skip non-service backends
+				klog.V(3).Infof("Ingress %q and path %q does not contain a service backend, using default backend", k8s.MetaNamespaceKey(ing), path.Path)
+				continue
+			}
+
+			upsName := upstreamName(ing.Namespace, path.Backend.Service)
 
 			altUps := upstreams[upsName]
 
@@ -1574,7 +1630,7 @@ func externalNamePorts(name string, svc *apiv1.Service) *apiv1.ServicePort {
 	}
 }
 
-func checkOverlap(ing *networking.Ingress, servers []*ingress.Server) error {
+func checkOverlap(ing *networking.Ingress, ingresses []*ingress.Ingress, servers []*ingress.Server) error {
 	for _, rule := range ing.Spec.Rules {
 		if rule.HTTP == nil {
 			continue
@@ -1585,6 +1641,12 @@ func checkOverlap(ing *networking.Ingress, servers []*ingress.Server) error {
 		}
 
 		for _, path := range rule.HTTP.Paths {
+			if path.Backend.Service == nil {
+				// skip non-service backends
+				klog.V(3).Infof("Ingress %q and path %q does not contain a service backend, using default backend", k8s.MetaNamespaceKey(ing), path.Path)
+				continue
+			}
+
 			if path.Path == "" {
 				path.Path = rootLocation
 			}
@@ -1597,12 +1659,17 @@ func checkOverlap(ing *networking.Ingress, servers []*ingress.Server) error {
 			}
 
 			// same ingress
+			skipValidation := false
 			for _, existing := range existingIngresses {
 				if existing.ObjectMeta.Namespace == ing.ObjectMeta.Namespace && existing.ObjectMeta.Name == ing.ObjectMeta.Name {
 					return nil
 				}
 			}
 
+			if skipValidation {
+				continue
+			}
+
 			// path overlap. Check if one of the ingresses has a canary annotation
 			isCanaryEnabled, annotationErr := parser.GetBoolAnnotation("canary", ing)
 			for _, existing := range existingIngresses {
diff --git a/internal/ingress/controller/controller_test.go b/internal/ingress/controller/controller_test.go
index 34ee87bdb9..86110c3ca5 100644
--- a/internal/ingress/controller/controller_test.go
+++ b/internal/ingress/controller/controller_test.go
@@ -33,9 +33,8 @@ import (
 	"github.com/eapache/channels"
 	corev1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes/fake"
 
 	"k8s.io/ingress-nginx/internal/file"
@@ -47,6 +46,7 @@ import (
 	"k8s.io/ingress-nginx/internal/ingress/annotations/sessionaffinity"
 	"k8s.io/ingress-nginx/internal/ingress/controller/config"
 	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	"k8s.io/ingress-nginx/internal/ingress/controller/store"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
 	"k8s.io/ingress-nginx/internal/ingress/metric"
@@ -190,18 +190,6 @@ func TestCheckIngress(t *testing.T) {
 			},
 		},
 	}
-
-	t.Run("When the ingress class differs from nginx", func(t *testing.T) {
-		ing.ObjectMeta.Annotations["kubernetes.io/ingress.class"] = "different"
-		nginx.command = testNginxTestCommand{
-			t:   t,
-			err: fmt.Errorf("test error"),
-		}
-		if nginx.CheckIngress(ing) != nil {
-			t.Errorf("with a different ingress class, no error should be returned")
-		}
-	})
-
 	t.Run("when the class is the nginx one", func(t *testing.T) {
 		ing.ObjectMeta.Annotations["kubernetes.io/ingress.class"] = "nginx"
 		nginx.command = testNginxTestCommand{
@@ -258,7 +246,7 @@ func TestCheckIngress(t *testing.T) {
 		})
 
 		t.Run("When a new catch-all ingress is being created despite catch-alls being disabled ", func(t *testing.T) {
-			backendBefore := ing.Spec.Backend
+			backendBefore := ing.Spec.DefaultBackend
 			disableCatchAllBefore := nginx.cfg.DisableCatchAll
 
 			nginx.command = testNginxTestCommand{
@@ -267,10 +255,12 @@ func TestCheckIngress(t *testing.T) {
 			}
 			nginx.cfg.DisableCatchAll = true
 
-			ing.Spec.Backend = &networking.IngressBackend{
-				ServiceName: "http-svc",
-				ServicePort: intstr.IntOrString{
-					IntVal: 80,
+			ing.Spec.DefaultBackend = &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: "http-svc",
+					Port: networking.ServiceBackendPort{
+						Number: 80,
+					},
 				},
 			}
 
@@ -279,7 +269,7 @@ func TestCheckIngress(t *testing.T) {
 			}
 
 			// reset backend and catch-all flag
-			ing.Spec.Backend = backendBefore
+			ing.Spec.DefaultBackend = backendBefore
 			nginx.cfg.DisableCatchAll = disableCatchAllBefore
 		})
 
@@ -332,10 +322,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														Type:   intstr.Int,
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -416,10 +407,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "foo-http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														Type:   intstr.Int,
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "foo-http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -436,10 +428,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														Type:   intstr.Int,
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -554,10 +547,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														Type:   intstr.Int,
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -589,10 +583,12 @@ func TestMergeAlternativeBackends(t *testing.T) {
 						Namespace: "example",
 					},
 					Spec: networking.IngressSpec{
-						Backend: &networking.IngressBackend{
-							ServiceName: "http-svc-canary",
-							ServicePort: intstr.IntOrString{
-								IntVal: 80,
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "http-svc-canary",
+								Port: networking.ServiceBackendPort{
+									Number: 80,
+								},
 							},
 						},
 					},
@@ -657,10 +653,12 @@ func TestMergeAlternativeBackends(t *testing.T) {
 						Namespace: "example",
 					},
 					Spec: networking.IngressSpec{
-						Backend: &networking.IngressBackend{
-							ServiceName: "http-svc-canary",
-							ServicePort: intstr.IntOrString{
-								IntVal: 80,
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "http-svc-canary",
+								Port: networking.ServiceBackendPort{
+									Number: 80,
+								},
 							},
 						},
 					},
@@ -721,9 +719,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -804,9 +804,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -913,9 +915,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -1022,9 +1026,11 @@ func TestMergeAlternativeBackends(t *testing.T) {
 												Path:     "/",
 												PathType: &pathTypePrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "http-svc-canary",
-													ServicePort: intstr.IntOrString{
-														IntVal: 80,
+													Service: &networking.IngressServiceBackend{
+														Name: "http-svc-canary",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
 													},
 												},
 											},
@@ -1322,10 +1328,12 @@ func TestGetBackendServers(t *testing.T) {
 							Namespace: "example",
 						},
 						Spec: networking.IngressSpec{
-							Backend: &networking.IngressBackend{
-								ServiceName: "http-svc-canary",
-								ServicePort: intstr.IntOrString{
-									IntVal: 80,
+							DefaultBackend: &networking.IngressBackend{
+								Service: &networking.IngressServiceBackend{
+									Name: "http-svc-canary",
+									Port: networking.ServiceBackendPort{
+										Number: 80,
+									},
 								},
 							},
 						},
@@ -1365,10 +1373,12 @@ func TestGetBackendServers(t *testing.T) {
 							Namespace: "example",
 						},
 						Spec: networking.IngressSpec{
-							Backend: &networking.IngressBackend{
-								ServiceName: "http-svc-canary",
-								ServicePort: intstr.IntOrString{
-									IntVal: 80,
+							DefaultBackend: &networking.IngressBackend{
+								Service: &networking.IngressServiceBackend{
+									Name: "http-svc-canary",
+									Port: networking.ServiceBackendPort{
+										Number: 80,
+									},
 								},
 							},
 						},
@@ -1385,10 +1395,12 @@ func TestGetBackendServers(t *testing.T) {
 							Namespace: "example",
 						},
 						Spec: networking.IngressSpec{
-							Backend: &networking.IngressBackend{
-								ServiceName: "http-svc",
-								ServicePort: intstr.IntOrString{
-									IntVal: 80,
+							DefaultBackend: &networking.IngressBackend{
+								Service: &networking.IngressServiceBackend{
+									Name: "http-svc",
+									Port: networking.ServiceBackendPort{
+										Number: 80,
+									},
 								},
 							},
 						},
@@ -1438,10 +1450,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-canary",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-canary",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1498,10 +1511,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1535,10 +1549,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-canary",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-canary",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1604,10 +1619,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/a",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-1",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-1",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1641,10 +1657,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/a",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-2",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-2",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1678,10 +1695,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/b",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-2",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-2",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1715,10 +1733,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/b",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-1",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-1",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1752,10 +1771,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/c",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-1",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-1",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1789,10 +1809,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/c",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "http-svc-2",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "http-svc-2",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1874,10 +1895,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/path1",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "path1-svc",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "path1-svc",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1914,10 +1936,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/path2",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "path2-svc",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "path2-svc",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -1979,10 +2002,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/path1",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "path1-svc",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "path1-svc",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -2019,10 +2043,11 @@ func TestGetBackendServers(t *testing.T) {
 													Path:     "/path2",
 													PathType: &pathTypePrefix,
 													Backend: networking.IngressBackend{
-														ServiceName: "path2-svc",
-														ServicePort: intstr.IntOrString{
-															Type:   intstr.Int,
-															IntVal: 80,
+														Service: &networking.IngressServiceBackend{
+															Name: "path2-svc",
+															Port: networking.ServiceBackendPort{
+																Number: 80,
+															},
 														},
 													},
 												},
@@ -2075,6 +2100,67 @@ func TestGetBackendServers(t *testing.T) {
 				}
 			},
 		},
+		{
+			Ingresses: []*ingress.Ingress{
+				{
+					Ingress: networking.Ingress{
+						ObjectMeta: metav1.ObjectMeta{
+							Name:      "proxy-ssl-1",
+							Namespace: "proxyssl",
+						},
+						Spec: networking.IngressSpec{
+							Rules: []networking.IngressRule{
+								{
+									Host: "example.com",
+									IngressRuleValue: networking.IngressRuleValue{
+										HTTP: &networking.HTTPIngressRuleValue{
+											Paths: []networking.HTTPIngressPath{
+												{
+													Path:     "/path1",
+													PathType: &pathTypePrefix,
+													Backend:  networking.IngressBackend{},
+												},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+					ParsedAnnotations: &annotations.Ingress{
+						ProxySSL: proxyssl.Config{
+							AuthSSLCert: resolver.AuthSSLCert{
+								CAFileName: "cafile1.crt",
+								Secret:     "secret1",
+							},
+						},
+					},
+				},
+			},
+			Validate: func(ingresses []*ingress.Ingress, upstreams []*ingress.Backend, servers []*ingress.Server) {
+				if len(servers) != 2 {
+					t.Errorf("servers count should be 1, got %d", len(servers))
+					return
+				}
+
+				s := servers[1]
+
+				if s.Locations[0].Backend != "upstream-default-backend" {
+					t.Errorf("backend should be upstream-default-backend, got '%s'", s.Locations[0].Backend)
+				}
+			},
+			SetConfigMap: func(ns string) *v1.ConfigMap {
+				return &v1.ConfigMap{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:     "config",
+						SelfLink: fmt.Sprintf("/api/v1/namespaces/%s/configmaps/config", ns),
+					},
+					Data: map[string]string{
+						"proxy-ssl-location-only": "true",
+					},
+				}
+			},
+		},
 	}
 
 	for _, testCase := range testCases {
@@ -2129,7 +2215,12 @@ func newNGINXController(t *testing.T) *NGINXController {
 		10*time.Minute,
 		clientSet,
 		channels.NewRingChannel(10),
-		false)
+		false,
+		&ingressclass.IngressClassConfiguration{
+			Controller:      "k8s.io/ingress-nginx",
+			AnnotationValue: "nginx",
+		},
+	)
 
 	sslCert := ssl.GetFakeSSLCert()
 	config := &Configuration{
@@ -2187,7 +2278,11 @@ func newDynamicNginxController(t *testing.T, setConfigMap func(string) *v1.Confi
 		10*time.Minute,
 		clientSet,
 		channels.NewRingChannel(10),
-		false)
+		false,
+		&ingressclass.IngressClassConfiguration{
+			Controller:      "k8s.io/ingress-nginx",
+			AnnotationValue: "nginx",
+		})
 
 	sslCert := ssl.GetFakeSSLCert()
 	config := &Configuration{
diff --git a/internal/ingress/controller/ingressclass/ingressclass.go b/internal/ingress/controller/ingressclass/ingressclass.go
new file mode 100644
index 0000000000..025a4e2a5d
--- /dev/null
+++ b/internal/ingress/controller/ingressclass/ingressclass.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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 ingressclass
+
+const (
+	// IngressKey picks a specific "class" for the Ingress.
+	// The controller only processes Ingresses with this annotation either
+	// unset, or set to either the configured value or the empty string.
+	IngressKey = "kubernetes.io/ingress.class"
+
+	// DefaultControllerName defines the default controller name for Ingress NGINX
+	DefaultControllerName = "k8s.io/ingress-nginx"
+
+	// DefaultAnnotationValue defines the default annotation value for the ingress-nginx controller
+	DefaultAnnotationValue = "nginx"
+)
+
+// IngressClassConfiguration defines the various aspects of IngressClass parsing
+// and how the controller should behave in each case
+type IngressClassConfiguration struct {
+	// Controller defines the controller value this daemon watch to.
+	// Defaults to "k8s.io/ingress-nginx" defined in flags
+	Controller string
+	// AnnotationValue defines the annotation value this Controller watch to, in case of the
+	// ingressSpecName is not found but the annotation is.
+	// The Annotation is deprecated and should not be used in future releases
+	AnnotationValue string
+	// WatchWithoutClass defines if Controller should watch to Ingress Objects that does
+	// not contain an IngressClass configuration
+	WatchWithoutClass bool
+}
diff --git a/internal/ingress/controller/location.go b/internal/ingress/controller/location.go
index c5db878c55..d40e88960f 100644
--- a/internal/ingress/controller/location.go
+++ b/internal/ingress/controller/location.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"strings"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/internal/ingress"
 )
 
diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go
index c63af275a7..ba167418f0 100644
--- a/internal/ingress/controller/nginx.go
+++ b/internal/ingress/controller/nginx.go
@@ -49,7 +49,6 @@ import (
 	adm_controller "k8s.io/ingress-nginx/internal/admission/controller"
 	"k8s.io/ingress-nginx/internal/file"
 	"k8s.io/ingress-nginx/internal/ingress"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
 	"k8s.io/ingress-nginx/internal/ingress/controller/process"
 	"k8s.io/ingress-nginx/internal/ingress/controller/store"
@@ -132,7 +131,8 @@ func NewNGINXController(config *Configuration, mc metric.Collector) *NGINXContro
 		config.ResyncPeriod,
 		config.Client,
 		n.updateCh,
-		config.DisableCatchAll)
+		config.DisableCatchAll,
+		config.IngressClassConfiguration)
 
 	n.syncQueue = task.NewTaskQueue(n.syncIngress)
 
@@ -260,10 +260,10 @@ func (n *NGINXController) Start() {
 
 	// we need to use the defined ingress class to allow multiple leaders
 	// in order to update information about ingress status
-	electionID := fmt.Sprintf("%v-%v", n.cfg.ElectionID, class.DefaultClass)
-	if class.IngressClass != "" {
-		electionID = fmt.Sprintf("%v-%v", n.cfg.ElectionID, class.IngressClass)
-	}
+	// TODO: For now, as the the IngressClass logics has changed, is up to the
+	// cluster admin to create different Leader Election IDs.
+	// Should revisit this in a future
+	electionID := n.cfg.ElectionID
 
 	setupLeaderElection(&leaderElectionConfig{
 		Client:     n.cfg.Client,
@@ -519,12 +519,7 @@ func (n *NGINXController) generateTemplate(cfg ngx_config.Configuration, ingress
 	if cfg.MaxWorkerOpenFiles == 0 {
 		// the limit of open files is per worker process
 		// and we leave some room to avoid consuming all the FDs available
-		wp, err := strconv.Atoi(cfg.WorkerProcesses)
-		klog.V(3).InfoS("Worker processes", "count", wp)
-		if err != nil {
-			wp = 1
-		}
-		maxOpenFiles := (rlimitMaxNumFiles() / wp) - 1024
+		maxOpenFiles := rlimitMaxNumFiles() - 1024
 		klog.V(3).InfoS("Maximum number of open file descriptors", "value", maxOpenFiles)
 		if maxOpenFiles < 1024 {
 			// this means the value of RLIMIT_NOFILE is too low.
diff --git a/internal/ingress/controller/store/backend_ssl.go b/internal/ingress/controller/store/backend_ssl.go
index fe9138c6f0..377f620158 100644
--- a/internal/ingress/controller/store/backend_ssl.go
+++ b/internal/ingress/controller/store/backend_ssl.go
@@ -24,7 +24,7 @@ import (
 
 	"github.com/pkg/errors"
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/internal/file"
diff --git a/internal/ingress/controller/store/ingress.go b/internal/ingress/controller/store/ingress.go
index dafc489245..1d8ccb3428 100644
--- a/internal/ingress/controller/store/ingress.go
+++ b/internal/ingress/controller/store/ingress.go
@@ -17,7 +17,7 @@ limitations under the License.
 package store
 
 import (
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/ingress-nginx/internal/ingress"
 )
diff --git a/internal/ingress/controller/store/ingressclass.go b/internal/ingress/controller/store/ingressclass.go
new file mode 100644
index 0000000000..da613d035d
--- /dev/null
+++ b/internal/ingress/controller/store/ingressclass.go
@@ -0,0 +1,39 @@
+/*
+Copyright 2021 The Kubernetes Authors.
+
+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 store
+
+import (
+	networking "k8s.io/api/networking/v1"
+	"k8s.io/client-go/tools/cache"
+)
+
+// IngressClassLister makes a Store that lists IngressClass.
+type IngressClassLister struct {
+	cache.Store
+}
+
+// ByKey returns the Ingress matching key in the local Ingress Store.
+func (il IngressClassLister) ByKey(key string) (*networking.IngressClass, error) {
+	i, exists, err := il.GetByKey(key)
+	if err != nil {
+		return nil, err
+	}
+	if !exists {
+		return nil, NotExistsError(key)
+	}
+	return i.(*networking.IngressClass), nil
+}
diff --git a/internal/ingress/controller/store/store.go b/internal/ingress/controller/store/store.go
index 14096d270d..f65098a21e 100644
--- a/internal/ingress/controller/store/store.go
+++ b/internal/ingress/controller/store/store.go
@@ -28,7 +28,7 @@ import (
 
 	"github.com/eapache/channels"
 	corev1 "k8s.io/api/core/v1"
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
+	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/fields"
 	k8sruntime "k8s.io/apimachinery/pkg/runtime"
@@ -41,14 +41,13 @@ import (
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/client-go/tools/record"
 	"k8s.io/klog/v2"
-	"k8s.io/utils/pointer"
 
 	"k8s.io/ingress-nginx/internal/file"
 	"k8s.io/ingress-nginx/internal/ingress"
 	"k8s.io/ingress-nginx/internal/ingress/annotations"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
 	ngx_config "k8s.io/ingress-nginx/internal/ingress/controller/config"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	ngx_template "k8s.io/ingress-nginx/internal/ingress/controller/template"
 	"k8s.io/ingress-nginx/internal/ingress/defaults"
 	"k8s.io/ingress-nginx/internal/ingress/errors"
@@ -121,16 +120,18 @@ type Event struct {
 
 // Informer defines the required SharedIndexInformers that interact with the API server.
 type Informer struct {
-	Ingress   cache.SharedIndexInformer
-	Endpoint  cache.SharedIndexInformer
-	Service   cache.SharedIndexInformer
-	Secret    cache.SharedIndexInformer
-	ConfigMap cache.SharedIndexInformer
+	Ingress      cache.SharedIndexInformer
+	IngressClass cache.SharedIndexInformer
+	Endpoint     cache.SharedIndexInformer
+	Service      cache.SharedIndexInformer
+	Secret       cache.SharedIndexInformer
+	ConfigMap    cache.SharedIndexInformer
 }
 
 // Lister contains object listers (stores).
 type Lister struct {
 	Ingress               IngressLister
+	IngressClass          IngressClassLister
 	Service               ServiceLister
 	Endpoint              EndpointLister
 	Secret                SecretLister
@@ -150,6 +151,7 @@ func (e NotExistsError) Error() string {
 func (i *Informer) Run(stopCh chan struct{}) {
 	go i.Secret.Run(stopCh)
 	go i.Endpoint.Run(stopCh)
+	go i.IngressClass.Run(stopCh)
 	go i.Service.Run(stopCh)
 	go i.ConfigMap.Run(stopCh)
 
@@ -157,6 +159,7 @@ func (i *Informer) Run(stopCh chan struct{}) {
 	// from the queue
 	if !cache.WaitForCacheSync(stopCh,
 		i.Endpoint.HasSynced,
+		i.IngressClass.HasSynced,
 		i.Service.HasSynced,
 		i.Secret.HasSynced,
 		i.ConfigMap.HasSynced,
@@ -221,7 +224,8 @@ func New(
 	resyncPeriod time.Duration,
 	client clientset.Interface,
 	updateCh *channels.RingChannel,
-	disableCatchAll bool) Storer {
+	disableCatchAll bool,
+	icConfig *ingressclass.IngressClassConfiguration) Storer {
 
 	store := &k8sStore{
 		informers:             &Informer{},
@@ -293,9 +297,12 @@ func New(
 		informers.WithTweakListOptions(secretsTweakListOptionsFunc),
 	)
 
-	store.informers.Ingress = infFactory.Networking().V1beta1().Ingresses().Informer()
+	store.informers.Ingress = infFactory.Networking().V1().Ingresses().Informer()
 	store.listers.Ingress.Store = store.informers.Ingress.GetStore()
 
+	store.informers.IngressClass = infFactory.Networking().V1().IngressClasses().Informer()
+	store.listers.IngressClass.Store = cache.NewStore(cache.MetaNamespaceKeyFunc)
+
 	store.informers.Endpoint = infFactory.Core().V1().Endpoints().Informer()
 	store.listers.Endpoint.Store = store.informers.Endpoint.GetStore()
 
@@ -317,14 +324,16 @@ func New(
 				klog.ErrorS(nil, "Error obtaining object from tombstone", "key", obj)
 				return
 			}
-			ing, ok = tombstone.Obj.(*networkingv1beta1.Ingress)
+			ing, ok = tombstone.Obj.(*networkingv1.Ingress)
 			if !ok {
 				klog.Errorf("Tombstone contained object that is not an Ingress: %#v", obj)
 				return
 			}
 		}
 
-		if !class.IsValid(ing) {
+		_, err := store.GetIngressClass(ing, icConfig)
+		if err != nil {
+			klog.InfoS("Ignoring ingress because of error while validating ingress class", "ingress", klog.KObj(ing), "error", err)
 			return
 		}
 
@@ -347,12 +356,14 @@ func New(
 	ingEventHandler := cache.ResourceEventHandlerFuncs{
 		AddFunc: func(obj interface{}) {
 			ing, _ := toIngress(obj)
-			if !class.IsValid(ing) {
-				ingressClass, _ := parser.GetStringAnnotation(class.IngressKey, ing)
-				klog.InfoS("Ignoring ingress", "ingress", klog.KObj(ing), "kubernetes.io/ingress.class", ingressClass, "ingressClassName", pointer.StringPtrDerefOr(ing.Spec.IngressClassName, ""))
+			ic, err := store.GetIngressClass(ing, icConfig)
+			if err != nil {
+				klog.InfoS("Ignoring ingress because of error while validating ingress class", "ingress", klog.KObj(ing), "error", err)
 				return
 			}
 
+			klog.InfoS("Found valid IngressClass", "ingress", klog.KObj(ing), "ingressclass", ic)
+
 			if hasCatchAllIngressRule(ing.Spec) && disableCatchAll {
 				klog.InfoS("Ignoring add for catch-all ingress because of --disable-catch-all", "ingress", klog.KObj(ing))
 				return
@@ -374,21 +385,21 @@ func New(
 			oldIng, _ := toIngress(old)
 			curIng, _ := toIngress(cur)
 
-			validOld := class.IsValid(oldIng)
-			validCur := class.IsValid(curIng)
-			if !validOld && validCur {
+			_, errOld := store.GetIngressClass(oldIng, icConfig)
+			classCur, errCur := store.GetIngressClass(curIng, icConfig)
+			if errOld != nil && errCur == nil {
 				if hasCatchAllIngressRule(curIng.Spec) && disableCatchAll {
 					klog.InfoS("ignoring update for catch-all ingress because of --disable-catch-all", "ingress", klog.KObj(curIng))
 					return
 				}
 
-				klog.InfoS("creating ingress", "ingress", klog.KObj(curIng), "class", class.IngressKey)
+				klog.InfoS("creating ingress", "ingress", klog.KObj(curIng), "ingressclass", classCur)
 				recorder.Eventf(curIng, corev1.EventTypeNormal, "Sync", "Scheduled for sync")
-			} else if validOld && !validCur {
-				klog.InfoS("removing ingress", "ingress", klog.KObj(curIng), "class", class.IngressKey)
+			} else if errOld == nil && errCur != nil {
+				klog.InfoS("removing ingress because of unknown ingressclass", "ingress", klog.KObj(curIng))
 				ingDeleteHandler(old)
 				return
-			} else if validCur && !reflect.DeepEqual(old, cur) {
+			} else if errCur == nil && !reflect.DeepEqual(old, cur) {
 				if hasCatchAllIngressRule(curIng.Spec) && disableCatchAll {
 					klog.InfoS("ignoring update for catch-all ingress and delete old one because of --disable-catch-all", "ingress", klog.KObj(curIng))
 					ingDeleteHandler(old)
@@ -412,6 +423,63 @@ func New(
 		},
 	}
 
+	ingressClassEventHandler := cache.ResourceEventHandlerFuncs{
+		AddFunc: func(obj interface{}) {
+			ingressclass := obj.(*networkingv1.IngressClass)
+			if ingressclass.Spec.Controller != icConfig.Controller {
+				klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(ingressclass))
+				return
+			}
+			err := store.listers.IngressClass.Add(ingressclass)
+			if err != nil {
+				klog.InfoS("error adding ingressclass to store", "ingressclass", klog.KObj(ingressclass), "error", err)
+				return
+			}
+
+			updateCh.In() <- Event{
+				Type: CreateEvent,
+				Obj:  obj,
+			}
+		},
+		DeleteFunc: func(obj interface{}) {
+			ingressclass := obj.(*networkingv1.IngressClass)
+			if ingressclass.Spec.Controller != icConfig.Controller {
+				klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(ingressclass))
+				return
+			}
+			err := store.listers.IngressClass.Delete(ingressclass)
+			if err != nil {
+				klog.InfoS("error removing ingressclass from store", "ingressclass", klog.KObj(ingressclass), "error", err)
+				return
+			}
+			updateCh.In() <- Event{
+				Type: DeleteEvent,
+				Obj:  obj,
+			}
+		},
+		UpdateFunc: func(old, cur interface{}) {
+			oic := old.(*networkingv1.IngressClass)
+			cic := cur.(*networkingv1.IngressClass)
+			if cic.Spec.Controller != icConfig.Controller {
+				klog.InfoS("ignoring ingressclass as the spec.controller is not the same of this ingress", "ingressclass", klog.KObj(cic))
+				return
+			}
+			// TODO: In a future we might be interested in parse parameters and use as
+			// current IngressClass for this case, crossing with configmap
+			if !reflect.DeepEqual(cic.Spec.Parameters, oic.Spec.Parameters) {
+				err := store.listers.IngressClass.Update(cic)
+				if err != nil {
+					klog.InfoS("error updating ingressclass in store", "ingressclass", klog.KObj(cic), "error", err)
+					return
+				}
+				updateCh.In() <- Event{
+					Type: UpdateEvent,
+					Obj:  cur,
+				}
+			}
+		},
+	}
+
 	secrEventHandler := cache.ResourceEventHandlerFuncs{
 		AddFunc: func(obj interface{}) {
 			sec := obj.(*corev1.Secret)
@@ -608,6 +676,7 @@ func New(
 	}
 
 	store.informers.Ingress.AddEventHandler(ingEventHandler)
+	store.informers.IngressClass.AddEventHandler(ingressClassEventHandler)
 	store.informers.Endpoint.AddEventHandler(epEventHandler)
 	store.informers.Secret.AddEventHandler(secrEventHandler)
 	store.informers.ConfigMap.AddEventHandler(cmEventHandler)
@@ -626,17 +695,17 @@ func New(
 
 // hasCatchAllIngressRule returns whether or not an ingress produces a
 // catch-all server, and so should be ignored when --disable-catch-all is set
-func hasCatchAllIngressRule(spec networkingv1beta1.IngressSpec) bool {
-	return spec.Backend != nil
+func hasCatchAllIngressRule(spec networkingv1.IngressSpec) bool {
+	return spec.DefaultBackend != nil
 }
 
 // syncIngress parses ingress annotations converting the value of the
 // annotation to a go struct
-func (s *k8sStore) syncIngress(ing *networkingv1beta1.Ingress) {
+func (s *k8sStore) syncIngress(ing *networkingv1.Ingress) {
 	key := k8s.MetaNamespaceKey(ing)
 	klog.V(3).Infof("updating annotations information for ingress %v", key)
 
-	copyIng := &networkingv1beta1.Ingress{}
+	copyIng := &networkingv1.Ingress{}
 	ing.ObjectMeta.DeepCopyInto(&copyIng.ObjectMeta)
 	ing.Spec.DeepCopyInto(&copyIng.Spec)
 	ing.Status.DeepCopyInto(&copyIng.Status)
@@ -666,7 +735,7 @@ func (s *k8sStore) syncIngress(ing *networkingv1beta1.Ingress) {
 
 // updateSecretIngressMap takes an Ingress and updates all Secret objects it
 // references in secretIngressMap.
-func (s *k8sStore) updateSecretIngressMap(ing *networkingv1beta1.Ingress) {
+func (s *k8sStore) updateSecretIngressMap(ing *networkingv1.Ingress) {
 	key := k8s.MetaNamespaceKey(ing)
 	klog.V(3).Infof("updating references to secrets for ingress %v", key)
 
@@ -710,7 +779,7 @@ func (s *k8sStore) updateSecretIngressMap(ing *networkingv1beta1.Ingress) {
 
 // objectRefAnnotationNsKey returns an object reference formatted as a
 // 'namespace/name' key from the given annotation name.
-func objectRefAnnotationNsKey(ann string, ing *networkingv1beta1.Ingress) (string, error) {
+func objectRefAnnotationNsKey(ann string, ing *networkingv1.Ingress) (string, error) {
 	annValue, err := parser.GetStringAnnotation(ann, ing)
 	if err != nil {
 		return "", err
@@ -729,7 +798,7 @@ func objectRefAnnotationNsKey(ann string, ing *networkingv1beta1.Ingress) (strin
 
 // syncSecrets synchronizes data from all Secrets referenced by the given
 // Ingress with the local store and file system.
-func (s *k8sStore) syncSecrets(ing *networkingv1beta1.Ingress) {
+func (s *k8sStore) syncSecrets(ing *networkingv1.Ingress) {
 	key := k8s.MetaNamespaceKey(ing)
 	for _, secrKey := range s.secretIngressMap.ReferencedBy(key) {
 		s.syncSecret(secrKey)
@@ -758,8 +827,34 @@ func (s *k8sStore) GetService(key string) (*corev1.Service, error) {
 	return s.listers.Service.ByKey(key)
 }
 
+func (s *k8sStore) GetIngressClass(ing *networkingv1.Ingress, icConfig *ingressclass.IngressClassConfiguration) (string, error) {
+	// First we try ingressClassName
+	if ing.Spec.IngressClassName != nil {
+		iclass, err := s.listers.IngressClass.ByKey(*ing.Spec.IngressClassName)
+		if err != nil {
+			return "", err
+		}
+		return iclass.Name, nil
+	}
+
+	// Then we try annotation
+	if ingressclass, ok := ing.GetAnnotations()[ingressclass.IngressKey]; ok {
+		if ingressclass != icConfig.AnnotationValue {
+			return "", fmt.Errorf("ingress class annotation is not equal to the expected by Ingress Controller")
+		}
+		return ingressclass, nil
+	}
+
+	// Then we accept if the WithoutClass is enabled
+	if icConfig.WatchWithoutClass {
+		// Reserving "_" as a "wildcard" name
+		return "_", nil
+	}
+	return "", fmt.Errorf("ingress does not contain a valid IngressClass")
+}
+
 // getIngress returns the Ingress matching key.
-func (s *k8sStore) getIngress(key string) (*networkingv1beta1.Ingress, error) {
+func (s *k8sStore) getIngress(key string) (*networkingv1.Ingress, error) {
 	ing, err := s.listers.IngressWithAnnotation.ByKey(key)
 	if err != nil {
 		return nil, err
@@ -900,11 +995,11 @@ func (s *k8sStore) Run(stopCh chan struct{}) {
 var runtimeScheme = k8sruntime.NewScheme()
 
 func init() {
-	utilruntime.Must(networkingv1beta1.AddToScheme(runtimeScheme))
+	utilruntime.Must(networkingv1.AddToScheme(runtimeScheme))
 }
 
-func toIngress(obj interface{}) (*networkingv1beta1.Ingress, bool) {
-	if ing, ok := obj.(*networkingv1beta1.Ingress); ok {
+func toIngress(obj interface{}) (*networkingv1.Ingress, bool) {
+	if ing, ok := obj.(*networkingv1.Ingress); ok {
 		k8s.SetDefaultNGINXPathType(ing)
 		return ing, true
 	}
diff --git a/internal/ingress/controller/store/store_test.go b/internal/ingress/controller/store/store_test.go
index 963d36af66..35e5955b11 100644
--- a/internal/ingress/controller/store/store_test.go
+++ b/internal/ingress/controller/store/store_test.go
@@ -28,24 +28,61 @@ import (
 
 	"github.com/eapache/channels"
 	v1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/cache"
 	"sigs.k8s.io/controller-runtime/pkg/envtest"
 
 	"k8s.io/ingress-nginx/internal/ingress"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
+var pathPrefix networking.PathType = networking.PathTypePrefix
+
+var DefaultClassConfig = &ingressclass.IngressClassConfiguration{
+	Controller:        ingressclass.DefaultControllerName,
+	AnnotationValue:   ingressclass.DefaultAnnotationValue,
+	WatchWithoutClass: false,
+}
+
+var (
+	commonIngressSpec = networking.IngressSpec{
+		Rules: []networking.IngressRule{
+			{
+				Host: "dummy",
+				IngressRuleValue: networking.IngressRuleValue{
+					HTTP: &networking.HTTPIngressRuleValue{
+						Paths: []networking.HTTPIngressPath{
+							{
+								Path:     "/",
+								PathType: &pathPrefix,
+								Backend: networking.IngressBackend{
+									Service: &networking.IngressServiceBackend{
+										Name: "http-svc",
+										Port: networking.ServiceBackendPort{
+											Number: 80,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+)
+
 func TestStore(t *testing.T) {
 	//TODO: move env definition to docker image?
 	os.Setenv("KUBEBUILDER_ASSETS", "/usr/local/bin")
 
+	pathPrefix = networking.PathTypePrefix
+
 	te := &envtest.Environment{}
 	cfg, err := te.Start()
 	if err != nil {
@@ -82,7 +119,8 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
 
@@ -108,13 +146,14 @@ func TestStore(t *testing.T) {
 			t.Errorf("expected an error but none returned")
 		}
 		if svc != nil {
-			t.Errorf("expected an Ingres but none returned")
+			t.Errorf("expected an Ingress but none returned")
 		}
 	})
 
-	t.Run("should return one event for add, update and delete of ingress", func(t *testing.T) {
+	t.Run("should return no event for add, update and delete of ingress as the existing ingressclass is not the expected", func(t *testing.T) {
 		ns := createNamespace(clientSet, t)
 		defer deleteNamespace(ns, clientSet, t)
+
 		createConfigMap(clientSet, ns, t)
 
 		stopCh := make(chan struct{})
@@ -159,35 +198,120 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
-
+		ic := createIngressClass(clientSet, t, "not-k8s.io/not-ingress-nginx")
+		defer deleteIngressClass(ic, clientSet, t)
+		validSpec := commonIngressSpec
+		validSpec.IngressClassName = &ic
 		ing := ensureIngress(&networking.Ingress{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "dummy",
+				Name:      "dummy-no-class",
 				Namespace: ns,
 			},
-			Spec: networking.IngressSpec{
-				Rules: []networking.IngressRule{
-					{
-						Host: "dummy",
-						IngressRuleValue: networking.IngressRuleValue{
-							HTTP: &networking.HTTPIngressRuleValue{
-								Paths: []networking.HTTPIngressPath{
-									{
-										Path: "/",
-										Backend: networking.IngressBackend{
-											ServiceName: "http-svc",
-											ServicePort: intstr.FromInt(80),
-										},
-									},
-								},
-							},
-						},
-					},
-				},
+			Spec: validSpec,
+		}, clientSet, t)
+
+		err := framework.WaitForIngressInNamespace(clientSet, ns, ing.Name)
+		if err != nil {
+			t.Errorf("error waiting for secret: %v", err)
+		}
+		time.Sleep(1 * time.Second)
+
+		ni := ing.DeepCopy()
+		ni.Spec.Rules[0].Host = "update-dummy"
+		_ = ensureIngress(ni, clientSet, t)
+		if err != nil {
+			t.Errorf("error creating ingress: %v", err)
+		}
+		// Secret takes a bit to update
+		time.Sleep(3 * time.Second)
+
+		err = clientSet.NetworkingV1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
+		if err != nil {
+			t.Errorf("error deleting ingress: %v", err)
+		}
+
+		err = framework.WaitForNoIngressInNamespace(clientSet, ni.Namespace, ni.Name)
+		if err != nil {
+			t.Errorf("error waiting for secret: %v", err)
+		}
+		time.Sleep(1 * time.Second)
+
+		if atomic.LoadUint64(&add) != 0 {
+			t.Errorf("expected 0 event of type Create but %v occurred", add)
+		}
+		if atomic.LoadUint64(&upd) != 0 {
+			t.Errorf("expected 0 event of type Update but %v occurred", upd)
+		}
+		if atomic.LoadUint64(&del) != 0 {
+			t.Errorf("expected 0 event of type Delete but %v occurred", del)
+		}
+	})
+
+	t.Run("should return one event for add, update and delete of ingress", func(t *testing.T) {
+		ns := createNamespace(clientSet, t)
+		defer deleteNamespace(ns, clientSet, t)
+		ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
+		defer deleteIngressClass(ic, clientSet, t)
+		createConfigMap(clientSet, ns, t)
+
+		stopCh := make(chan struct{})
+		updateCh := channels.NewRingChannel(1024)
+
+		var add uint64
+		var upd uint64
+		var del uint64
+
+		go func(ch *channels.RingChannel) {
+			for {
+				evt, ok := <-ch.Out()
+				if !ok {
+					return
+				}
+
+				e := evt.(Event)
+				if e.Obj == nil {
+					continue
+				}
+				if _, ok := e.Obj.(*networking.Ingress); !ok {
+					continue
+				}
+
+				switch e.Type {
+				case CreateEvent:
+					atomic.AddUint64(&add, 1)
+				case UpdateEvent:
+					atomic.AddUint64(&upd, 1)
+				case DeleteEvent:
+					atomic.AddUint64(&del, 1)
+				}
+			}
+		}(updateCh)
+
+		storer := New(
+			ns,
+			fmt.Sprintf("%v/config", ns),
+			fmt.Sprintf("%v/tcp", ns),
+			fmt.Sprintf("%v/udp", ns),
+			"",
+			10*time.Minute,
+			clientSet,
+			updateCh,
+			false,
+			DefaultClassConfig)
+
+		storer.Run(stopCh)
+		validSpec := commonIngressSpec
+		validSpec.IngressClassName = &ic
+		ing := ensureIngress(&networking.Ingress{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "dummy-class",
+				Namespace: ns,
 			},
+			Spec: validSpec,
 		}, clientSet, t)
 
 		err := framework.WaitForIngressInNamespace(clientSet, ns, ing.Name)
@@ -196,35 +320,13 @@ func TestStore(t *testing.T) {
 		}
 		time.Sleep(1 * time.Second)
 
-		// create an invalid ingress (different class)
+		// create an invalid ingress (no ingress class and no watchWithoutClass config)
 		invalidIngress := ensureIngress(&networking.Ingress{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "custom-class",
+				Name:      "no-class",
 				Namespace: ns,
-				Annotations: map[string]string{
-					class.IngressKey: "something",
-				},
-			},
-			Spec: networking.IngressSpec{
-				Rules: []networking.IngressRule{
-					{
-						Host: "dummy",
-						IngressRuleValue: networking.IngressRuleValue{
-							HTTP: &networking.HTTPIngressRuleValue{
-								Paths: []networking.HTTPIngressPath{
-									{
-										Path: "/",
-										Backend: networking.IngressBackend{
-											ServiceName: "http-svc",
-											ServicePort: intstr.FromInt(80),
-										},
-									},
-								},
-							},
-						},
-					},
-				},
 			},
+			Spec: commonIngressSpec,
 		}, clientSet, t)
 		defer deleteIngress(invalidIngress, clientSet, t)
 
@@ -237,9 +339,9 @@ func TestStore(t *testing.T) {
 		// Secret takes a bit to update
 		time.Sleep(3 * time.Second)
 
-		err = clientSet.NetworkingV1beta1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
+		err = clientSet.NetworkingV1().Ingresses(ni.Namespace).Delete(context.TODO(), ni.Name, metav1.DeleteOptions{})
 		if err != nil {
-			t.Errorf("error creating ingress: %v", err)
+			t.Errorf("error deleting ingress: %v", err)
 		}
 
 		err = framework.WaitForNoIngressInNamespace(clientSet, ni.Namespace, ni.Name)
@@ -259,7 +361,132 @@ func TestStore(t *testing.T) {
 		}
 	})
 
-	t.Run("should not receive updates for ingress with invalid class", func(t *testing.T) {
+	t.Run("should return two events for add and delete and one for update of ingress and watch-without-class", func(t *testing.T) {
+		ns := createNamespace(clientSet, t)
+		defer deleteNamespace(ns, clientSet, t)
+		createConfigMap(clientSet, ns, t)
+
+		stopCh := make(chan struct{})
+		updateCh := channels.NewRingChannel(1024)
+
+		var add uint64
+		var upd uint64
+		var del uint64
+
+		go func(ch *channels.RingChannel) {
+			for {
+				evt, ok := <-ch.Out()
+				if !ok {
+					return
+				}
+
+				e := evt.(Event)
+				if e.Obj == nil {
+					continue
+				}
+				if _, ok := e.Obj.(*networking.Ingress); !ok {
+					continue
+				}
+
+				switch e.Type {
+				case CreateEvent:
+					atomic.AddUint64(&add, 1)
+				case UpdateEvent:
+					atomic.AddUint64(&upd, 1)
+				case DeleteEvent:
+					atomic.AddUint64(&del, 1)
+				}
+			}
+		}(updateCh)
+
+		ingressClassconfig := &ingressclass.IngressClassConfiguration{
+			Controller:        ingressclass.DefaultControllerName,
+			AnnotationValue:   ingressclass.DefaultAnnotationValue,
+			WatchWithoutClass: true,
+		}
+
+		storer := New(
+			ns,
+			fmt.Sprintf("%v/config", ns),
+			fmt.Sprintf("%v/tcp", ns),
+			fmt.Sprintf("%v/udp", ns),
+			"",
+			10*time.Minute,
+			clientSet,
+			updateCh,
+			false,
+			ingressClassconfig)
+
+		storer.Run(stopCh)
+
+		validIngress1 := ensureIngress(&networking.Ingress{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "ing1",
+				Namespace: ns,
+			},
+			Spec: commonIngressSpec,
+		}, clientSet, t)
+		err := framework.WaitForIngressInNamespace(clientSet, ns, validIngress1.Name)
+		if err != nil {
+			t.Errorf("error waiting for ingress: %v", err)
+		}
+
+		otherIngress := commonIngressSpec
+		otherIngress.Rules[0].Host = "other-ingress"
+		validIngress2 := ensureIngress(&networking.Ingress{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "ing2",
+				Namespace: ns,
+			},
+			Spec: otherIngress,
+		}, clientSet, t)
+		err = framework.WaitForIngressInNamespace(clientSet, ns, validIngress2.Name)
+		if err != nil {
+			t.Errorf("error waiting for ingress: %v", err)
+		}
+
+		time.Sleep(1 * time.Second)
+
+		validIngressUpdated := validIngress1.DeepCopy()
+		validIngressUpdated.Spec.Rules[0].Host = "update-dummy"
+		_ = ensureIngress(validIngressUpdated, clientSet, t)
+		if err != nil {
+			t.Errorf("error updating ingress: %v", err)
+		}
+		// Secret takes a bit to update
+		time.Sleep(3 * time.Second)
+
+		err = clientSet.NetworkingV1().Ingresses(validIngressUpdated.Namespace).Delete(context.TODO(), validIngressUpdated.Name, metav1.DeleteOptions{})
+		if err != nil {
+			t.Errorf("error deleting ingress: %v", err)
+		}
+		err = clientSet.NetworkingV1().Ingresses(validIngress2.Namespace).Delete(context.TODO(), validIngress2.Name, metav1.DeleteOptions{})
+		if err != nil {
+			t.Errorf("error deleting ingress: %v", err)
+		}
+
+		err = framework.WaitForNoIngressInNamespace(clientSet, validIngressUpdated.Namespace, validIngressUpdated.Name)
+		if err != nil {
+			t.Errorf("error waiting for ingress deletion: %v", err)
+		}
+		err = framework.WaitForNoIngressInNamespace(clientSet, validIngress2.Namespace, validIngress2.Name)
+		if err != nil {
+			t.Errorf("error waiting for ingress deletion: %v", err)
+		}
+		time.Sleep(1 * time.Second)
+
+		if atomic.LoadUint64(&add) != 2 {
+			t.Errorf("expected 0 event of type Create but %v occurred", add)
+		}
+		if atomic.LoadUint64(&upd) != 1 {
+			t.Errorf("expected 0 event of type Update but %v occurred", upd)
+		}
+		if atomic.LoadUint64(&del) != 2 {
+			t.Errorf("expected 0 event of type Delete but %v occurred", del)
+		}
+	})
+
+	t.Run("should not receive updates for ingress with invalid class annotation", func(t *testing.T) {
 		ns := createNamespace(clientSet, t)
 		defer deleteNamespace(ns, clientSet, t)
 		createConfigMap(clientSet, ns, t)
@@ -271,6 +498,7 @@ func TestStore(t *testing.T) {
 		var upd uint64
 		var del uint64
 
+		// TODO: This repeats a lot, transform in a local function
 		go func(ch *channels.RingChannel) {
 			for {
 				evt, ok := <-ch.Out()
@@ -306,7 +534,8 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
 
@@ -316,29 +545,101 @@ func TestStore(t *testing.T) {
 				Name:      "custom-class",
 				Namespace: ns,
 				Annotations: map[string]string{
-					class.IngressKey: "something",
+					ingressclass.IngressKey: "something",
 				},
 			},
-			Spec: networking.IngressSpec{
-				Rules: []networking.IngressRule{
-					{
-						Host: "dummy",
-						IngressRuleValue: networking.IngressRuleValue{
-							HTTP: &networking.HTTPIngressRuleValue{
-								Paths: []networking.HTTPIngressPath{
-									{
-										Path: "/",
-										Backend: networking.IngressBackend{
-											ServiceName: "http-svc",
-											ServicePort: intstr.FromInt(80),
-										},
-									},
-								},
-							},
-						},
-					},
-				},
+			Spec: commonIngressSpec,
+		}, clientSet, t)
+		err := framework.WaitForIngressInNamespace(clientSet, ns, invalidIngress.Name)
+		if err != nil {
+			t.Errorf("error waiting for ingress: %v", err)
+		}
+		time.Sleep(1 * time.Second)
+
+		invalidIngressUpdated := invalidIngress.DeepCopy()
+		invalidIngressUpdated.Spec.Rules[0].Host = "update-dummy"
+		_ = ensureIngress(invalidIngressUpdated, clientSet, t)
+		if err != nil {
+			t.Errorf("error creating ingress: %v", err)
+		}
+		// Secret takes a bit to update
+		time.Sleep(3 * time.Second)
+
+		if atomic.LoadUint64(&add) != 0 {
+			t.Errorf("expected 0 event of type Create but %v occurred", add)
+		}
+		if atomic.LoadUint64(&upd) != 0 {
+			t.Errorf("expected 0 event of type Update but %v occurred", upd)
+		}
+		if atomic.LoadUint64(&del) != 0 {
+			t.Errorf("expected 0 event of type Delete but %v occurred", del)
+		}
+	})
+
+	t.Run("should not receive updates for ingress with invalid class specification", func(t *testing.T) {
+		ns := createNamespace(clientSet, t)
+		defer deleteNamespace(ns, clientSet, t)
+		ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
+		defer deleteIngressClass(ic, clientSet, t)
+
+		createConfigMap(clientSet, ns, t)
+
+		stopCh := make(chan struct{})
+		updateCh := channels.NewRingChannel(1024)
+
+		var add uint64
+		var upd uint64
+		var del uint64
+
+		go func(ch *channels.RingChannel) {
+			for {
+				evt, ok := <-ch.Out()
+				if !ok {
+					return
+				}
+
+				e := evt.(Event)
+				if e.Obj == nil {
+					continue
+				}
+				if _, ok := e.Obj.(*networking.Ingress); !ok {
+					continue
+				}
+
+				switch e.Type {
+				case CreateEvent:
+					atomic.AddUint64(&add, 1)
+				case UpdateEvent:
+					atomic.AddUint64(&upd, 1)
+				case DeleteEvent:
+					atomic.AddUint64(&del, 1)
+				}
+			}
+		}(updateCh)
+
+		storer := New(
+			ns,
+			fmt.Sprintf("%v/config", ns),
+			fmt.Sprintf("%v/tcp", ns),
+			fmt.Sprintf("%v/udp", ns),
+			"",
+			10*time.Minute,
+			clientSet,
+			updateCh,
+			false,
+			DefaultClassConfig)
+
+		storer.Run(stopCh)
+		invalidSpec := commonIngressSpec
+		invalidClassName := "blo123"
+		invalidSpec.IngressClassName = &invalidClassName
+		// create an invalid ingress (different class)
+		invalidIngress := ensureIngress(&networking.Ingress{
+			ObjectMeta: metav1.ObjectMeta{
+				Name:      "custom-class",
+				Namespace: ns,
 			},
+			Spec: invalidSpec,
 		}, clientSet, t)
 		err := framework.WaitForIngressInNamespace(clientSet, ns, invalidIngress.Name)
 		if err != nil {
@@ -409,7 +710,8 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
 
@@ -455,6 +757,8 @@ func TestStore(t *testing.T) {
 	t.Run("should receive events from secret referenced from ingress", func(t *testing.T) {
 		ns := createNamespace(clientSet, t)
 		defer deleteNamespace(ns, clientSet, t)
+		ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
+		defer deleteIngressClass(ic, clientSet, t)
 		createConfigMap(clientSet, ns, t)
 
 		stopCh := make(chan struct{})
@@ -475,6 +779,11 @@ func TestStore(t *testing.T) {
 				if e.Obj == nil {
 					continue
 				}
+
+				// We should skip IngressClass events
+				if _, ok := e.Obj.(*networking.IngressClass); ok {
+					continue
+				}
 				switch e.Type {
 				case CreateEvent:
 					atomic.AddUint64(&add, 1)
@@ -495,7 +804,8 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
 
@@ -508,14 +818,19 @@ func TestStore(t *testing.T) {
 				Namespace: ns,
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: &ic,
 				TLS: []networking.IngressTLS{
 					{
 						SecretName: secretName,
 					},
 				},
-				Backend: &networking.IngressBackend{
-					ServiceName: "http-svc",
-					ServicePort: intstr.FromInt(80),
+				DefaultBackend: &networking.IngressBackend{
+					Service: &networking.IngressServiceBackend{
+						Name: "http-svc",
+						Port: networking.ServiceBackendPort{
+							Number: 80,
+						},
+					},
 				},
 			},
 		}, clientSet, t)
@@ -563,6 +878,8 @@ func TestStore(t *testing.T) {
 	t.Run("should create an ingress with a secret which does not exist", func(t *testing.T) {
 		ns := createNamespace(clientSet, t)
 		defer deleteNamespace(ns, clientSet, t)
+		ic := createIngressClass(clientSet, t, ingressclass.DefaultControllerName)
+		defer deleteIngressClass(ic, clientSet, t)
 		createConfigMap(clientSet, ns, t)
 
 		stopCh := make(chan struct{})
@@ -583,6 +900,12 @@ func TestStore(t *testing.T) {
 				if e.Obj == nil {
 					continue
 				}
+
+				// We should skip IngressClass objects here
+				if _, ok := e.Obj.(*networking.IngressClass); ok {
+					continue
+				}
+
 				switch e.Type {
 				case CreateEvent:
 					atomic.AddUint64(&add, 1)
@@ -603,7 +926,8 @@ func TestStore(t *testing.T) {
 			10*time.Minute,
 			clientSet,
 			updateCh,
-			false)
+			false,
+			DefaultClassConfig)
 
 		storer.Run(stopCh)
 
@@ -616,6 +940,7 @@ func TestStore(t *testing.T) {
 				Namespace: ns,
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: &ic,
 				TLS: []networking.IngressTLS{
 					{
 						Hosts:      secretHosts,
@@ -629,10 +954,15 @@ func TestStore(t *testing.T) {
 							HTTP: &networking.HTTPIngressRuleValue{
 								Paths: []networking.HTTPIngressPath{
 									{
-										Path: "/",
+										Path:     "/",
+										PathType: &pathPrefix,
 										Backend: networking.IngressBackend{
-											ServiceName: "http-svc",
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: "http-svc",
+												Port: networking.ServiceBackendPort{
+													Number: 80,
+												},
+											},
 										},
 									},
 								},
@@ -705,6 +1035,33 @@ func deleteNamespace(ns string, clientSet kubernetes.Interface, t *testing.T) {
 	}
 }
 
+func createIngressClass(clientSet kubernetes.Interface, t *testing.T, controller string) string {
+	t.Helper()
+	ingressclass := &networking.IngressClass{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf("ingress-nginx-%v", time.Now().Unix()),
+			//Namespace: "xpto" // TODO: We don't support namespaced ingress-class yet
+		},
+		Spec: networking.IngressClassSpec{
+			Controller: controller,
+		},
+	}
+	ic, err := clientSet.NetworkingV1().IngressClasses().Create(context.TODO(), ingressclass, metav1.CreateOptions{})
+	if err != nil {
+		t.Errorf("error creating ingress class: %v", err)
+	}
+	return ic.Name
+}
+
+func deleteIngressClass(ic string, clientSet kubernetes.Interface, t *testing.T) {
+	t.Helper()
+
+	err := clientSet.NetworkingV1().IngressClasses().Delete(context.TODO(), ic, metav1.DeleteOptions{})
+	if err != nil {
+		t.Errorf("error deleting the ingress class: %v", err)
+	}
+}
+
 func createConfigMap(clientSet kubernetes.Interface, ns string, t *testing.T) string {
 	t.Helper()
 
@@ -724,13 +1081,13 @@ func createConfigMap(clientSet kubernetes.Interface, ns string, t *testing.T) st
 
 func ensureIngress(ingress *networking.Ingress, clientSet kubernetes.Interface, t *testing.T) *networking.Ingress {
 	t.Helper()
-	ing, err := clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
+	ing, err := clientSet.NetworkingV1().Ingresses(ingress.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
 
 	if err != nil {
 		if k8sErrors.IsNotFound(err) {
 			t.Logf("Ingress %v not found, creating", ingress)
 
-			ing, err = clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Create(context.TODO(), ingress, metav1.CreateOptions{})
+			ing, err = clientSet.NetworkingV1().Ingresses(ingress.Namespace).Create(context.TODO(), ingress, metav1.CreateOptions{})
 			if err != nil {
 				t.Fatalf("error creating ingress %+v: %v", ingress, err)
 			}
@@ -747,7 +1104,7 @@ func ensureIngress(ingress *networking.Ingress, clientSet kubernetes.Interface,
 
 func deleteIngress(ingress *networking.Ingress, clientSet kubernetes.Interface, t *testing.T) {
 	t.Helper()
-	err := clientSet.NetworkingV1beta1().Ingresses(ingress.Namespace).Delete(context.TODO(), ingress.Name, metav1.DeleteOptions{})
+	err := clientSet.NetworkingV1().Ingresses(ingress.Namespace).Delete(context.TODO(), ingress.Name, metav1.DeleteOptions{})
 
 	if err != nil {
 		t.Errorf("failed to delete ingress %+v: %v", ingress, err)
@@ -762,6 +1119,7 @@ func newStore(t *testing.T) *k8sStore {
 	return &k8sStore{
 		listers: &Lister{
 			// add more listers if needed
+			IngressClass:          IngressClassLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
 			Ingress:               IngressLister{cache.NewStore(cache.MetaNamespaceKeyFunc)},
 			IngressWithAnnotation: IngressWithAnnotationsLister{cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)},
 		},
@@ -839,21 +1197,25 @@ func TestUpdateSecretIngressMap(t *testing.T) {
 
 func TestListIngresses(t *testing.T) {
 	s := newStore(t)
+	invalidIngressClass := "something"
+	validIngressClass := ingressclass.DefaultControllerName
 
 	ingressToIgnore := &ingress.Ingress{
 		Ingress: networking.Ingress{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "test-2",
-				Namespace: "testns",
-				Annotations: map[string]string{
-					class.IngressKey: "something",
-				},
+				Name:              "test-2",
+				Namespace:         "testns",
 				CreationTimestamp: metav1.NewTime(time.Now()),
 			},
 			Spec: networking.IngressSpec{
-				Backend: &networking.IngressBackend{
-					ServiceName: "demo",
-					ServicePort: intstr.FromInt(80),
+				IngressClassName: &invalidIngressClass,
+				DefaultBackend: &networking.IngressBackend{
+					Service: &networking.IngressServiceBackend{
+						Name: "demo",
+						Port: networking.ServiceBackendPort{
+							Number: 80,
+						},
+					},
 				},
 			},
 		},
@@ -868,6 +1230,7 @@ func TestListIngresses(t *testing.T) {
 				CreationTimestamp: metav1.NewTime(time.Now()),
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: &validIngressClass,
 				Rules: []networking.IngressRule{
 					{
 						Host: "foo.bar",
@@ -876,8 +1239,12 @@ func TestListIngresses(t *testing.T) {
 								Paths: []networking.HTTPIngressPath{
 									{
 										Backend: networking.IngressBackend{
-											ServiceName: "demo",
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: "demo",
+												Port: networking.ServiceBackendPort{
+													Number: 80,
+												},
+											},
 										},
 									},
 								},
@@ -890,13 +1257,13 @@ func TestListIngresses(t *testing.T) {
 	}
 	s.listers.IngressWithAnnotation.Add(ingressWithoutPath)
 
-	ingressWithNginxClass := &ingress.Ingress{
+	ingressWithNginxClassAnnotation := &ingress.Ingress{
 		Ingress: networking.Ingress{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      "test-4",
 				Namespace: "testns",
 				Annotations: map[string]string{
-					class.IngressKey: "nginx",
+					ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
 				},
 				CreationTimestamp: metav1.NewTime(time.Now()),
 			},
@@ -908,10 +1275,15 @@ func TestListIngresses(t *testing.T) {
 							HTTP: &networking.HTTPIngressRuleValue{
 								Paths: []networking.HTTPIngressPath{
 									{
-										Path: "/demo",
+										Path:     "/demo",
+										PathType: &pathPrefix,
 										Backend: networking.IngressBackend{
-											ServiceName: "demo",
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: "demo",
+												Port: networking.ServiceBackendPort{
+													Number: 80,
+												},
+											},
 										},
 									},
 								},
@@ -922,7 +1294,7 @@ func TestListIngresses(t *testing.T) {
 			},
 		},
 	}
-	s.listers.IngressWithAnnotation.Add(ingressWithNginxClass)
+	s.listers.IngressWithAnnotation.Add(ingressWithNginxClassAnnotation)
 
 	ingresses := s.ListIngresses()
 
diff --git a/internal/ingress/controller/tcp.go b/internal/ingress/controller/tcp.go
index a97c46a7ed..eedecc71ab 100644
--- a/internal/ingress/controller/tcp.go
+++ b/internal/ingress/controller/tcp.go
@@ -82,6 +82,7 @@ func (p *TCPProxy) Handle(conn net.Conn) {
 	hostPort := net.JoinHostPort(proxy.IP, fmt.Sprintf("%v", proxy.Port))
 	clientConn, err := net.Dial("tcp", hostPort)
 	if err != nil {
+		klog.V(4).ErrorS(err, "error dialing proxy", "ip", proxy.IP, "port", proxy.Port, "hostname", proxy.Hostname)
 		return
 	}
 	defer clientConn.Close()
diff --git a/internal/ingress/controller/template/template.go b/internal/ingress/controller/template/template.go
index 3ba46681eb..3f7e4af503 100644
--- a/internal/ingress/controller/template/template.go
+++ b/internal/ingress/controller/template/template.go
@@ -31,13 +31,14 @@ import (
 	"reflect"
 	"regexp"
 	"sort"
+	"strconv"
 	"strings"
 	text_template "text/template"
 	"time"
 
 	"github.com/pkg/errors"
 
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
+	networkingv1 "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/klog/v2"
 
@@ -519,7 +520,7 @@ func buildLocation(input interface{}, enforceRegex bool) string {
 		return fmt.Sprintf(`~* "^%s"`, path)
 	}
 
-	if location.PathType != nil && *location.PathType == networkingv1beta1.PathTypeExact {
+	if location.PathType != nil && *location.PathType == networkingv1.PathTypeExact {
 		return fmt.Sprintf(`= %s`, path)
 	}
 
@@ -985,10 +986,12 @@ func getIngressInformation(i, h, p interface{}) *ingressInformation {
 		info.Path = "/"
 	}
 
-	if ing.Spec.Backend != nil {
-		info.Service = ing.Spec.Backend.ServiceName
-		if ing.Spec.Backend.ServicePort.String() != "0" {
-			info.ServicePort = ing.Spec.Backend.ServicePort.String()
+	if ing.Spec.DefaultBackend != nil && ing.Spec.DefaultBackend.Service != nil {
+		info.Service = ing.Spec.DefaultBackend.Service.Name
+		if ing.Spec.DefaultBackend.Service.Port.Number > 0 {
+			info.ServicePort = strconv.Itoa(int(ing.Spec.DefaultBackend.Service.Port.Number))
+		} else {
+			info.ServicePort = ing.Spec.DefaultBackend.Service.Port.Name
 		}
 	}
 
@@ -1015,14 +1018,16 @@ func getIngressInformation(i, h, p interface{}) *ingressInformation {
 				continue
 			}
 
-			if info.Service != "" && rPath.Backend.ServiceName == "" {
+			if info.Service != "" && rPath.Backend.Service.Name == "" {
 				// empty rule. Only contains a Path and PathType
 				return info
 			}
 
-			info.Service = rPath.Backend.ServiceName
-			if rPath.Backend.ServicePort.String() != "0" {
-				info.ServicePort = rPath.Backend.ServicePort.String()
+			info.Service = rPath.Backend.Service.Name
+			if rPath.Backend.Service.Port.Number > 0 {
+				info.ServicePort = strconv.Itoa(int(rPath.Backend.Service.Port.Number))
+			} else {
+				info.ServicePort = rPath.Backend.Service.Port.Name
 			}
 
 			return info
diff --git a/internal/ingress/controller/template/template_test.go b/internal/ingress/controller/template/template_test.go
index cb2d20b9a6..4a64a09629 100644
--- a/internal/ingress/controller/template/template_test.go
+++ b/internal/ingress/controller/template/template_test.go
@@ -31,9 +31,8 @@ import (
 	jsoniter "github.com/json-iterator/go"
 	"github.com/pmezard/go-difflib/difflib"
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress"
 	"k8s.io/ingress-nginx/internal/ingress/annotations/authreq"
@@ -56,6 +55,8 @@ func init() {
 }
 
 var (
+	pathPrefix networking.PathType = networking.PathTypePrefix
+
 	// TODO: add tests for SSLPassthrough
 	tmplFuncTestcases = map[string]struct {
 		Path              string
@@ -226,11 +227,11 @@ func TestBuildLuaSharedDictionaries(t *testing.T) {
 	servers := []*ingress.Server{
 		{
 			Hostname:  "foo.bar",
-			Locations: []*ingress.Location{{Path: "/"}},
+			Locations: []*ingress.Location{{Path: "/", PathType: &pathPrefix}},
 		},
 		{
 			Hostname:  "another.host",
-			Locations: []*ingress.Location{{Path: "/"}},
+			Locations: []*ingress.Location{{Path: "/", PathType: &pathPrefix}},
 		},
 	}
 	// returns value from config
@@ -312,8 +313,9 @@ func TestBuildLocation(t *testing.T) {
 
 	for k, tc := range tmplFuncTestcases {
 		loc := &ingress.Location{
-			Path:    tc.Path,
-			Rewrite: rewrite.Config{Target: tc.Target},
+			Path:     tc.Path,
+			PathType: &pathPrefix,
+			Rewrite:  rewrite.Config{Target: tc.Target},
 		}
 
 		newLoc := buildLocation(loc, tc.enforceRegex)
@@ -330,6 +332,7 @@ func TestBuildProxyPass(t *testing.T) {
 	for k, tc := range tmplFuncTestcases {
 		loc := &ingress.Location{
 			Path:             tc.Path,
+			PathType:         &pathPrefix,
 			Rewrite:          rewrite.Config{Target: tc.Target},
 			Backend:          defaultBackend,
 			XForwardedPrefix: tc.XForwardedPrefix,
@@ -899,6 +902,7 @@ func TestBuildUpstreamName(t *testing.T) {
 	for k, tc := range tmplFuncTestcases {
 		loc := &ingress.Location{
 			Path:             tc.Path,
+			PathType:         &pathPrefix,
 			Rewrite:          rewrite.Config{Target: tc.Target},
 			Backend:          defaultBackend,
 			XForwardedPrefix: tc.XForwardedPrefix,
@@ -998,6 +1002,76 @@ func TestGetIngressInformation(t *testing.T) {
 			10,
 			&ingressInformation{},
 		},
+		"valid ingress definition with name validIng in namespace default  using a service with name a-svc port number 8080": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "validIng",
+						Namespace: apiv1.NamespaceDefault,
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "a-svc",
+								Port: networking.ServiceBackendPort{
+									Number: 8080,
+								},
+							},
+						},
+					},
+				},
+			},
+			"host1",
+			"",
+			&ingressInformation{
+				Namespace: "default",
+				Rule:      "validIng",
+				Path:      "/",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "a-svc",
+				ServicePort: "8080",
+			},
+		},
+		"valid ingress definition with name validIng in namespace default  using a service with name a-svc port name b-svc": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "validIng",
+						Namespace: apiv1.NamespaceDefault,
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "a-svc",
+								Port: networking.ServiceBackendPort{
+									Name: "b-svc",
+								},
+							},
+						},
+					},
+				},
+			},
+			"host1",
+			"",
+			&ingressInformation{
+				Namespace: "default",
+				Rule:      "validIng",
+				Path:      "/",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "a-svc",
+				ServicePort: "b-svc",
+			},
+		},
 		"valid ingress definition with name validIng in namespace default": {
 			&ingress.Ingress{
 				Ingress: networking.Ingress{
@@ -1009,8 +1083,10 @@ func TestGetIngressInformation(t *testing.T) {
 						},
 					},
 					Spec: networking.IngressSpec{
-						Backend: &networking.IngressBackend{
-							ServiceName: "a-svc",
+						DefaultBackend: &networking.IngressBackend{
+							Service: &networking.IngressServiceBackend{
+								Name: "a-svc",
+							},
 						},
 					},
 				},
@@ -1020,6 +1096,7 @@ func TestGetIngressInformation(t *testing.T) {
 			&ingressInformation{
 				Namespace: "default",
 				Rule:      "validIng",
+				Path:      "/",
 				Annotations: map[string]string{
 					"ingress.annotation": "ok",
 				},
@@ -1044,10 +1121,15 @@ func TestGetIngressInformation(t *testing.T) {
 									HTTP: &networking.HTTPIngressRuleValue{
 										Paths: []networking.HTTPIngressPath{
 											{
-												Path: "/ok",
+												Path:     "/ok",
+												PathType: &pathPrefix,
 												Backend: networking.IngressBackend{
-													ServiceName: "b-svc",
-													ServicePort: intstr.FromInt(80),
+													Service: &networking.IngressServiceBackend{
+														Name: "b-svc",
+														Port: networking.ServiceBackendPort{
+															Number: 80,
+														},
+													},
 												},
 											},
 										},
@@ -1071,6 +1153,56 @@ func TestGetIngressInformation(t *testing.T) {
 				ServicePort: "80",
 			},
 		},
+		"valid ingress definition with name demo in namespace something and path /ok using a service with name b-svc port name b-svc-80": {
+			&ingress.Ingress{
+				Ingress: networking.Ingress{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "demo",
+						Namespace: "something",
+						Annotations: map[string]string{
+							"ingress.annotation": "ok",
+						},
+					},
+					Spec: networking.IngressSpec{
+						Rules: []networking.IngressRule{
+							{
+								Host: "foo.bar",
+								IngressRuleValue: networking.IngressRuleValue{
+									HTTP: &networking.HTTPIngressRuleValue{
+										Paths: []networking.HTTPIngressPath{
+											{
+												Path:     "/ok",
+												PathType: &pathPrefix,
+												Backend: networking.IngressBackend{
+													Service: &networking.IngressServiceBackend{
+														Name: "b-svc",
+														Port: networking.ServiceBackendPort{
+															Name: "b-svc-80",
+														},
+													},
+												},
+											},
+										},
+									},
+								},
+							},
+							{},
+						},
+					},
+				},
+			},
+			"foo.bar",
+			"/ok",
+			&ingressInformation{
+				Namespace: "something",
+				Rule:      "demo",
+				Annotations: map[string]string{
+					"ingress.annotation": "ok",
+				},
+				Service:     "b-svc",
+				ServicePort: "b-svc-80",
+			},
+		},
 	}
 
 	for title, testCase := range testcases {
@@ -1338,7 +1470,8 @@ func TestEnforceRegexModifier(t *testing.T) {
 				Target:   "/alright",
 				UseRegex: true,
 			},
-			Path: "/ok",
+			Path:     "/ok",
+			PathType: &pathPrefix,
 		},
 	}
 	expected = true
diff --git a/internal/ingress/controller/util.go b/internal/ingress/controller/util.go
index b84f2c2e4b..91e0c3acf8 100644
--- a/internal/ingress/controller/util.go
+++ b/internal/ingress/controller/util.go
@@ -26,6 +26,7 @@ import (
 	"syscall"
 
 	api "k8s.io/api/core/v1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/internal/ingress"
 	"k8s.io/klog/v2"
@@ -46,8 +47,30 @@ func newUpstream(name string) *ingress.Backend {
 }
 
 // upstreamName returns a formatted upstream name based on namespace, service, and port
-func upstreamName(namespace string, service string, port intstr.IntOrString) string {
-	return fmt.Sprintf("%v-%v-%v", namespace, service, port.String())
+func upstreamName(namespace string, service *networking.IngressServiceBackend) string {
+	if service != nil {
+		if service.Port.Number > 0 {
+			return fmt.Sprintf("%s-%s-%d", namespace, service.Name, service.Port.Number)
+		}
+		if service.Port.Name != "" {
+			return fmt.Sprintf("%s-%s-%s", namespace, service.Name, service.Port.Name)
+		}
+	}
+	return fmt.Sprintf("%s-INVALID", namespace)
+}
+
+// upstreamServiceNameAndPort verifies if service is not nil, and then return the
+// correct serviceName and Port
+func upstreamServiceNameAndPort(service *networking.IngressServiceBackend) (string, intstr.IntOrString) {
+	if service != nil {
+		if service.Port.Number > 0 {
+			return service.Name, intstr.FromInt(int(service.Port.Number))
+		}
+		if service.Port.Name != "" {
+			return service.Name, intstr.FromString(service.Port.Name)
+		}
+	}
+	return "", intstr.IntOrString{}
 }
 
 // sysctlSomaxconn returns the maximum number of connections that can be queued
diff --git a/internal/ingress/metric/main.go b/internal/ingress/metric/main.go
index d85e1c9798..64810dd362 100644
--- a/internal/ingress/metric/main.go
+++ b/internal/ingress/metric/main.go
@@ -26,7 +26,6 @@ import (
 
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/ingress-nginx/internal/ingress"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
 	"k8s.io/ingress-nginx/internal/ingress/metric/collectors"
 )
 
@@ -66,7 +65,7 @@ type collector struct {
 }
 
 // NewCollector creates a new metric collector the for ingress controller
-func NewCollector(metricsPerHost bool, registry *prometheus.Registry) (Collector, error) {
+func NewCollector(metricsPerHost bool, registry *prometheus.Registry, ingressclass string) (Collector, error) {
 	podNamespace := os.Getenv("POD_NAMESPACE")
 	if podNamespace == "" {
 		podNamespace = "default"
@@ -74,22 +73,22 @@ func NewCollector(metricsPerHost bool, registry *prometheus.Registry) (Collector
 
 	podName := os.Getenv("POD_NAME")
 
-	nc, err := collectors.NewNGINXStatus(podName, podNamespace, class.IngressClass)
+	nc, err := collectors.NewNGINXStatus(podName, podNamespace, ingressclass)
 	if err != nil {
 		return nil, err
 	}
 
-	pc, err := collectors.NewNGINXProcess(podName, podNamespace, class.IngressClass)
+	pc, err := collectors.NewNGINXProcess(podName, podNamespace, ingressclass)
 	if err != nil {
 		return nil, err
 	}
 
-	s, err := collectors.NewSocketCollector(podName, podNamespace, class.IngressClass, metricsPerHost)
+	s, err := collectors.NewSocketCollector(podName, podNamespace, ingressclass, metricsPerHost)
 	if err != nil {
 		return nil, err
 	}
 
-	ic := collectors.NewController(podName, podNamespace, class.IngressClass)
+	ic := collectors.NewController(podName, podNamespace, ingressclass)
 
 	return Collector(&collector{
 		nginxStatus:  nc,
diff --git a/internal/ingress/status/status.go b/internal/ingress/status/status.go
index 506ae398cc..cabc6b3a2c 100644
--- a/internal/ingress/status/status.go
+++ b/internal/ingress/status/status.go
@@ -275,7 +275,7 @@ func runUpdate(ing *ingress.Ingress, status []apiv1.LoadBalancerIngress,
 			return nil, nil
 		}
 
-		ingClient := client.NetworkingV1beta1().Ingresses(ing.Namespace)
+		ingClient := client.NetworkingV1().Ingresses(ing.Namespace)
 		currIng, err := ingClient.Get(context.TODO(), ing.Name, metav1.GetOptions{})
 		if err != nil {
 			return nil, errors.Wrap(err, fmt.Sprintf("unexpected error searching Ingress %v/%v", ing.Namespace, ing.Name))
diff --git a/internal/ingress/status/status_test.go b/internal/ingress/status/status_test.go
index 9ad0c29cf4..79bb85891a 100644
--- a/internal/ingress/status/status_test.go
+++ b/internal/ingress/status/status_test.go
@@ -24,12 +24,12 @@ import (
 	"time"
 
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	testclient "k8s.io/client-go/kubernetes/fake"
 
 	"k8s.io/ingress-nginx/internal/ingress"
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	"k8s.io/ingress-nginx/internal/k8s"
 	"k8s.io/ingress-nginx/internal/task"
 )
@@ -214,7 +214,7 @@ func buildExtensionsIngresses() []networking.Ingress {
 				Name:      "foo_ingress_different_class",
 				Namespace: metav1.NamespaceDefault,
 				Annotations: map[string]string{
-					class.IngressKey: "no-nginx",
+					ingressclass.IngressKey: "no-nginx",
 				},
 			},
 			Status: networking.IngressStatus{
@@ -328,7 +328,7 @@ func TestStatusActions(t *testing.T) {
 	newIPs := []apiv1.LoadBalancerIngress{{
 		IP: "11.0.0.2",
 	}}
-	fooIngress1, err1 := fk.Client.NetworkingV1beta1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
+	fooIngress1, err1 := fk.Client.NetworkingV1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
 	if err1 != nil {
 		t.Fatalf("unexpected error")
 	}
@@ -343,7 +343,7 @@ func TestStatusActions(t *testing.T) {
 	fk.Shutdown()
 	// ingress should be empty
 	newIPs2 := []apiv1.LoadBalancerIngress{}
-	fooIngress2, err2 := fk.Client.NetworkingV1beta1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
+	fooIngress2, err2 := fk.Client.NetworkingV1().Ingresses(apiv1.NamespaceDefault).Get(context.TODO(), "foo_ingress_1", metav1.GetOptions{})
 	if err2 != nil {
 		t.Fatalf("unexpected error")
 	}
@@ -352,7 +352,7 @@ func TestStatusActions(t *testing.T) {
 		t.Fatalf("returned %v but expected %v", fooIngress2CurIPs, newIPs2)
 	}
 
-	oic, err := fk.Client.NetworkingV1beta1().Ingresses(metav1.NamespaceDefault).Get(context.TODO(), "foo_ingress_different_class", metav1.GetOptions{})
+	oic, err := fk.Client.NetworkingV1().Ingresses(metav1.NamespaceDefault).Get(context.TODO(), "foo_ingress_different_class", metav1.GetOptions{})
 	if err != nil {
 		t.Fatalf("unexpected error")
 	}
diff --git a/internal/ingress/types.go b/internal/ingress/types.go
index 84d964b7a0..a1cbdf685d 100644
--- a/internal/ingress/types.go
+++ b/internal/ingress/types.go
@@ -18,7 +18,7 @@ package ingress
 
 import (
 	apiv1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/internal/ingress/annotations"
diff --git a/internal/k8s/main.go b/internal/k8s/main.go
index 364d7c8ec1..1487e892ac 100644
--- a/internal/k8s/main.go
+++ b/internal/k8s/main.go
@@ -25,7 +25,7 @@ import (
 	"k8s.io/klog/v2"
 
 	apiv1 "k8s.io/api/core/v1"
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
+	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/version"
 	clientset "k8s.io/client-go/kubernetes"
@@ -121,46 +121,37 @@ func MetaNamespaceKey(obj interface{}) string {
 	return key
 }
 
-// IsIngressV1Beta1Ready indicates if the running Kubernetes version is at least v1.18.0
-var IsIngressV1Beta1Ready bool
-
 // IsIngressV1Ready indicates if the running Kubernetes version is at least v1.19.0
 var IsIngressV1Ready bool
 
-// IngressClass indicates the class of the Ingress to use as filter
-var IngressClass *networkingv1beta1.IngressClass
-
 // IngressNGINXController defines the valid value of IngressClass
 // Controller field for ingress-nginx
 const IngressNGINXController = "k8s.io/ingress-nginx"
 
-// NetworkingIngressAvailable checks if the package "k8s.io/api/networking/v1beta1"
-// is available or not and if Ingress V1 is supported (k8s >= v1.18.0)
-func NetworkingIngressAvailable(client clientset.Interface) (bool, bool, bool) {
-	// check kubernetes version to use new ingress package or not
-	version114, _ := version.ParseGeneric("v1.14.0")
-	version118, _ := version.ParseGeneric("v1.18.0")
+// NetworkingIngressAvailable checks if the package "k8s.io/api/networking/v1"
+// is available or not and if Ingress V1 is supported (k8s >= v1.19.0)
+func NetworkingIngressAvailable(client clientset.Interface) bool {
 	version119, _ := version.ParseGeneric("v1.19.0")
 
 	serverVersion, err := client.Discovery().ServerVersion()
 	if err != nil {
-		return false, false, false
+		return false
 	}
 
 	runningVersion, err := version.ParseGeneric(serverVersion.String())
 	if err != nil {
 		klog.ErrorS(err, "unexpected error parsing running Kubernetes version")
-		return false, false, false
+		return false
 	}
 
-	return runningVersion.AtLeast(version114), runningVersion.AtLeast(version118), runningVersion.AtLeast(version119)
+	return runningVersion.AtLeast(version119)
 }
 
 // default path type is Prefix to not break existing definitions
-var defaultPathType = networkingv1beta1.PathTypePrefix
+var defaultPathType = networkingv1.PathTypePrefix
 
 // SetDefaultNGINXPathType sets a default PathType when is not defined.
-func SetDefaultNGINXPathType(ing *networkingv1beta1.Ingress) {
+func SetDefaultNGINXPathType(ing *networkingv1.Ingress) {
 	for _, rule := range ing.Spec.Rules {
 		if rule.IngressRuleValue.HTTP == nil {
 			continue
@@ -172,7 +163,7 @@ func SetDefaultNGINXPathType(ing *networkingv1beta1.Ingress) {
 				p.PathType = &defaultPathType
 			}
 
-			if *p.PathType == networkingv1beta1.PathTypeImplementationSpecific {
+			if *p.PathType == networkingv1.PathTypeImplementationSpecific {
 				p.PathType = &defaultPathType
 			}
 		}
diff --git a/stable.txt b/stable.txt
index 19b69dedd1..c23a4ae6d9 100644
--- a/stable.txt
+++ b/stable.txt
@@ -1 +1 @@
-controller-v0.49.0
+controller-v0.49.0
\ No newline at end of file
diff --git a/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml b/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml
index c79154d289..4fef671a76 100644
--- a/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml
+++ b/test/e2e-image/namespace-overlays/forwarded-port-headers/values.yaml
@@ -14,7 +14,9 @@ controller:
     https-port: "1443"
     # e2e tests do not require information about ingress status
     update-status: "false"
-
+  ingressClassResource:
+    # We will create and remove each IC/ClusterRole/ClusterRoleBinding per test so there's no conflict
+    enabled: false
   scope:
     enabled: true
 
diff --git a/test/e2e/admission/admission.go b/test/e2e/admission/admission.go
index b6cf638fe4..121d0d37aa 100644
--- a/test/e2e/admission/admission.go
+++ b/test/e2e/admission/admission.go
@@ -56,14 +56,14 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 
 		ginkgo.By("rejects ingress when memcached is not configured")
 
-		_, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{})
+		_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{})
 		assert.NotNil(ginkgo.GinkgoT(), err, "creating ingress with global throttle annotations when memcached is not configured")
 
 		ginkgo.By("accepts ingress when memcached is not configured")
 
 		f.UpdateNginxConfigMapData("global-rate-limit-memcached-host", "memc.default.svc.cluster.local")
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), ing, metav1.CreateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress with global throttle annotations when memcached is configured")
 
 		f.WaitForNginxServer(host,
@@ -76,7 +76,7 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 		host := "admission-test"
 
 		firstIngress := framework.NewSingleIngress("first-ingress", "/", host, f.Namespace, framework.EchoService, 80, nil)
-		_, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
+		_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
 
 		f.WaitForNginxServer(host,
@@ -85,7 +85,7 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 			})
 
 		secondIngress := framework.NewSingleIngress("second-ingress", "/", host, f.Namespace, framework.EchoService, 80, nil)
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), secondIngress, metav1.CreateOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), secondIngress, metav1.CreateOptions{})
 		assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with the same host and path should return an error")
 	})
 
@@ -93,7 +93,7 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 		host := "admission-test"
 
 		firstIngress := framework.NewSingleIngress("first-ingress", "/", host, f.Namespace, framework.EchoService, 80, nil)
-		_, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
+		_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "creating ingress")
 
 		f.WaitForNginxServer(host,
@@ -106,7 +106,7 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 			"nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader",
 		}
 		secondIngress := framework.NewSingleIngress("second-ingress", "/", host, f.Namespace, framework.SlowEchoService, 80, canaryAnnotations)
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), secondIngress, metav1.CreateOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), secondIngress, metav1.CreateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress with the same host and path should not return an error using a canary annotation")
 	})
 
@@ -117,12 +117,12 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 			"nginx.ingress.kubernetes.io/configuration-snippet": "something invalid",
 		}
 		firstIngress := framework.NewSingleIngress("first-ingress", "/", host, f.Namespace, framework.EchoService, 80, annotations)
-		_, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
+		_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Create(context.TODO(), firstIngress, metav1.CreateOptions{})
 		assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid configuration should return an error")
 	})
 
-	ginkgo.It("should not return an error the ingress definition uses the deprecated extensions package", func() {
-		err := createIngress(f.Namespace, validIngress)
+	ginkgo.It("should not return an error if the Ingress V1 definition is valid with Ingress Class", func() {
+		err := createIngress(f.Namespace, validV1Ingress)
 		assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl")
 
 		f.WaitForNginxConfiguration(func(cfg string) bool {
@@ -136,44 +136,26 @@ var _ = framework.IngressNginxDescribe("[Serial] admission controller", func() {
 			Status(http.StatusOK)
 	})
 
-	ginkgo.It("should return an error if the ingress definition uses the deprecated extensions package and invalid annotations", func() {
-		err := createIngress(f.Namespace, invalidIngress)
-		assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl")
-
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), "extensions", metav1.GetOptions{})
-		if !apierrors.IsNotFound(err) {
-			assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid configuration should return an error")
-		}
-	})
-
-	ginkgo.It("should not return an error if the Ingress V1 definition is valid", func() {
-		if !f.IsIngressV1Ready {
-			ginkgo.Skip("Test requires Kubernetes v1.19 or higher")
-		}
-
-		err := createIngress(f.Namespace, validV1Ingress)
+	ginkgo.It("should not return an error if the Ingress V1 definition is valid with IngressClass annotation", func() {
+		err := createIngress(f.Namespace, validV1IngressAnnotation)
 		assert.Nil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl")
 
 		f.WaitForNginxConfiguration(func(cfg string) bool {
-			return strings.Contains(cfg, "extensions")
+			return strings.Contains(cfg, "extensions-class")
 		})
 
 		f.HTTPTestClient().
 			GET("/").
-			WithHeader("Host", "extensions").
+			WithHeader("Host", "extensions-class").
 			Expect().
 			Status(http.StatusOK)
 	})
 
 	ginkgo.It("should return an error if the Ingress V1 definition contains invalid annotations", func() {
-		if !f.IsIngressV1Ready {
-			ginkgo.Skip("Test requires Kubernetes v1.19 or higher")
-		}
-
 		err := createIngress(f.Namespace, invalidV1Ingress)
 		assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress using kubectl")
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), "extensions", metav1.GetOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), "extensions-invalid", metav1.GetOptions{})
 		if !apierrors.IsNotFound(err) {
 			assert.NotNil(ginkgo.GinkgoT(), err, "creating an ingress with invalid configuration should return an error")
 		}
@@ -191,51 +173,37 @@ func uninstallChart(f *framework.Framework) error {
 }
 
 const (
-	validIngress = `
-apiVersion: extensions/v1beta1
+	validV1Ingress = `
+apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   name: extensions
 spec:
+  ingressClassName: nginx
   rules:
   - host: extensions
     http:
       paths:
       - path: /
+        pathType: Prefix
         backend:
-          serviceName: echo
-          servicePort: 80
----
-`
+          service:
+            name: echo
+            port:
+              number: 80
 
-	invalidIngress = `
-apiVersion: extensions/v1beta1
-kind: Ingress
-metadata:
-  name: extensions
-  annotations:
-    nginx.ingress.kubernetes.io/configuration-snippet: |
-      invalid directive
-spec:
-  rules:
-  - host: extensions
-    http:
-      paths:
-      - path: /
-        backend:
-          serviceName: echo
-          servicePort: 80
 ---
 `
-
-	validV1Ingress = `
+	validV1IngressAnnotation = `
 apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
-  name: extensions
+  name: extensions-class
+  annotations:
+    kubernetes.io/ingress.class: nginx
 spec:
   rules:
-  - host: extensions
+  - host: extensions-class
     http:
       paths:
       - path: /
@@ -253,13 +221,14 @@ spec:
 apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
-  name: extensions
+  name: extensions-invalid
   annotations:
     nginx.ingress.kubernetes.io/configuration-snippet: |
       invalid directive
 spec:
+  ingressClassName: nginx
   rules:
-  - host: extensions
+  - host: extensions-invalid
     http:
       paths:
       - path: /
diff --git a/test/e2e/annotations/affinity.go b/test/e2e/annotations/affinity.go
index a17df1cc6b..998eca82f7 100644
--- a/test/e2e/annotations/affinity.go
+++ b/test/e2e/annotations/affinity.go
@@ -25,9 +25,8 @@ import (
 
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
@@ -84,7 +83,7 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
 
 		ing.ObjectMeta.Annotations["nginx.ingress.kubernetes.io/session-cookie-name"] = "OTHERCOOKIENAME"
 
-		_, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+		_, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "updating ingress")
 		framework.Sleep()
 
@@ -119,6 +118,7 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
 	})
 
 	ginkgo.It("does not set the path to / on the generated cookie if there's more than one rule referring to the same backend", func() {
+		pathtype := networking.PathTypePrefix
 		host := "morethanonerule.foo.com"
 		annotations := make(map[string]string)
 		annotations["nginx.ingress.kubernetes.io/affinity"] = "cookie"
@@ -131,6 +131,7 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
 				Annotations: annotations,
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: &f.IngressClass,
 				Rules: []networking.IngressRule{
 					{
 						Host: host,
@@ -138,17 +139,27 @@ var _ = framework.DescribeAnnotation("affinity session-cookie-name", func() {
 							HTTP: &networking.HTTPIngressRuleValue{
 								Paths: []networking.HTTPIngressPath{
 									{
-										Path: "/something",
+										Path:     "/something",
+										PathType: &pathtype,
 										Backend: networking.IngressBackend{
-											ServiceName: framework.EchoService,
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: framework.EchoService,
+												Port: networking.ServiceBackendPort{
+													Number: int32(80),
+												},
+											},
 										},
 									},
 									{
-										Path: "/somewhereelse",
+										Path:     "/somewhereelse",
+										PathType: &pathtype,
 										Backend: networking.IngressBackend{
-											ServiceName: framework.EchoService,
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: framework.EchoService,
+												Port: networking.ServiceBackendPort{
+													Number: int32(80),
+												},
+											},
 										},
 									},
 								},
diff --git a/test/e2e/annotations/auth.go b/test/e2e/annotations/auth.go
index fac0658c08..f2c1a59d65 100644
--- a/test/e2e/annotations/auth.go
+++ b/test/e2e/annotations/auth.go
@@ -30,7 +30,7 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	corev1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
diff --git a/test/e2e/annotations/canary.go b/test/e2e/annotations/canary.go
index c66e9b9815..fe3e1544f6 100644
--- a/test/e2e/annotations/canary.go
+++ b/test/e2e/annotations/canary.go
@@ -22,9 +22,7 @@ import (
 	"strings"
 
 	"github.com/onsi/ginkgo"
-	"github.com/stretchr/testify/assert"
 
-	networking "k8s.io/api/networking/v1beta1"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
@@ -32,7 +30,7 @@ const (
 	canaryService = "echo-canary"
 )
 
-var _ = framework.DescribeAnnotation("canary-*", func() {
+var _ = framework.DescribeAnnotation("canary", func() {
 	f := framework.NewDefaultFramework("canary")
 
 	ginkgo.BeforeEach(func() {
@@ -327,15 +325,25 @@ var _ = framework.DescribeAnnotation("canary-*", func() {
 				f.Namespace, canaryService, 80, canaryAnnotations)
 			f.EnsureIngress(canaryIng)
 
-			err := framework.UpdateIngress(f.KubeClientSet, f.Namespace, canaryIngName,
-				func(ingress *networking.Ingress) error {
-					ingress.ObjectMeta.Annotations = map[string]string{
-						"nginx.ingress.kubernetes.io/canary":           "true",
-						"nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader2",
-					}
-					return nil
+			f.WaitForNginxServer(host,
+				func(server string) bool {
+					return strings.Contains(server, "server_name foo")
+				})
+
+			newAnnotations := map[string]string{
+				"nginx.ingress.kubernetes.io/canary":           "true",
+				"nginx.ingress.kubernetes.io/canary-by-header": "CanaryByHeader2",
+			}
+
+			modIng := framework.NewSingleIngress(canaryIngName, "/", host,
+				f.Namespace, canaryService, 80, newAnnotations)
+
+			f.UpdateIngress(modIng)
+
+			f.WaitForNginxServer(host,
+				func(server string) bool {
+					return strings.Contains(server, "server_name foo")
 				})
-			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ginkgo.By("routing requests destined for the mainline ingress to the mainline upstream")
 			f.HTTPTestClient().
@@ -707,6 +715,11 @@ var _ = framework.DescribeAnnotation("canary-*", func() {
 				f.Namespace, canaryService, 80, canaryAnnotations)
 			f.EnsureIngress(canaryIng)
 
+			f.WaitForNginxServer(host,
+				func(server string) bool {
+					return strings.Contains(server, "server_name foo")
+				})
+
 			ginkgo.By("returning requests from the mainline only when weight is equal to 0")
 			f.HTTPTestClient().
 				GET("/").
@@ -719,15 +732,20 @@ var _ = framework.DescribeAnnotation("canary-*", func() {
 
 			ginkgo.By("returning requests from the canary only when weight is equal to 100")
 
-			err := framework.UpdateIngress(f.KubeClientSet, f.Namespace, canaryIngName,
-				func(ingress *networking.Ingress) error {
-					ingress.ObjectMeta.Annotations = map[string]string{
-						"nginx.ingress.kubernetes.io/canary":        "true",
-						"nginx.ingress.kubernetes.io/canary-weight": "100",
-					}
-					return nil
+			newAnnotations := map[string]string{
+				"nginx.ingress.kubernetes.io/canary":        "true",
+				"nginx.ingress.kubernetes.io/canary-weight": "100",
+			}
+
+			modIng := framework.NewSingleIngress(canaryIngName, "/", host,
+				f.Namespace, canaryService, 80, newAnnotations)
+
+			f.UpdateIngress(modIng)
+
+			f.WaitForNginxServer(host,
+				func(server string) bool {
+					return strings.Contains(server, "server_name foo")
 				})
-			assert.Nil(ginkgo.GinkgoT(), err)
 
 			f.HTTPTestClient().
 				GET("/").
diff --git a/test/e2e/annotations/customhttperrors.go b/test/e2e/annotations/customhttperrors.go
index f00ec88590..c0115cb524 100644
--- a/test/e2e/annotations/customhttperrors.go
+++ b/test/e2e/annotations/customhttperrors.go
@@ -22,7 +22,7 @@ import (
 
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
diff --git a/test/e2e/annotations/satisfy.go b/test/e2e/annotations/satisfy.go
index dba710b4b6..8c0f88d2f0 100644
--- a/test/e2e/annotations/satisfy.go
+++ b/test/e2e/annotations/satisfy.go
@@ -26,7 +26,7 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
diff --git a/test/e2e/defaultbackend/with_hosts.go b/test/e2e/defaultbackend/with_hosts.go
index 9a3d87a274..c59b5807b9 100644
--- a/test/e2e/defaultbackend/with_hosts.go
+++ b/test/e2e/defaultbackend/with_hosts.go
@@ -22,9 +22,8 @@ import (
 
 	"github.com/onsi/ginkgo"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
@@ -48,9 +47,14 @@ var _ = framework.IngressNginxDescribe("[Default Backend] change default setting
 				Annotations: annotations,
 			},
 			Spec: networking.IngressSpec{
-				Backend: &networking.IngressBackend{
-					ServiceName: framework.EchoService,
-					ServicePort: intstr.FromInt(80),
+				IngressClassName: &f.IngressClass,
+				DefaultBackend: &networking.IngressBackend{
+					Service: &networking.IngressServiceBackend{
+						Name: framework.EchoService,
+						Port: networking.ServiceBackendPort{
+							Number: int32(80),
+						},
+					},
 				},
 				Rules: []networking.IngressRule{
 					{
diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go
index 8f5fb3884f..e31fd1e4ee 100644
--- a/test/e2e/framework/framework.go
+++ b/test/e2e/framework/framework.go
@@ -29,12 +29,11 @@ import (
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/fields"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/kubernetes/scheme"
@@ -62,15 +61,15 @@ var (
 type Framework struct {
 	BaseName string
 
-	IsIngressV1Ready      bool
-	IsIngressV1Beta1Ready bool
+	IsIngressV1Ready bool
 
 	// A Kubernetes and Service Catalog client
 	KubeClientSet          kubernetes.Interface
 	KubeConfig             *restclient.Config
 	APIExtensionsClientSet apiextcs.Interface
 
-	Namespace string
+	Namespace    string
+	IngressClass string
 
 	pod *corev1.Pod
 }
@@ -104,12 +103,15 @@ func (f *Framework) BeforeEach() {
 		f.KubeClientSet, err = kubernetes.NewForConfig(f.KubeConfig)
 		assert.Nil(ginkgo.GinkgoT(), err, "creating a kubernetes client")
 
-		_, f.IsIngressV1Beta1Ready, f.IsIngressV1Ready = k8s.NetworkingIngressAvailable(f.KubeClientSet)
+		f.IsIngressV1Ready = k8s.NetworkingIngressAvailable(f.KubeClientSet)
 	}
 
 	f.Namespace, err = CreateKubeNamespace(f.BaseName, f.KubeClientSet)
 	assert.Nil(ginkgo.GinkgoT(), err, "creating namespace")
 
+	f.IngressClass, err = CreateIngressClass(f.Namespace, f.KubeClientSet)
+	assert.Nil(ginkgo.GinkgoT(), err, "creating IngressClass")
+
 	err = f.newIngressController(f.Namespace, f.BaseName)
 	assert.Nil(ginkgo.GinkgoT(), err, "deploying the ingress controller")
 
@@ -129,6 +131,14 @@ func (f *Framework) AfterEach() {
 		}()
 	}(f.KubeClientSet, f.Namespace)
 
+	defer func(kubeClient kubernetes.Interface, ingressclass string) {
+		go func() {
+			defer ginkgo.GinkgoRecover()
+			err := deleteIngressClass(kubeClient, ingressclass)
+			assert.Nil(ginkgo.GinkgoT(), err, "deleting IngressClass")
+		}()
+	}(f.KubeClientSet, f.IngressClass)
+
 	if !ginkgo.CurrentGinkgoTestDescription().Failed {
 		return
 	}
@@ -542,7 +552,7 @@ func waitForDeploymentRollout(kubeClientSet kubernetes.Interface, resource *apps
 
 // UpdateIngress runs the given updateFunc on the ingress
 func UpdateIngress(kubeClientSet kubernetes.Interface, namespace string, name string, updateFunc func(d *networking.Ingress) error) error {
-	ingress, err := kubeClientSet.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+	ingress, err := kubeClientSet.NetworkingV1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
 	if err != nil {
 		return err
 	}
@@ -559,7 +569,7 @@ func UpdateIngress(kubeClientSet kubernetes.Interface, namespace string, name st
 		return err
 	}
 
-	_, err = kubeClientSet.NetworkingV1beta1().Ingresses(namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
+	_, err = kubeClientSet.NetworkingV1().Ingresses(namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
 	if err != nil {
 		return err
 	}
@@ -580,7 +590,9 @@ func NewSingleIngress(name, path, host, ns, service string, port int, annotation
 
 // NewSingleIngressWithMultiplePaths creates a simple ingress rule with multiple paths
 func NewSingleIngressWithMultiplePaths(name string, paths []string, host, ns, service string, port int, annotations map[string]string) *networking.Ingress {
+	pathtype := networking.PathTypePrefix
 	spec := networking.IngressSpec{
+		IngressClassName: GetIngressClassName(ns),
 		Rules: []networking.IngressRule{
 			{
 				Host: host,
@@ -593,10 +605,15 @@ func NewSingleIngressWithMultiplePaths(name string, paths []string, host, ns, se
 
 	for _, path := range paths {
 		spec.Rules[0].IngressRuleValue.HTTP.Paths = append(spec.Rules[0].IngressRuleValue.HTTP.Paths, networking.HTTPIngressPath{
-			Path: path,
+			Path:     path,
+			PathType: &pathtype,
 			Backend: networking.IngressBackend{
-				ServiceName: service,
-				ServicePort: intstr.FromInt(port),
+				Service: &networking.IngressServiceBackend{
+					Name: service,
+					Port: networking.ServiceBackendPort{
+						Number: int32(port),
+					},
+				},
 			},
 		})
 	}
@@ -605,17 +622,24 @@ func NewSingleIngressWithMultiplePaths(name string, paths []string, host, ns, se
 }
 
 func newSingleIngressWithRules(name, path, host, ns, service string, port int, annotations map[string]string, tlsHosts []string) *networking.Ingress {
+	pathtype := networking.PathTypePrefix
 	spec := networking.IngressSpec{
+		IngressClassName: GetIngressClassName(ns),
 		Rules: []networking.IngressRule{
 			{
 				IngressRuleValue: networking.IngressRuleValue{
 					HTTP: &networking.HTTPIngressRuleValue{
 						Paths: []networking.HTTPIngressPath{
 							{
-								Path: path,
+								Path:     path,
+								PathType: &pathtype,
 								Backend: networking.IngressBackend{
-									ServiceName: service,
-									ServicePort: intstr.FromInt(port),
+									Service: &networking.IngressServiceBackend{
+										Name: service,
+										Port: networking.ServiceBackendPort{
+											Number: int32(port),
+										},
+									},
 								},
 							},
 						},
@@ -644,10 +668,16 @@ func newSingleIngressWithRules(name, path, host, ns, service string, port int, a
 
 // NewSingleIngressWithBackendAndRules creates an ingress with both a default backend and a rule
 func NewSingleIngressWithBackendAndRules(name, path, host, ns, defaultService string, defaultPort int, service string, port int, annotations map[string]string) *networking.Ingress {
+	pathtype := networking.PathTypePrefix
 	spec := networking.IngressSpec{
-		Backend: &networking.IngressBackend{
-			ServiceName: defaultService,
-			ServicePort: intstr.FromInt(defaultPort),
+		IngressClassName: GetIngressClassName(ns),
+		DefaultBackend: &networking.IngressBackend{
+			Service: &networking.IngressServiceBackend{
+				Name: defaultService,
+				Port: networking.ServiceBackendPort{
+					Number: int32(defaultPort),
+				},
+			},
 		},
 		Rules: []networking.IngressRule{
 			{
@@ -656,10 +686,15 @@ func NewSingleIngressWithBackendAndRules(name, path, host, ns, defaultService st
 					HTTP: &networking.HTTPIngressRuleValue{
 						Paths: []networking.HTTPIngressPath{
 							{
-								Path: path,
+								Path:     path,
+								PathType: &pathtype,
 								Backend: networking.IngressBackend{
-									ServiceName: service,
-									ServicePort: intstr.FromInt(port),
+									Service: &networking.IngressServiceBackend{
+										Name: service,
+										Port: networking.ServiceBackendPort{
+											Number: int32(port),
+										},
+									},
 								},
 							},
 						},
@@ -675,9 +710,14 @@ func NewSingleIngressWithBackendAndRules(name, path, host, ns, defaultService st
 // NewSingleCatchAllIngress creates a simple ingress with a catch-all backend
 func NewSingleCatchAllIngress(name, ns, service string, port int, annotations map[string]string) *networking.Ingress {
 	spec := networking.IngressSpec{
-		Backend: &networking.IngressBackend{
-			ServiceName: service,
-			ServicePort: intstr.FromInt(port),
+		IngressClassName: GetIngressClassName(ns),
+		DefaultBackend: &networking.IngressBackend{
+			Service: &networking.IngressServiceBackend{
+				Name: service,
+				Port: networking.ServiceBackendPort{
+					Number: int32(port),
+				},
+			},
 		},
 	}
 	return newSingleIngress(name, ns, annotations, spec)
diff --git a/test/e2e/framework/k8s.go b/test/e2e/framework/k8s.go
index 3ca4a3c465..14937e6bd4 100644
--- a/test/e2e/framework/k8s.go
+++ b/test/e2e/framework/k8s.go
@@ -28,7 +28,7 @@ import (
 	api "k8s.io/api/core/v1"
 	core "k8s.io/api/core/v1"
 	v1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utilnet "k8s.io/apimachinery/pkg/util/net"
@@ -63,7 +63,7 @@ func (f *Framework) EnsureConfigMap(configMap *api.ConfigMap) (*api.ConfigMap, e
 
 // GetIngress gets an Ingress object from the given namespace, name and returns it, throws error if it does not exists.
 func (f *Framework) GetIngress(namespace string, name string) *networking.Ingress {
-	ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+	ing, err := f.KubeClientSet.NetworkingV1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
 	assert.Nil(ginkgo.GinkgoT(), err, "getting ingress")
 	assert.NotNil(ginkgo.GinkgoT(), ing, "expected an ingress but none returned")
 	return ing
@@ -334,7 +334,7 @@ func createIngressWithRetries(c kubernetes.Interface, namespace string, obj *net
 		return fmt.Errorf("Object provided to create is empty")
 	}
 	createFunc := func() (bool, error) {
-		_, err := c.NetworkingV1beta1().Ingresses(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
+		_, err := c.NetworkingV1().Ingresses(namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
 		if err == nil {
 			return true, nil
 		}
@@ -355,7 +355,7 @@ func updateIngressWithRetries(c kubernetes.Interface, namespace string, obj *net
 		return fmt.Errorf("Object provided to create is empty")
 	}
 	updateFunc := func() (bool, error) {
-		_, err := c.NetworkingV1beta1().Ingresses(namespace).Update(context.TODO(), obj, metav1.UpdateOptions{})
+		_, err := c.NetworkingV1().Ingresses(namespace).Update(context.TODO(), obj, metav1.UpdateOptions{})
 		if err == nil {
 			return true, nil
 		}
diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go
index e094166f1b..75fcb58ea4 100644
--- a/test/e2e/framework/util.go
+++ b/test/e2e/framework/util.go
@@ -24,6 +24,8 @@ import (
 
 	"github.com/onsi/ginkgo"
 	corev1 "k8s.io/api/core/v1"
+	networkingv1 "k8s.io/api/networking/v1"
+	rbacv1 "k8s.io/api/rbac/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/uuid"
@@ -31,6 +33,8 @@ import (
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/clientcmd"
 	"k8s.io/client-go/tools/clientcmd/api"
+
+	"k8s.io/ingress-nginx/internal/k8s"
 )
 
 const (
@@ -117,6 +121,93 @@ func deleteKubeNamespace(c kubernetes.Interface, namespace string) error {
 	})
 }
 
+// CreateIngressClass creates a new IngressClass related to a test/namespace and also
+// the required ClusterRole/ClusterRoleBinding
+func CreateIngressClass(namespace string, c kubernetes.Interface) (string, error) {
+	icname := fmt.Sprintf("ic-%s", namespace)
+	var err error
+
+	ic, err := c.NetworkingV1().IngressClasses().
+		Create(context.TODO(), &networkingv1.IngressClass{
+			ObjectMeta: metav1.ObjectMeta{
+				Name: icname,
+			},
+			Spec: networkingv1.IngressClassSpec{
+				Controller: k8s.IngressNGINXController,
+			},
+		}, metav1.CreateOptions{})
+	if err != nil {
+		return "", fmt.Errorf("Unexpected error creating IngressClass %s: %v", icname, err)
+	}
+
+	_, err = c.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{
+		ObjectMeta: metav1.ObjectMeta{Name: icname},
+		Rules: []rbacv1.PolicyRule{{
+			APIGroups: []string{"networking.k8s.io"},
+			Resources: []string{"ingressclasses"},
+			Verbs:     []string{"get", "list", "watch"},
+		}},
+	}, metav1.CreateOptions{})
+	if err != nil {
+		return "", fmt.Errorf("Unexpected error creating IngressClass ClusterRole %s: %v", icname, err)
+	}
+
+	_, err = c.RbacV1().ClusterRoleBindings().Create(context.TODO(), &rbacv1.ClusterRoleBinding{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: icname,
+		},
+		RoleRef: rbacv1.RoleRef{
+			APIGroup: "rbac.authorization.k8s.io",
+			Kind:     "ClusterRole",
+			Name:     icname,
+		},
+		Subjects: []rbacv1.Subject{
+			{
+				APIGroup:  "",
+				Kind:      "ServiceAccount",
+				Namespace: namespace,
+				Name:      "nginx-ingress",
+			},
+		},
+	}, metav1.CreateOptions{})
+	if err != nil {
+		return "", fmt.Errorf("Unexpected error creating IngressClass ClusterRoleBinding %s: %v", icname, err)
+	}
+	return ic.Name, nil
+}
+
+//deleteIngressClass deletes an IngressClass and its related ClusterRole* objects
+func deleteIngressClass(c kubernetes.Interface, ingressclass string) error {
+	var err error
+	grace := int64(0)
+	pb := metav1.DeletePropagationBackground
+	deleteOptions := metav1.DeleteOptions{
+		GracePeriodSeconds: &grace,
+		PropagationPolicy:  &pb,
+	}
+	err = c.NetworkingV1().IngressClasses().Delete(context.TODO(), ingressclass, deleteOptions)
+	if err != nil {
+		return fmt.Errorf("Unexpected error deleting IngressClass %s: %v", ingressclass, err)
+	}
+
+	err = c.RbacV1().ClusterRoleBindings().Delete(context.TODO(), ingressclass, deleteOptions)
+	if err != nil {
+		return fmt.Errorf("Unexpected error deleting IngressClass ClusterRoleBinding %s: %v", ingressclass, err)
+	}
+	err = c.RbacV1().ClusterRoles().Delete(context.TODO(), ingressclass, deleteOptions)
+	if err != nil {
+		return fmt.Errorf("Unexpected error deleting IngressClass ClusterRole %s: %v", ingressclass, err)
+	}
+
+	return nil
+}
+
+//GetIngressClassName returns the default IngressClassName given a namespace
+func GetIngressClassName(namespace string) *string {
+	icname := fmt.Sprintf("ic-%s", namespace)
+	return &icname
+}
+
 // WaitForKubeNamespaceNotExist waits until a namespaces is not present in the cluster
 func WaitForKubeNamespaceNotExist(c kubernetes.Interface, namespace string) error {
 	return wait.Poll(Poll, DefaultTimeout, namespaceNotExist(c, namespace))
@@ -223,7 +314,7 @@ func WaitForNoIngressInNamespace(c kubernetes.Interface, namespace, name string)
 
 func noIngressInNamespace(c kubernetes.Interface, namespace, name string) wait.ConditionFunc {
 	return func() (bool, error) {
-		ing, err := c.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+		ing, err := c.NetworkingV1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
 		if apierrors.IsNotFound(err) {
 			return true, nil
 		}
@@ -245,7 +336,7 @@ func WaitForIngressInNamespace(c kubernetes.Interface, namespace, name string) e
 
 func ingressInNamespace(c kubernetes.Interface, namespace, name string) wait.ConditionFunc {
 	return func() (bool, error) {
-		ing, err := c.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+		ing, err := c.NetworkingV1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
 		if apierrors.IsNotFound(err) {
 			return false, nil
 		}
diff --git a/test/e2e/ingress/multiple_rules.go b/test/e2e/ingress/multiple_rules.go
index dd5abd7ae2..030be172ab 100644
--- a/test/e2e/ingress/multiple_rules.go
+++ b/test/e2e/ingress/multiple_rules.go
@@ -22,15 +22,14 @@ import (
 
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
-	"k8s.io/apimachinery/pkg/util/intstr"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
 var _ = framework.IngressNginxDescribe("single ingress - multiple hosts", func() {
 	f := framework.NewDefaultFramework("simh")
-
+	pathprefix := networking.PathTypePrefix
 	ginkgo.BeforeEach(func() {
 		f.NewEchoDeploymentWithNameAndReplicas("first-service", 1)
 		f.NewEchoDeploymentWithNameAndReplicas("second-service", 1)
@@ -43,16 +42,21 @@ var _ = framework.IngressNginxDescribe("single ingress - multiple hosts", func()
 
 		ing := framework.NewSingleIngress("simh", "/", "first.host", f.Namespace, "first-service", 80, annotations)
 
-		ing.Spec.Rules = append(ing.Spec.Rules, networkingv1beta1.IngressRule{
+		ing.Spec.Rules = append(ing.Spec.Rules, networking.IngressRule{
 			Host: "second.host",
-			IngressRuleValue: networkingv1beta1.IngressRuleValue{
-				HTTP: &networkingv1beta1.HTTPIngressRuleValue{
-					Paths: []networkingv1beta1.HTTPIngressPath{
+			IngressRuleValue: networking.IngressRuleValue{
+				HTTP: &networking.HTTPIngressRuleValue{
+					Paths: []networking.HTTPIngressPath{
 						{
-							Path: "/",
-							Backend: networkingv1beta1.IngressBackend{
-								ServiceName: "second-service",
-								ServicePort: intstr.FromInt(80),
+							Path:     "/",
+							PathType: &pathprefix,
+							Backend: networking.IngressBackend{
+								Service: &networking.IngressServiceBackend{
+									Name: "second-service",
+									Port: networking.ServiceBackendPort{
+										Number: int32(80),
+									},
+								},
 							},
 						},
 					},
diff --git a/test/e2e/ingress/pathtype_exact.go b/test/e2e/ingress/pathtype_exact.go
index 01e37836a2..38df19fcc8 100644
--- a/test/e2e/ingress/pathtype_exact.go
+++ b/test/e2e/ingress/pathtype_exact.go
@@ -22,7 +22,7 @@ import (
 
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
@@ -35,9 +35,6 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() {
 	})
 
 	ginkgo.It("should choose exact location for /exact", func() {
-		if !f.IsIngressV1Beta1Ready {
-			ginkgo.Skip("Test requires Kubernetes v1.18 or higher")
-		}
 
 		host := "exact.path"
 
@@ -45,7 +42,7 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] exact", func() {
 			"nginx.ingress.kubernetes.io/configuration-snippet": `more_set_input_headers "pathType: exact";`,
 		}
 
-		var exactPathType = networkingv1beta1.PathTypeExact
+		var exactPathType = networking.PathTypeExact
 		ing := framework.NewSingleIngress("exact", "/exact", host, f.Namespace, framework.EchoService, 80, annotations)
 		ing.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].PathType = &exactPathType
 		f.EnsureIngress(ing)
diff --git a/test/e2e/ingress/pathtype_mixed.go b/test/e2e/ingress/pathtype_mixed.go
index aac7d9ffa4..28e3049c92 100644
--- a/test/e2e/ingress/pathtype_mixed.go
+++ b/test/e2e/ingress/pathtype_mixed.go
@@ -23,7 +23,7 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 
-	networkingv1beta1 "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
@@ -34,12 +34,9 @@ var _ = framework.IngressNginxDescribe("[Ingress] [PathType] mix Exact and Prefi
 		f.NewEchoDeployment()
 	})
 
-	var exactPathType = networkingv1beta1.PathTypeExact
+	var exactPathType = networking.PathTypeExact
 
 	ginkgo.It("should choose the correct location", func() {
-		if !f.IsIngressV1Beta1Ready {
-			ginkgo.Skip("Test requires Kubernetes v1.18 or higher")
-		}
 
 		host := "mixed.path"
 
diff --git a/test/e2e/ingress/without_host.go b/test/e2e/ingress/without_host.go
index 154767fa45..c0c2d3b12e 100644
--- a/test/e2e/ingress/without_host.go
+++ b/test/e2e/ingress/without_host.go
@@ -22,9 +22,8 @@ import (
 	"strings"
 
 	"github.com/onsi/ginkgo"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
@@ -62,9 +61,14 @@ var _ = framework.IngressNginxDescribe("[Ingress] definition without host", func
 				Namespace: f.Namespace,
 			},
 			Spec: networking.IngressSpec{
-				Backend: &networking.IngressBackend{
-					ServiceName: framework.EchoService,
-					ServicePort: intstr.FromInt(80),
+				IngressClassName: &f.IngressClass,
+				DefaultBackend: &networking.IngressBackend{
+					Service: &networking.IngressServiceBackend{
+						Name: framework.EchoService,
+						Port: networking.ServiceBackendPort{
+							Number: int32(80),
+						},
+					},
 				},
 				Rules: []networking.IngressRule{
 					{
diff --git a/test/e2e/leaks/lua_ssl.go b/test/e2e/leaks/lua_ssl.go
index 6eb8bbc63c..8756a973d8 100644
--- a/test/e2e/leaks/lua_ssl.go
+++ b/test/e2e/leaks/lua_ssl.go
@@ -103,7 +103,7 @@ func checkIngress(hostname string, f *framework.Framework) {
 }
 
 func deleteIngress(hostname string, f *framework.Framework) {
-	err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Delete(context.TODO(), hostname, metav1.DeleteOptions{})
+	err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Delete(context.TODO(), hostname, metav1.DeleteOptions{})
 	assert.Nil(ginkgo.GinkgoT(), err, "unexpected error deleting ingress")
 }
 
diff --git a/test/e2e/lua/dynamic_certificates.go b/test/e2e/lua/dynamic_certificates.go
index 455bf0fc29..f5585995eb 100644
--- a/test/e2e/lua/dynamic_certificates.go
+++ b/test/e2e/lua/dynamic_certificates.go
@@ -28,7 +28,7 @@ import (
 	"github.com/prometheus/common/expfmt"
 	"github.com/prometheus/common/model"
 	"github.com/stretchr/testify/assert"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
@@ -45,7 +45,7 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 	ginkgo.It("picks up the certificate when we add TLS spec to existing ingress", func() {
 		ensureIngress(f, host, framework.EchoService)
 
-		ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+		ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err)
 		ing.Spec.TLS = []networking.IngressTLS{
 			{
@@ -59,7 +59,7 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 			ing.Namespace)
 		assert.Nil(ginkgo.GinkgoT(), err)
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err)
 
 		time.Sleep(waitForLuaSync)
@@ -147,7 +147,7 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 		})
 
 		ginkgo.It("picks up the updated certificate without reloading", func() {
-			ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ensureHTTPSRequest(f, fmt.Sprintf("%s?id=dummy_log_splitter_foo_bar", f.GetURL(framework.HTTPS)), host, host)
@@ -183,7 +183,7 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 		})
 
 		ginkgo.It("falls back to using default certificate when secret gets deleted without reloading", func() {
-			ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ensureHTTPSRequest(f, fmt.Sprintf("%s?id=dummy_log_splitter_foo_bar", f.GetURL(framework.HTTPS)), host, host)
@@ -217,11 +217,11 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 
 		ginkgo.It("picks up a non-certificate only change", func() {
 			newHost := "foo2.com"
-			ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ing.Spec.Rules[0].Host = newHost
-			_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			time.Sleep(waitForLuaSync)
@@ -231,11 +231,11 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic certificates", func() {
 		})
 
 		ginkgo.It("removes HTTPS configuration when we delete TLS spec", func() {
-			ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ing.Spec.TLS = []networking.IngressTLS{}
-			_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			time.Sleep(waitForLuaSync)
diff --git a/test/e2e/lua/dynamic_configuration.go b/test/e2e/lua/dynamic_configuration.go
index 5fcebac7dc..0a88fb07bb 100644
--- a/test/e2e/lua/dynamic_configuration.go
+++ b/test/e2e/lua/dynamic_configuration.go
@@ -26,7 +26,7 @@ import (
 
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
@@ -172,11 +172,11 @@ var _ = framework.IngressNginxDescribe("[Lua] dynamic configuration", func() {
 				return true
 			})
 
-			ingress, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), "foo.com", metav1.GetOptions{})
+			ingress, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), "foo.com", metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			ingress.ObjectMeta.Annotations["nginx.ingress.kubernetes.io/load-balance"] = "round_robin"
-			_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Update(context.TODO(), ingress, metav1.UpdateOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			f.HTTPTestClient().
diff --git a/test/e2e/run-chart-test.sh b/test/e2e/run-chart-test.sh
index 841c05e7df..0e618244ca 100755
--- a/test/e2e/run-chart-test.sh
+++ b/test/e2e/run-chart-test.sh
@@ -36,6 +36,8 @@ cleanup() {
 
 trap cleanup EXIT
 
+export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev}
+
 if ! command -v kind --version &> /dev/null; then
   echo "kind is not installed. Use the package manager or visit the official site https://kind.sigs.k8s.io/"
   exit 1
@@ -43,14 +45,17 @@ fi
 
 DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 
-export KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-ingress-nginx-dev}
+# Use 1.0.0-dev to make sure we use the latest configuration in the helm template
+export TAG=1.0.0-dev
+export ARCH=${ARCH:-amd64}
+export REGISTRY=ingress-controller
 
 export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}"
 
 if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
   echo "[dev-env] creating Kubernetes cluster with kind"
 
-  export K8S_VERSION=${K8S_VERSION:-v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab}
+  export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6}
 
   kind create cluster \
     --verbosity=${KIND_LOG_LEVEL} \
@@ -61,8 +66,23 @@ if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
 
   echo "Kubernetes cluster:"
   kubectl get nodes -o wide
+
 fi
 
+if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then
+  if ! command -v ginkgo &> /dev/null; then
+    go get github.com/onsi/ginkgo/ginkgo@v1.16.4
+  fi
+  echo "[dev-env] building image"
+  make -C ${DIR}/../../ clean-image build image
+fi
+  
+
+KIND_WORKERS=$(kind get nodes --name="${KIND_CLUSTER_NAME}" | awk '{printf (NR>1?",":"") $1}')
+echo "[dev-env] copying docker images to cluster..."
+
+kind load docker-image --name="${KIND_CLUSTER_NAME}" --nodes=${KIND_WORKERS} ${REGISTRY}/controller:${TAG}
+
 echo "[dev-env] running helm chart e2e tests..."
 # Uses a custom chart-testing image to avoid timeouts waiting for namespace deletion.
 # The changes can be found here: https://github.com/aledbf/chart-testing/commit/41fe0ae0733d0c9a538099fb3cec522e888e3d82
diff --git a/test/e2e/run.sh b/test/e2e/run.sh
index d3caf2537a..bfe13b428f 100755
--- a/test/e2e/run.sh
+++ b/test/e2e/run.sh
@@ -58,7 +58,7 @@ export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/kind-config-$KIND_CLUSTER_NAME}"
 if [ "${SKIP_CLUSTER_CREATION:-false}" = "false" ]; then
   echo "[dev-env] creating Kubernetes cluster with kind"
 
-  export K8S_VERSION=${K8S_VERSION:-v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab}
+  export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6}
 
   kind create cluster \
     --verbosity=${KIND_LOG_LEVEL} \
@@ -73,7 +73,7 @@ fi
 
 if [ "${SKIP_IMAGE_CREATION:-false}" = "false" ]; then
   if ! command -v ginkgo &> /dev/null; then
-    go get github.com/onsi/ginkgo/ginkgo
+    go get github.com/onsi/ginkgo/ginkgo@v1.16.4
   fi
 
   echo "[dev-env] building image"
diff --git a/test/e2e/servicebackend/service_backend.go b/test/e2e/servicebackend/service_backend.go
index 86f39b8425..0467e434e3 100644
--- a/test/e2e/servicebackend/service_backend.go
+++ b/test/e2e/servicebackend/service_backend.go
@@ -22,13 +22,14 @@ import (
 
 	"github.com/onsi/ginkgo"
 	corev1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
+var pathtype = networking.PathTypePrefix
 var _ = framework.IngressNginxDescribe("[Service] backend status code 503", func() {
 	f := framework.NewDefaultFramework("service-backend")
 
@@ -79,6 +80,7 @@ func buildIngressWithNonexistentService(host, namespace, path string) *networkin
 			Namespace: namespace,
 		},
 		Spec: networking.IngressSpec{
+			IngressClassName: framework.GetIngressClassName(namespace),
 			Rules: []networking.IngressRule{
 				{
 					Host: host,
@@ -86,10 +88,15 @@ func buildIngressWithNonexistentService(host, namespace, path string) *networkin
 						HTTP: &networking.HTTPIngressRuleValue{
 							Paths: []networking.HTTPIngressPath{
 								{
-									Path: path,
+									Path:     path,
+									PathType: &pathtype,
 									Backend: networking.IngressBackend{
-										ServiceName: backendService,
-										ServicePort: intstr.FromInt(80),
+										Service: &networking.IngressServiceBackend{
+											Name: backendService,
+											Port: networking.ServiceBackendPort{
+												Number: int32(80),
+											},
+										},
 									},
 								},
 							},
@@ -109,6 +116,7 @@ func buildIngressWithUnavailableServiceEndpoints(host, namespace, path string) (
 				Namespace: namespace,
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: framework.GetIngressClassName(namespace),
 				Rules: []networking.IngressRule{
 					{
 						Host: host,
@@ -116,10 +124,15 @@ func buildIngressWithUnavailableServiceEndpoints(host, namespace, path string) (
 							HTTP: &networking.HTTPIngressRuleValue{
 								Paths: []networking.HTTPIngressPath{
 									{
-										Path: path,
+										Path:     path,
+										PathType: &pathtype,
 										Backend: networking.IngressBackend{
-											ServiceName: backendService,
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: backendService,
+												Port: networking.ServiceBackendPort{
+													Number: int32(80),
+												},
+											},
 										},
 									},
 								},
diff --git a/test/e2e/servicebackend/service_externalname.go b/test/e2e/servicebackend/service_externalname.go
index bd10519e77..2c33c020f3 100644
--- a/test/e2e/servicebackend/service_externalname.go
+++ b/test/e2e/servicebackend/service_externalname.go
@@ -25,8 +25,8 @@ import (
 	"github.com/gavv/httpexpect/v2"
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
-	core "k8s.io/api/core/v1"
 	corev1 "k8s.io/api/core/v1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/intstr"
 
@@ -42,7 +42,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -73,7 +73,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should return 200 for service type=ExternalName without a port defined", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -107,7 +107,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should return 200 for service type=ExternalName with a port defined", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -148,7 +148,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should return status 502 for service type=ExternalName with an invalid host", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -179,7 +179,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should return 200 for service type=ExternalName using a port name", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -203,7 +203,15 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
 		}
 		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
-		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
+		namedBackend := networking.IngressBackend{
+			Service: &networking.IngressServiceBackend{
+				Name: framework.HTTPBinService,
+				Port: networking.ServiceBackendPort{
+					Name: host,
+				},
+			},
+		}
+		ing.Spec.Rules[0].HTTP.Paths[0].Backend = namedBackend
 		f.EnsureIngress(ing)
 
 		f.WaitForNginxServer(host,
@@ -221,7 +229,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should return 200 for service type=ExternalName using FQDN with trailing dot", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -252,7 +260,7 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 	ginkgo.It("should update the external name after a service update", func() {
 		host := "echo"
 
-		svc := &core.Service{
+		svc := &corev1.Service{
 			ObjectMeta: metav1.ObjectMeta{
 				Name:      framework.HTTPBinService,
 				Namespace: f.Namespace,
@@ -276,7 +284,15 @@ var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
 			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
 		}
 		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
-		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
+		namedBackend := networking.IngressBackend{
+			Service: &networking.IngressServiceBackend{
+				Name: framework.HTTPBinService,
+				Port: networking.ServiceBackendPort{
+					Name: host,
+				},
+			},
+		}
+		ing.Spec.Rules[0].HTTP.Paths[0].Backend = namedBackend
 		f.EnsureIngress(ing)
 
 		f.WaitForNginxServer(host,
diff --git a/test/e2e/settings/disable_catch_all.go b/test/e2e/settings/disable_catch_all.go
index 1a8791d807..f5d9bfadc4 100644
--- a/test/e2e/settings/disable_catch_all.go
+++ b/test/e2e/settings/disable_catch_all.go
@@ -24,9 +24,8 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 	appsv1 "k8s.io/api/apps/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
@@ -98,9 +97,13 @@ var _ = framework.IngressNginxDescribe("[Flag] disable-catch-all", func() {
 
 		err := framework.UpdateIngress(f.KubeClientSet, f.Namespace, host, func(ingress *networking.Ingress) error {
 			ingress.Spec.Rules = nil
-			ingress.Spec.Backend = &networking.IngressBackend{
-				ServiceName: framework.EchoService,
-				ServicePort: intstr.FromInt(80),
+			ingress.Spec.DefaultBackend = &networking.IngressBackend{
+				Service: &networking.IngressServiceBackend{
+					Name: framework.EchoService,
+					Port: networking.ServiceBackendPort{
+						Number: int32(80),
+					},
+				},
 			}
 			return nil
 		})
diff --git a/test/e2e/settings/global_external_auth.go b/test/e2e/settings/global_external_auth.go
old mode 100755
new mode 100644
index 7960b6ca75..1e5bf4301c
--- a/test/e2e/settings/global_external_auth.go
+++ b/test/e2e/settings/global_external_auth.go
@@ -25,7 +25,7 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
diff --git a/test/e2e/settings/global_options.go b/test/e2e/settings/global_options.go
new file mode 100644
index 0000000000..ef0487cc57
--- /dev/null
+++ b/test/e2e/settings/global_options.go
@@ -0,0 +1,58 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+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 settings
+
+import (
+	"fmt"
+	"strings"
+	"syscall"
+
+	"github.com/onsi/ginkgo"
+	"k8s.io/ingress-nginx/test/e2e/framework"
+)
+
+var _ = framework.IngressNginxDescribe("global-options", func() {
+	f := framework.NewDefaultFramework("global-options")
+
+	ginkgo.It("should have worker_rlimit_nofile option", func() {
+		f.WaitForNginxConfiguration(func(server string) bool {
+			return strings.Contains(server, fmt.Sprintf("worker_rlimit_nofile %d;", rlimitMaxNumFiles()-1024))
+
+		})
+	})
+
+	ginkgo.It("should have worker_rlimit_nofile option and be independent on amount of worker processes", func() {
+		f.SetNginxConfigMapData(map[string]string{
+			"worker-processes": "11",
+		})
+
+		f.WaitForNginxConfiguration(func(server string) bool {
+			return strings.Contains(server, "worker_processes 11;") &&
+				strings.Contains(server, fmt.Sprintf("worker_rlimit_nofile %d;", rlimitMaxNumFiles()-1024))
+		})
+	})
+})
+
+// rlimitMaxNumFiles returns hard limit for RLIMIT_NOFILE
+func rlimitMaxNumFiles() int {
+	var rLimit syscall.Rlimit
+	err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
+	if err != nil {
+		return 0
+	}
+	return int(rLimit.Max)
+}
diff --git a/test/e2e/settings/ingress_class.go b/test/e2e/settings/ingress_class.go
index 1fa02183f1..3ba42f3113 100644
--- a/test/e2e/settings/ingress_class.go
+++ b/test/e2e/settings/ingress_class.go
@@ -18,7 +18,6 @@ package settings
 
 import (
 	"context"
-	"fmt"
 	"net/http"
 	"strings"
 	"sync"
@@ -26,13 +25,11 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 	appsv1 "k8s.io/api/apps/v1"
-	networking "k8s.io/api/networking/v1beta1"
-	rbacv1 "k8s.io/api/rbac/v1"
+	networkingv1 "k8s.io/api/networking/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
-	"k8s.io/ingress-nginx/internal/k8s"
+	"k8s.io/ingress-nginx/internal/ingress/controller/ingressclass"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
@@ -41,43 +38,20 @@ var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() {
 
 	var doOnce sync.Once
 
-	testIngressClassName := "test-new-ingress-class"
+	otherIngressClassName := "test-new-ingress-class"
+	otherController := "k8s.io/other-class"
 
 	ginkgo.BeforeEach(func() {
 		f.NewEchoDeploymentWithReplicas(1)
 
 		doOnce.Do(func() {
-			f.KubeClientSet.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{
-				ObjectMeta: metav1.ObjectMeta{Name: "ingress-nginx-class"},
-				Rules: []rbacv1.PolicyRule{{
-					APIGroups: []string{"networking.k8s.io"},
-					Resources: []string{"ingressclasses"},
-					Verbs:     []string{"get", "list", "watch"},
-				}},
-			}, metav1.CreateOptions{})
-
-			f.KubeClientSet.RbacV1().ClusterRoleBindings().Create(context.TODO(), &rbacv1.ClusterRoleBinding{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "ingress-nginx-class",
-				},
-				RoleRef: rbacv1.RoleRef{
-					APIGroup: "rbac.authorization.k8s.io",
-					Kind:     "ClusterRole",
-					Name:     "ingress-nginx-class",
-				},
-			}, metav1.CreateOptions{})
-
-			if !f.IsIngressV1Beta1Ready {
-				return
-			}
-
-			_, err := f.KubeClientSet.NetworkingV1beta1().IngressClasses().
-				Create(context.TODO(), &networking.IngressClass{
+			_, err := f.KubeClientSet.NetworkingV1().IngressClasses().
+				Create(context.TODO(), &networkingv1.IngressClass{
 					ObjectMeta: metav1.ObjectMeta{
-						Name: testIngressClassName,
+						Name: otherIngressClassName,
 					},
-					Spec: networking.IngressClassSpec{
-						Controller: k8s.IngressNGINXController,
+					Spec: networkingv1.IngressClassSpec{
+						Controller: otherController,
 					},
 				}, metav1.CreateOptions{})
 
@@ -87,17 +61,23 @@ var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() {
 		})
 	})
 
-	ginkgo.Context("Without a specific ingress-class", func() {
-		ginkgo.It("should ignore Ingress with class", func() {
+	ginkgo.Context("With default ingress class config", func() {
+		ginkgo.It("should ignore Ingress with a different class annotation", func() {
 			invalidHost := "foo"
 			annotations := map[string]string{
-				class.IngressKey: "testclass",
+				ingressclass.IngressKey: "testclass",
 			}
 			ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, annotations)
+			// We should drop the ingressClassName here as we just want to rely on the annotation in this test
+			ing.Spec.IngressClassName = nil
 			f.EnsureIngress(ing)
 
 			validHost := "bar"
-			ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil)
+			annotationClass := map[string]string{
+				ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
+			}
+			ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotationClass)
+			ing.Spec.IngressClassName = nil
 			f.EnsureIngress(ing)
 
 			f.WaitForNginxConfiguration(func(cfg string) bool {
@@ -117,225 +97,417 @@ var _ = framework.IngressNginxDescribe("[Flag] ingress-class", func() {
 				Expect().
 				Status(http.StatusOK)
 		})
-	})
 
-	ginkgo.Context("With a specific ingress-class", func() {
-		ginkgo.BeforeEach(func() {
-			err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
-				args := []string{}
-				for _, v := range deployment.Spec.Template.Spec.Containers[0].Args {
-					if strings.Contains(v, "--ingress-class") {
-						continue
-					}
-
-					args = append(args, v)
-				}
+		ginkgo.It("should ignore Ingress with different controller class", func() {
+			invalidHost := "foo-1"
+			ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = &otherIngressClassName
+			f.EnsureIngress(ing)
 
-				args = append(args, "--ingress-class=testclass")
-				deployment.Spec.Template.Spec.Containers[0].Args = args
-				_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
+			validHost := "bar-1"
+			ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil)
+			f.EnsureIngress(ing)
 
-				return err
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return !strings.Contains(cfg, "server_name foo-1") &&
+					strings.Contains(cfg, "server_name bar-1")
 			})
-			assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
-		})
 
-		ginkgo.It("should ignore Ingress with no class", func() {
-			invalidHost := "bar"
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", invalidHost).
+				Expect().
+				Status(http.StatusNotFound)
 
-			ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil)
-			f.EnsureIngress(ing)
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHost).
+				Expect().
+				Status(http.StatusOK)
+		})
 
-			validHost := "foo"
-			annotations := map[string]string{
-				class.IngressKey: "testclass",
+		ginkgo.It("should accept both Ingresses with default IngressClassName and IngressClass annotation", func() {
+			validHostAnnotation := "foo-ok"
+			annotationClass := map[string]string{
+				ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
 			}
-			ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotations)
+			ing := framework.NewSingleIngress(validHostAnnotation, "/", validHostAnnotation, f.Namespace, framework.EchoService, 80, annotationClass)
+			// We need to drop the Class here as we just want the annotation
+			ing.Spec.IngressClassName = nil
 			f.EnsureIngress(ing)
 
-			f.WaitForNginxServer(validHost, func(cfg string) bool {
-				return strings.Contains(cfg, "server_name foo")
-			})
+			validHostClass := "bar-ok"
+			ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil)
+			f.EnsureIngress(ing)
 
 			f.WaitForNginxConfiguration(func(cfg string) bool {
-				return !strings.Contains(cfg, "server_name bar")
+				return strings.Contains(cfg, "server_name foo-ok") &&
+					strings.Contains(cfg, "server_name bar-ok")
 			})
 
 			f.HTTPTestClient().
 				GET("/").
-				WithHeader("Host", validHost).
+				WithHeader("Host", validHostAnnotation).
 				Expect().
 				Status(http.StatusOK)
 
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHostClass).
+				Expect().
+				Status(http.StatusOK)
+		})
+
+		ginkgo.It("should ignore Ingress without IngressClass configuration", func() {
+			invalidHost := "foo-invalid"
+			ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			validHostClass := "bar-valid"
+			ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil)
+			f.EnsureIngress(ing)
+
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return !strings.Contains(cfg, "server_name foo-invalid") &&
+					strings.Contains(cfg, "server_name bar-valid")
+			})
+
 			f.HTTPTestClient().
 				GET("/").
 				WithHeader("Host", invalidHost).
 				Expect().
 				Status(http.StatusNotFound)
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHostClass).
+				Expect().
+				Status(http.StatusOK)
 		})
 
 		ginkgo.It("should delete Ingress when class is removed", func() {
-			host := "foo"
+			hostAnnotation := "foo-annotation"
+
 			annotations := map[string]string{
-				class.IngressKey: "testclass",
+				ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
 			}
-			ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
+			ing := framework.NewSingleIngress(hostAnnotation, "/", hostAnnotation, f.Namespace, framework.EchoService, 80, annotations)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			hostClass := "foo-class"
+			ing = framework.NewSingleIngress(hostClass, "/", hostClass, f.Namespace, framework.EchoService, 80, nil)
 			f.EnsureIngress(ing)
 
-			f.WaitForNginxServer(host, func(cfg string) bool {
-				return strings.Contains(cfg, "server_name foo")
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return strings.Contains(cfg, "server_name foo-annotation") &&
+					strings.Contains(cfg, "server_name foo-class")
 			})
 
 			f.HTTPTestClient().
 				GET("/").
-				WithHeader("Host", host).
+				WithHeader("Host", hostAnnotation).
 				Expect().
 				Status(http.StatusOK)
 
-			ing, err := f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostClass).
+				Expect().
+				Status(http.StatusOK)
+
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostAnnotation, metav1.GetOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			delete(ing.Annotations, ingressclass.IngressKey)
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			ingWithClass, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostClass, metav1.GetOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
-			delete(ing.Annotations, class.IngressKey)
-			_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+			ingWithClass.Spec.IngressClassName = nil
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ingWithClass.Namespace).Update(context.TODO(), ingWithClass, metav1.UpdateOptions{})
 			assert.Nil(ginkgo.GinkgoT(), err)
 
 			framework.Sleep()
 
 			f.WaitForNginxConfiguration(func(cfg string) bool {
-				return !strings.Contains(cfg, "server_name foo")
+				return !strings.Contains(cfg, "server_name foo-annotation") &&
+					!strings.Contains(cfg, "server_name foo-class")
 			})
 
 			f.HTTPTestClient().
 				GET("/").
-				WithHeader("Host", host).
+				WithHeader("Host", hostAnnotation).
+				Expect().
+				Status(http.StatusNotFound)
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostClass).
 				Expect().
 				Status(http.StatusNotFound)
 		})
-	})
 
-	ginkgo.It("check scenarios for IngressClass and ingress.class annotation", func() {
-		if !f.IsIngressV1Beta1Ready {
-			ginkgo.Skip("Test requires Kubernetes v1.18 or higher")
-		}
+		ginkgo.It("should serve Ingress when class is added", func() {
+			hostNoAnnotation := "foo-no-annotation"
 
-		pod := f.GetIngressNGINXPod()
+			ing := framework.NewSingleIngress(hostNoAnnotation, "/", hostNoAnnotation, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
 
-		crb, err := f.KubeClientSet.RbacV1().ClusterRoleBindings().Get(context.Background(), "ingress-nginx-class", metav1.GetOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err, "searching cluster role binding")
+			hostNoClass := "foo-no-class"
+			ing = framework.NewSingleIngress(hostNoClass, "/", hostNoClass, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
 
-		// add service of current namespace
-		crb.Subjects = append(crb.Subjects, rbacv1.Subject{
-			APIGroup:  "",
-			Kind:      "ServiceAccount",
-			Name:      pod.Spec.ServiceAccountName,
-			Namespace: f.Namespace,
-		})
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return !strings.Contains(cfg, "server_name foo-no-nnotation") &&
+					!strings.Contains(cfg, "server_name foo-no-class")
+			})
 
-		_, err = f.KubeClientSet.RbacV1().ClusterRoleBindings().Update(context.Background(), crb, metav1.UpdateOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err, "searching cluster role binding")
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostNoAnnotation).
+				Expect().
+				Status(http.StatusNotFound)
 
-		err = f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
-			args := []string{}
-			for _, v := range deployment.Spec.Template.Spec.Containers[0].Args {
-				if strings.Contains(v, "--ingress-class") {
-					continue
-				}
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostNoClass).
+				Expect().
+				Status(http.StatusNotFound)
 
-				args = append(args, v)
+			ing, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostNoAnnotation, metav1.GetOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			annotation := map[string]string{
+				ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
 			}
+			ing.Annotations = annotation
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ing.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			ingWithClass, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostNoClass, metav1.GetOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			ingWithClass.Spec.IngressClassName = framework.GetIngressClassName(f.Namespace)
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ingWithClass.Namespace).Update(context.TODO(), ingWithClass, metav1.UpdateOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
 
-			args = append(args, fmt.Sprintf("--ingress-class=%v", testIngressClassName))
-			deployment.Spec.Template.Spec.Containers[0].Args = args
-			_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
-			return err
+			framework.Sleep()
+
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return strings.Contains(cfg, "server_name foo-no-annotation") &&
+					strings.Contains(cfg, "server_name foo-no-class")
+			})
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostNoAnnotation).
+				Expect().
+				Status(http.StatusOK)
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostNoClass).
+				Expect().
+				Status(http.StatusOK)
 		})
-		assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
 
-		host := "ingress.class"
+		ginkgo.It("should serve Ingress when class is updated between annotation and ingressClassName", func() {
+			hostAnnotation2class := "foo-annotation2class"
+			annotationClass := map[string]string{
+				ingressclass.IngressKey: ingressclass.DefaultAnnotationValue,
+			}
+			ing := framework.NewSingleIngress(hostAnnotation2class, "/", hostAnnotation2class, f.Namespace, framework.EchoService, 80, annotationClass)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			hostClass2Annotation := "foo-class2annotation"
+			ing = framework.NewSingleIngress(hostClass2Annotation, "/", hostClass2Annotation, f.Namespace, framework.EchoService, 80, nil)
+			f.EnsureIngress(ing)
+
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return strings.Contains(cfg, "server_name foo-annotation2class") &&
+					strings.Contains(cfg, "server_name foo-class2annotation")
+			})
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostAnnotation2class).
+				Expect().
+				Status(http.StatusOK)
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostClass2Annotation).
+				Expect().
+				Status(http.StatusOK)
+
+			ingAnnotation2Class, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostAnnotation2class, metav1.GetOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
 
-		ginkgo.By("only having IngressClassName")
-		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, nil)
-		ing.Spec.IngressClassName = &testIngressClassName
-		f.EnsureIngress(ing)
+			delete(ingAnnotation2Class.Annotations, ingressclass.IngressKey)
+			ingAnnotation2Class.Spec.IngressClassName = framework.GetIngressClassName(ingAnnotation2Class.Namespace)
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ingAnnotation2Class.Namespace).Update(context.TODO(), ingAnnotation2Class, metav1.UpdateOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			ingClass2Annotation, err := f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), hostClass2Annotation, metav1.GetOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
 
-		f.WaitForNginxConfiguration(func(cfg string) bool {
-			return strings.Contains(cfg, fmt.Sprintf("server_name %v", host))
+			ingClass2Annotation.Spec.IngressClassName = nil
+			ingClass2Annotation.Annotations = annotationClass
+			_, err = f.KubeClientSet.NetworkingV1().Ingresses(ingClass2Annotation.Namespace).Update(context.TODO(), ingClass2Annotation, metav1.UpdateOptions{})
+			assert.Nil(ginkgo.GinkgoT(), err)
+
+			framework.Sleep()
+
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return strings.Contains(cfg, "server_name foo-annotation2class") &&
+					strings.Contains(cfg, "server_name foo-class2annotation")
+			})
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostAnnotation2class).
+				Expect().
+				Status(http.StatusOK)
+
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", hostClass2Annotation).
+				Expect().
+				Status(http.StatusOK)
 		})
 
-		f.HTTPTestClient().
-			GET("/").
-			WithHeader("Host", host).
-			Expect().
-			Status(http.StatusOK)
+	})
 
-		ginkgo.By("only having ingress.class annotation")
-		ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
+	ginkgo.Context("With specific ingress-class flags", func() {
+		ginkgo.BeforeEach(func() {
+			err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
+				args := []string{}
+				for _, v := range deployment.Spec.Template.Spec.Containers[0].Args {
+					if strings.Contains(v, "--ingress-class") && strings.Contains(v, "--controller-class") {
+						continue
+					}
 
-		ing.Annotations = map[string]string{
-			class.IngressKey: testIngressClassName,
-		}
-		ing.Spec.IngressClassName = nil
+					args = append(args, v)
+				}
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
+				args = append(args, "--ingress-class=testclass")
+				args = append(args, "--controller-class=k8s.io/other-class")
+				deployment.Spec.Template.Spec.Containers[0].Args = args
+				_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
 
-		f.WaitForNginxConfiguration(func(cfg string) bool {
-			return strings.Contains(cfg, fmt.Sprintf("server_name %v", host))
+				return err
+			})
+			assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
 		})
 
-		framework.Sleep()
+		ginkgo.It("should ignore Ingress with no class and accept the correctly configured Ingresses", func() {
+			invalidHost := "bar"
+
+			ing := framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			validHost := "foo"
+			annotations := map[string]string{
+				ingressclass.IngressKey: "testclass",
+			}
+			ing = framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, annotations)
+			// Delete the IngressClass as we want just the annotation here
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			validHostClass := "foobar123"
+			ing = framework.NewSingleIngress(validHostClass, "/", validHostClass, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = &otherIngressClassName
+			f.EnsureIngress(ing)
 
-		f.HTTPTestClient().
-			GET("/").
-			WithHeader("Host", host).
-			Expect().
-			Status(http.StatusOK)
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return !strings.Contains(cfg, "server_name bar") &&
+					strings.Contains(cfg, "server_name foo") &&
+					strings.Contains(cfg, "server_name foobar123")
+			})
 
-		ginkgo.By("having an invalid ingress.class annotation and no IngressClassName")
-		ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHost).
+				Expect().
+				Status(http.StatusOK)
 
-		ing.Annotations = map[string]string{
-			class.IngressKey: "invalid",
-		}
-		ing.Spec.IngressClassName = nil
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHostClass).
+				Expect().
+				Status(http.StatusOK)
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", invalidHost).
+				Expect().
+				Status(http.StatusNotFound)
+		})
 
-		framework.Sleep()
+	})
 
-		f.WaitForNginxConfiguration(func(cfg string) bool {
-			return !strings.Contains(cfg, fmt.Sprintf("server_name %v", host))
+	ginkgo.Context("With watch-ingress-without-class flag", func() {
+		ginkgo.BeforeEach(func() {
+			err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
+				args := []string{}
+				for _, v := range deployment.Spec.Template.Spec.Containers[0].Args {
+					if strings.Contains(v, "--watch-ingress-without-class") && strings.Contains(v, "--controller-class") {
+						continue
+					}
+
+					args = append(args, v)
+				}
+
+				args = append(args, "--watch-ingress-without-class")
+				deployment.Spec.Template.Spec.Containers[0].Args = args
+				_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
+
+				return err
+			})
+			assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
 		})
 
-		f.HTTPTestClient().
-			GET("/").
-			WithHeader("Host", host).
-			Expect().
-			Status(http.StatusNotFound)
+		ginkgo.It("should watch Ingress with no class and ignore ingress with a different class", func() {
+			validHost := "bar"
 
-		ginkgo.By("not having ingress.class annotation and invalid IngressClassName")
-		ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
-		ing.Annotations = map[string]string{}
-		invalidClassName := "invalidclass"
-		ing.Spec.IngressClassName = &invalidClassName
+			ing := framework.NewSingleIngress(validHost, "/", validHost, f.Namespace, framework.EchoService, 80, nil)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
 
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Update(context.TODO(), ing, metav1.UpdateOptions{})
-		assert.Nil(ginkgo.GinkgoT(), err)
+			invalidHost := "foo"
+			annotations := map[string]string{
+				ingressclass.IngressKey: "testclass123",
+			}
+			ing = framework.NewSingleIngress(invalidHost, "/", invalidHost, f.Namespace, framework.EchoService, 80, annotations)
+			ing.Spec.IngressClassName = nil
+			f.EnsureIngress(ing)
+
+			f.WaitForNginxConfiguration(func(cfg string) bool {
+				return strings.Contains(cfg, "server_name bar") &&
+					!strings.Contains(cfg, "server_name foo")
+			})
 
-		framework.Sleep()
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", validHost).
+				Expect().
+				Status(http.StatusOK)
 
-		f.WaitForNginxConfiguration(func(cfg string) bool {
-			return !strings.Contains(cfg, fmt.Sprintf("server_name %v", host))
+			f.HTTPTestClient().
+				GET("/").
+				WithHeader("Host", invalidHost).
+				Expect().
+				Status(http.StatusNotFound)
 		})
 
-		f.HTTPTestClient().
-			GET("/").
-			WithHeader("Host", host).
-			Expect().
-			Status(http.StatusNotFound)
 	})
 })
diff --git a/test/e2e/settings/no_auth_locations.go b/test/e2e/settings/no_auth_locations.go
index dd7112b5ae..2d32b05d6b 100644
--- a/test/e2e/settings/no_auth_locations.go
+++ b/test/e2e/settings/no_auth_locations.go
@@ -25,9 +25,8 @@ import (
 	"github.com/onsi/ginkgo"
 	"github.com/stretchr/testify/assert"
 	corev1 "k8s.io/api/core/v1"
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
@@ -96,6 +95,7 @@ var _ = framework.DescribeSetting("[Security] no-auth-locations", func() {
 })
 
 func buildBasicAuthIngressWithSecondPath(host, namespace, secretName, pathName string) *networking.Ingress {
+	pathtype := networking.PathTypePrefix
 	return &networking.Ingress{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      host,
@@ -106,6 +106,7 @@ func buildBasicAuthIngressWithSecondPath(host, namespace, secretName, pathName s
 			},
 		},
 		Spec: networking.IngressSpec{
+			IngressClassName: framework.GetIngressClassName(namespace),
 			Rules: []networking.IngressRule{
 				{
 					Host: host,
@@ -113,17 +114,27 @@ func buildBasicAuthIngressWithSecondPath(host, namespace, secretName, pathName s
 						HTTP: &networking.HTTPIngressRuleValue{
 							Paths: []networking.HTTPIngressPath{
 								{
-									Path: "/",
+									Path:     "/",
+									PathType: &pathtype,
 									Backend: networking.IngressBackend{
-										ServiceName: framework.EchoService,
-										ServicePort: intstr.FromInt(80),
+										Service: &networking.IngressServiceBackend{
+											Name: framework.EchoService,
+											Port: networking.ServiceBackendPort{
+												Number: int32(80),
+											},
+										},
 									},
 								},
 								{
-									Path: pathName,
+									Path:     pathName,
+									PathType: &pathtype,
 									Backend: networking.IngressBackend{
-										ServiceName: framework.EchoService,
-										ServicePort: intstr.FromInt(80),
+										Service: &networking.IngressServiceBackend{
+											Name: framework.EchoService,
+											Port: networking.ServiceBackendPort{
+												Number: int32(80),
+											},
+										},
 									},
 								},
 							},
diff --git a/test/e2e/settings/server_tokens.go b/test/e2e/settings/server_tokens.go
index 43ccc86d3e..e84639b081 100644
--- a/test/e2e/settings/server_tokens.go
+++ b/test/e2e/settings/server_tokens.go
@@ -21,13 +21,13 @@ import (
 
 	"github.com/onsi/ginkgo"
 
-	networking "k8s.io/api/networking/v1beta1"
+	networking "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/intstr"
 	"k8s.io/ingress-nginx/test/e2e/framework"
 )
 
 var _ = framework.DescribeSetting("server-tokens", func() {
+	pathtype := networking.PathTypePrefix
 	f := framework.NewDefaultFramework("server-tokens")
 	serverTokens := "server-tokens"
 
@@ -57,6 +57,7 @@ var _ = framework.DescribeSetting("server-tokens", func() {
 				Annotations: map[string]string{},
 			},
 			Spec: networking.IngressSpec{
+				IngressClassName: &f.IngressClass,
 				Rules: []networking.IngressRule{
 					{
 						Host: serverTokens,
@@ -64,10 +65,15 @@ var _ = framework.DescribeSetting("server-tokens", func() {
 							HTTP: &networking.HTTPIngressRuleValue{
 								Paths: []networking.HTTPIngressPath{
 									{
-										Path: "/",
+										Path:     "/",
+										PathType: &pathtype,
 										Backend: networking.IngressBackend{
-											ServiceName: framework.EchoService,
-											ServicePort: intstr.FromInt(80),
+											Service: &networking.IngressServiceBackend{
+												Name: framework.EchoService,
+												Port: networking.ServiceBackendPort{
+													Number: int32(80),
+												},
+											},
 										},
 									},
 								},
diff --git a/test/e2e/status/update.go b/test/e2e/status/update.go
index af0c6b9a4f..23679afdc2 100644
--- a/test/e2e/status/update.go
+++ b/test/e2e/status/update.go
@@ -84,17 +84,17 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
 		err = cmd.Process.Kill()
 		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error terminating kubectl proxy")
 
-		ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+		ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error getting %s/%v Ingress", f.Namespace, host)
 
 		ing.Status.LoadBalancer.Ingress = []apiv1.LoadBalancerIngress{}
-		_, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).UpdateStatus(context.TODO(), ing, metav1.UpdateOptions{})
+		_, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).UpdateStatus(context.TODO(), ing, metav1.UpdateOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error cleaning Ingress status")
 		framework.Sleep(10 * time.Second)
 
 		err = f.KubeClientSet.CoreV1().
 			ConfigMaps(f.Namespace).
-			Delete(context.TODO(), "ingress-controller-leader-nginx", metav1.DeleteOptions{})
+			Delete(context.TODO(), "ingress-controller-leader", metav1.DeleteOptions{})
 		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error deleting leader election configmap")
 
 		_, cmd, err = f.KubectlProxy(port)
@@ -109,7 +109,7 @@ var _ = framework.IngressNginxDescribe("[Status] status update", func() {
 		}()
 
 		err = wait.Poll(5*time.Second, 4*time.Minute, func() (done bool, err error) {
-			ing, err = f.KubeClientSet.NetworkingV1beta1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
+			ing, err = f.KubeClientSet.NetworkingV1().Ingresses(f.Namespace).Get(context.TODO(), host, metav1.GetOptions{})
 			if err != nil {
 				return false, nil
 			}
diff --git a/test/e2e/wait-for-nginx.sh b/test/e2e/wait-for-nginx.sh
index 1eb8b32ccd..9a37d1ffcf 100755
--- a/test/e2e/wait-for-nginx.sh
+++ b/test/e2e/wait-for-nginx.sh
@@ -73,6 +73,10 @@ controller:
     periodSeconds: 1
   service:
     type: NodePort
+  electionID: ingress-controller-leader
+  ingressClassResource:
+    # We will create and remove each IC/ClusterRole/ClusterRoleBinding per test so there's no conflict
+    enabled: false
   extraArgs:
     tcp-services-configmap: $NAMESPACE/tcp-services
     # e2e tests do not require information about ingress status