bump nginx ingress chart to fix 2025 CVEs

Change-Id: I83eb8cc3088e53c083249256a93b7b66744ebe00
diff --git a/.charts.yml b/.charts.yml
index 6b1ed14..63d9b47 100644
--- a/.charts.yml
+++ b/.charts.yml
@@ -82,7 +82,7 @@
         review.opendev.org:
           - 919480
   - name: ingress-nginx
-    version: 4.10.1
+    version: 4.12.1
     repository:
       url: https://kubernetes.github.io/ingress-nginx
   - name: ironic
diff --git a/charts/ingress-nginx/Chart.yaml b/charts/ingress-nginx/Chart.yaml
index 1533a53..42d9f82 100644
--- a/charts/ingress-nginx/Chart.yaml
+++ b/charts/ingress-nginx/Chart.yaml
@@ -1,11 +1,9 @@
 annotations:
-  artifacthub.io/changes: |-
-    - "update post submit helm ci and clean up (#11221)"
-    - "refactor helm ci tests part I (#11188)"
-    - "Update Ingress-Nginx version controller-v1.10.1"
+  artifacthub.io/changes: |
+    - Update Ingress-Nginx version controller-v1.12.1
   artifacthub.io/prerelease: "false"
 apiVersion: v2
-appVersion: 1.10.1
+appVersion: 1.12.1
 description: Ingress controller for Kubernetes using NGINX as a reverse proxy and
   load balancer
 home: https://github.com/kubernetes/ingress-nginx
@@ -15,11 +13,11 @@
 - nginx
 kubeVersion: '>=1.21.0-0'
 maintainers:
+- name: cpanato
 - name: Gacko
-- name: rikatz
 - name: strongjz
 - name: tao12345666333
 name: ingress-nginx
 sources:
 - https://github.com/kubernetes/ingress-nginx
-version: 4.10.1
+version: 4.12.1
diff --git a/charts/ingress-nginx/OWNERS b/charts/ingress-nginx/OWNERS
index d588ede..428474f 100644
--- a/charts/ingress-nginx/OWNERS
+++ b/charts/ingress-nginx/OWNERS
@@ -1,10 +1,4 @@
 # See the OWNERS docs: https://www.kubernetes.dev/docs/guide/owners
 
-approvers:
-- ingress-nginx-helm-maintainers
-
-reviewers:
-- ingress-nginx-helm-reviewers
-
 labels:
 - area/helm
diff --git a/charts/ingress-nginx/README.md b/charts/ingress-nginx/README.md
index 882a26f..5861a73 100644
--- a/charts/ingress-nginx/README.md
+++ b/charts/ingress-nginx/README.md
@@ -2,7 +2,7 @@
 
 [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer
 
-![Version: 4.10.1](https://img.shields.io/badge/Version-4.10.1-informational?style=flat-square) ![AppVersion: 1.10.1](https://img.shields.io/badge/AppVersion-1.10.1-informational?style=flat-square)
+![Version: 4.12.1](https://img.shields.io/badge/Version-4.12.1-informational?style=flat-square) ![AppVersion: 1.12.1](https://img.shields.io/badge/AppVersion-1.12.1-informational?style=flat-square)
 
 To use, add `ingressClassName: nginx` spec field or the `kubernetes.io/ingress.class: nginx` annotation to your Ingress resources.
 
@@ -229,6 +229,24 @@
 
 As of version `1.26.0` of this chart, by simply not providing any clusterIP value, `invalid: spec.clusterIP: Invalid value: "": field is immutable` will no longer occur since `clusterIP: ""` will not be rendered.
 
+### Pod Security Admission
+
+You can use Pod Security Admission by applying labels to the `ingress-nginx` namespace as instructed by the [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels).
+
+Example:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: ingress-nginx
+  labels:
+    kubernetes.io/metadata.name: ingress-nginx
+    name: ingress-nginx
+    pod-security.kubernetes.io/enforce: restricted
+    pod-security.kubernetes.io/enforce-version: v1.31
+```
+
 ## Values
 
 | Key | Type | Default | Description |
@@ -242,9 +260,8 @@
 | controller.admissionWebhooks.certificate | string | `"/usr/local/certificates/cert"` |  |
 | controller.admissionWebhooks.createSecretJob.name | string | `"create"` |  |
 | controller.admissionWebhooks.createSecretJob.resources | object | `{}` |  |
-| controller.admissionWebhooks.createSecretJob.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for secret creation containers |
+| controller.admissionWebhooks.createSecretJob.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for secret creation containers |
 | controller.admissionWebhooks.enabled | bool | `true` |  |
-| controller.admissionWebhooks.existingPsp | string | `""` | Use an existing PSP instead of creating one |
 | controller.admissionWebhooks.extraEnvs | list | `[]` | Additional environment variables to set |
 | controller.admissionWebhooks.failurePolicy | string | `"Fail"` | Admission Webhook failure policy to use |
 | controller.admissionWebhooks.key | string | `"/usr/local/certificates/key"` |  |
@@ -253,21 +270,26 @@
 | controller.admissionWebhooks.namespaceSelector | object | `{}` |  |
 | controller.admissionWebhooks.objectSelector | object | `{}` |  |
 | controller.admissionWebhooks.patch.enabled | bool | `true` |  |
-| controller.admissionWebhooks.patch.image.digest | string | `"sha256:36d05b4077fb8e3d13663702fa337f124675ba8667cbd949c03a8e8ea6fa4366"` |  |
+| controller.admissionWebhooks.patch.image.digest | string | `"sha256:e8825994b7a2c7497375a9b945f386506ca6a3eda80b89b74ef2db743f66a5ea"` |  |
 | controller.admissionWebhooks.patch.image.image | string | `"ingress-nginx/kube-webhook-certgen"` |  |
 | controller.admissionWebhooks.patch.image.pullPolicy | string | `"IfNotPresent"` |  |
-| controller.admissionWebhooks.patch.image.registry | string | `"registry.k8s.io"` |  |
-| controller.admissionWebhooks.patch.image.tag | string | `"v1.4.1"` |  |
+| controller.admissionWebhooks.patch.image.tag | string | `"v1.5.2"` |  |
 | controller.admissionWebhooks.patch.labels | object | `{}` | Labels to be added to patch job resources |
 | controller.admissionWebhooks.patch.networkPolicy.enabled | bool | `false` | Enable 'networkPolicy' or not |
 | controller.admissionWebhooks.patch.nodeSelector."kubernetes.io/os" | string | `"linux"` |  |
 | controller.admissionWebhooks.patch.podAnnotations | object | `{}` |  |
 | controller.admissionWebhooks.patch.priorityClassName | string | `""` | Provide a priority class name to the webhook patching job # |
+| controller.admissionWebhooks.patch.rbac | object | `{"create":true}` | Admission webhook patch job RBAC |
+| controller.admissionWebhooks.patch.rbac.create | bool | `true` | Create RBAC or not |
 | controller.admissionWebhooks.patch.securityContext | object | `{}` | Security context for secret creation & webhook patch pods |
+| controller.admissionWebhooks.patch.serviceAccount | object | `{"automountServiceAccountToken":true,"create":true,"name":""}` | Admission webhook patch job service account |
+| controller.admissionWebhooks.patch.serviceAccount.automountServiceAccountToken | bool | `true` | Auto-mount service account token or not |
+| controller.admissionWebhooks.patch.serviceAccount.create | bool | `true` | Create a service account or not |
+| controller.admissionWebhooks.patch.serviceAccount.name | string | `""` | Custom service account name |
 | controller.admissionWebhooks.patch.tolerations | list | `[]` |  |
 | controller.admissionWebhooks.patchWebhookJob.name | string | `"patch"` |  |
 | controller.admissionWebhooks.patchWebhookJob.resources | object | `{}` |  |
-| controller.admissionWebhooks.patchWebhookJob.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for webhook patch containers |
+| controller.admissionWebhooks.patchWebhookJob.securityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"readOnlyRootFilesystem":true,"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532,"seccompProfile":{"type":"RuntimeDefault"}}` | Security context for webhook patch containers |
 | controller.admissionWebhooks.port | int | `8443` |  |
 | controller.admissionWebhooks.service.annotations | object | `{}` |  |
 | controller.admissionWebhooks.service.externalIPs | list | `[]` |  |
@@ -285,7 +307,7 @@
 | controller.autoscaling.targetCPUUtilizationPercentage | int | `50` |  |
 | controller.autoscaling.targetMemoryUtilizationPercentage | int | `50` |  |
 | controller.autoscalingTemplate | list | `[]` |  |
-| controller.config | object | `{}` | Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ |
+| controller.config | object | `{}` | Global configuration passed to the ConfigMap consumed by the controller. Values may contain Helm templates. Ref.: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/ |
 | controller.configAnnotations | object | `{}` | Annotations to be added to the controller config configuration configmap. |
 | controller.configMapNamespace | string | `""` | Allows customization of the configmap / nginx-configmap namespace; defaults to $(POD_NAMESPACE) |
 | controller.containerName | string | `"controller"` | Configures the controller container name |
@@ -293,18 +315,19 @@
 | controller.containerSecurityContext | object | `{}` | Security context for controller containers |
 | controller.customTemplate.configMapKey | string | `""` |  |
 | controller.customTemplate.configMapName | string | `""` |  |
+| controller.disableLeaderElection | bool | `false` | This configuration disable Nginx Controller Leader Election |
 | controller.dnsConfig | object | `{}` | Optionally customize the pod dnsConfig. |
 | controller.dnsPolicy | string | `"ClusterFirst"` | Optionally change this to ClusterFirstWithHostNet in case you have 'hostNetwork: true'. By default, while using host network, name resolution uses the host's DNS. If you wish nginx-controller to keep resolving names inside the k8s network, use ClusterFirstWithHostNet. |
 | controller.electionID | string | `""` | Election ID to use for status update, by default it uses the controller name combined with a suffix of 'leader' |
-| controller.enableAnnotationValidations | bool | `false` |  |
+| controller.electionTTL | string | `""` | Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s) |
+| controller.enableAnnotationValidations | bool | `true` |  |
 | controller.enableMimalloc | bool | `true` | Enable mimalloc as a drop-in replacement for malloc. # ref: https://github.com/microsoft/mimalloc # |
 | controller.enableTopologyAwareRouting | bool | `false` | This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto" Defaults to false |
-| controller.existingPsp | string | `""` | Use an existing PSP instead of creating one |
 | controller.extraArgs | object | `{}` | Additional command line arguments to pass to Ingress-Nginx Controller E.g. to specify the default SSL certificate you can use |
 | controller.extraContainers | list | `[]` | Additional containers to be added to the controller pod. See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example. |
 | controller.extraEnvs | list | `[]` | Additional environment variables to set |
 | controller.extraInitContainers | list | `[]` | Containers, which are run before the app containers are started. |
-| controller.extraModules | list | `[]` | Modules, which are mounted into the core nginx image. See values.yaml for a sample to add opentelemetry module |
+| controller.extraModules | list | `[]` | Modules, which are mounted into the core nginx image. |
 | controller.extraVolumeMounts | list | `[]` | Additional volumeMounts to the controller main container. |
 | controller.extraVolumes | list | `[]` | Additional volumes to the controller pod. |
 | controller.healthCheckHost | string | `""` | Address to bind the health check endpoint. It is better to set this option to the internal node address if the Ingress-Nginx Controller is running in the `hostNetwork: true` mode. |
@@ -317,19 +340,21 @@
 | controller.hostname | object | `{}` | Optionally customize the pod hostname. |
 | controller.image.allowPrivilegeEscalation | bool | `false` |  |
 | controller.image.chroot | bool | `false` |  |
-| controller.image.digest | string | `"sha256:e24f39d3eed6bcc239a56f20098878845f62baa34b9f2be2fd2c38ce9fb0f29e"` |  |
-| controller.image.digestChroot | string | `"sha256:c155954116b397163c88afcb3252462771bd7867017e8a17623e83601bab7ac7"` |  |
+| controller.image.digest | string | `"sha256:d2fbc4ec70d8aa2050dd91a91506e998765e86c96f32cffb56c503c9c34eed5b"` |  |
+| controller.image.digestChroot | string | `"sha256:90155c86548e0bb95b3abf1971cd687d8f5d43f340cfca0ad3484e2b8351096e"` |  |
 | controller.image.image | string | `"ingress-nginx/controller"` |  |
 | controller.image.pullPolicy | string | `"IfNotPresent"` |  |
 | controller.image.readOnlyRootFilesystem | bool | `false` |  |
-| controller.image.registry | string | `"registry.k8s.io"` |  |
+| controller.image.runAsGroup | int | `82` | This value must not be changed using the official image. uid=101(www-data) gid=82(www-data) groups=82(www-data) |
 | controller.image.runAsNonRoot | bool | `true` |  |
-| controller.image.runAsUser | int | `101` |  |
+| controller.image.runAsUser | int | `101` | This value must not be changed using the official image. uid=101(www-data) gid=82(www-data) groups=82(www-data) |
 | controller.image.seccompProfile.type | string | `"RuntimeDefault"` |  |
-| controller.image.tag | string | `"v1.10.1"` |  |
+| controller.image.tag | string | `"v1.12.1"` |  |
 | controller.ingressClass | string | `"nginx"` | For backwards compatibility with ingress.class annotation, use ingressClass. Algorithm is as follows, first ingressClassName is considered, if not present, controller looks for ingress.class annotation |
 | controller.ingressClassByName | bool | `false` | Process IngressClass per name (additionally as per spec.controller). |
-| controller.ingressClassResource | object | `{"controllerValue":"k8s.io/ingress-nginx","default":false,"enabled":true,"name":"nginx","parameters":{}}` | This section refers to the creation of the IngressClass resource. IngressClasses are immutable and cannot be changed after creation. We do not support namespaced IngressClasses, yet, so a ClusterRole and a ClusterRoleBinding is required. |
+| controller.ingressClassResource | object | `{"aliases":[],"annotations":{},"controllerValue":"k8s.io/ingress-nginx","default":false,"enabled":true,"name":"nginx","parameters":{}}` | This section refers to the creation of the IngressClass resource. IngressClasses are immutable and cannot be changed after creation. We do not support namespaced IngressClasses, yet, so a ClusterRole and a ClusterRoleBinding is required. |
+| controller.ingressClassResource.aliases | list | `[]` | Aliases of this IngressClass. Creates copies with identical settings but the respective alias as name. Useful for development environments with only one Ingress Controller but production-like Ingress resources. `default` gets enabled on the original IngressClass only. |
+| controller.ingressClassResource.annotations | object | `{}` | Annotations to be added to the IngressClass resource. |
 | controller.ingressClassResource.controllerValue | string | `"k8s.io/ingress-nginx"` | Controller of the IngressClass. An Ingress Controller looks for IngressClasses it should reconcile by this value. This value is also being set as the `--controller-class` argument of this Ingress Controller. Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class |
 | controller.ingressClassResource.default | bool | `false` | If true, Ingresses without `ingressClassName` get assigned to this IngressClass on creation. Ingress creation gets rejected if there are multiple default IngressClasses. Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#default-ingress-class |
 | controller.ingressClassResource.enabled | bool | `true` | Create the IngressClass or not |
@@ -356,21 +381,23 @@
 | controller.livenessProbe.periodSeconds | int | `10` |  |
 | controller.livenessProbe.successThreshold | int | `1` |  |
 | controller.livenessProbe.timeoutSeconds | int | `1` |  |
-| controller.maxmindLicenseKey | string | `""` | Maxmind license key to download GeoLite2 Databases. # https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases |
+| controller.maxmindLicenseKey | string | `""` | Maxmind license key to download GeoLite2 Databases. # https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geolite2-databases/ |
 | controller.metrics.enabled | bool | `false` |  |
 | controller.metrics.port | int | `10254` |  |
 | controller.metrics.portName | string | `"metrics"` |  |
 | controller.metrics.prometheusRule.additionalLabels | object | `{}` |  |
+| controller.metrics.prometheusRule.annotations | object | `{}` | Annotations to be added to the PrometheusRule. |
 | controller.metrics.prometheusRule.enabled | bool | `false` |  |
 | controller.metrics.prometheusRule.rules | list | `[]` |  |
 | controller.metrics.service.annotations | object | `{}` |  |
+| controller.metrics.service.enabled | bool | `true` | Enable the metrics service or not. |
 | controller.metrics.service.externalIPs | list | `[]` | List of IP addresses at which the stats-exporter service is available # Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips # |
 | controller.metrics.service.labels | object | `{}` | Labels to be added to the metrics service resource |
 | controller.metrics.service.loadBalancerSourceRanges | list | `[]` |  |
 | controller.metrics.service.servicePort | int | `10254` |  |
 | controller.metrics.service.type | string | `"ClusterIP"` |  |
 | controller.metrics.serviceMonitor.additionalLabels | object | `{}` |  |
-| controller.metrics.serviceMonitor.annotations | object | `{}` |  |
+| controller.metrics.serviceMonitor.annotations | object | `{}` | Annotations to be added to the ServiceMonitor. |
 | controller.metrics.serviceMonitor.enabled | bool | `false` |  |
 | controller.metrics.serviceMonitor.metricRelabelings | list | `[]` |  |
 | controller.metrics.serviceMonitor.namespace | string | `""` |  |
@@ -383,24 +410,11 @@
 | controller.name | string | `"controller"` |  |
 | controller.networkPolicy.enabled | bool | `false` | Enable 'networkPolicy' or not |
 | controller.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node labels for controller pod assignment # Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ # |
-| controller.opentelemetry.containerSecurityContext.allowPrivilegeEscalation | bool | `false` |  |
-| controller.opentelemetry.containerSecurityContext.capabilities.drop[0] | string | `"ALL"` |  |
-| controller.opentelemetry.containerSecurityContext.readOnlyRootFilesystem | bool | `true` |  |
-| controller.opentelemetry.containerSecurityContext.runAsNonRoot | bool | `true` |  |
-| controller.opentelemetry.containerSecurityContext.runAsUser | int | `65532` | The image's default user, inherited from its base image `cgr.dev/chainguard/static`. |
-| controller.opentelemetry.containerSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` |  |
-| controller.opentelemetry.enabled | bool | `false` |  |
-| controller.opentelemetry.image.digest | string | `"sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472"` |  |
-| controller.opentelemetry.image.distroless | bool | `true` |  |
-| controller.opentelemetry.image.image | string | `"ingress-nginx/opentelemetry"` |  |
-| controller.opentelemetry.image.registry | string | `"registry.k8s.io"` |  |
-| controller.opentelemetry.image.tag | string | `"v20230721-3e2062ee5"` |  |
-| controller.opentelemetry.name | string | `"opentelemetry"` |  |
-| controller.opentelemetry.resources | object | `{}` |  |
 | controller.podAnnotations | object | `{}` | Annotations to be added to controller pods # |
 | controller.podLabels | object | `{}` | Labels to add to the pod container metadata |
 | controller.podSecurityContext | object | `{}` | Security context for controller pods |
 | controller.priorityClassName | string | `""` |  |
+| controller.progressDeadlineSeconds | int | `0` | Specifies the number of seconds you want to wait for the controller deployment to progress before the system reports back that it has failed. Ref.: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#progress-deadline-seconds |
 | controller.proxySetHeaders | object | `{}` | Will add custom headers before sending traffic to backends according to https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples/customization/custom-headers |
 | controller.publishService | object | `{"enabled":true,"pathOverride":""}` | Allows customization of the source of the IP address or FQDN to report in the ingress status field. By default, it reads the information provided by the service. If disable, the status field reports the IP address of the node or nodes where an ingress controller pod is running. |
 | controller.publishService.enabled | bool | `true` | Enable 'publishService' or not |
@@ -473,9 +487,10 @@
 | controller.topologySpreadConstraints | list | `[]` | Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in. # Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ # |
 | controller.udp.annotations | object | `{}` | Annotations to be added to the udp config configmap |
 | controller.udp.configMapNamespace | string | `""` | Allows customization of the udp-services-configmap; defaults to $(POD_NAMESPACE) |
+| controller.unhealthyPodEvictionPolicy | string | `""` | Eviction policy for unhealthy pods guarded by PodDisruptionBudget. Ref: https://kubernetes.io/blog/2023/01/06/unhealthy-pod-eviction-policy-for-pdbs/ |
 | controller.updateStrategy | object | `{}` | The update strategy to apply to the Deployment or DaemonSet # |
 | controller.watchIngressWithoutClass | bool | `false` | Process Ingress objects without ingressClass annotation/ingressClassName field Overrides value for --watch-ingress-without-class flag of the controller binary Defaults to false |
-| defaultBackend.affinity | object | `{}` |  |
+| defaultBackend.affinity | object | `{}` | Affinity and anti-affinity rules for server scheduling to nodes # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity |
 | defaultBackend.autoscaling.annotations | object | `{}` |  |
 | defaultBackend.autoscaling.enabled | bool | `false` |  |
 | defaultBackend.autoscaling.maxReplicas | int | `2` |  |
@@ -484,7 +499,6 @@
 | defaultBackend.autoscaling.targetMemoryUtilizationPercentage | int | `50` |  |
 | defaultBackend.containerSecurityContext | object | `{}` | Security context for default backend containers |
 | defaultBackend.enabled | bool | `false` |  |
-| defaultBackend.existingPsp | string | `""` | Use an existing PSP instead of creating one |
 | defaultBackend.extraArgs | object | `{}` |  |
 | defaultBackend.extraConfigMaps | list | `[]` |  |
 | defaultBackend.extraEnvs | list | `[]` | Additional environment variables to set for defaultBackend pods |
@@ -494,7 +508,7 @@
 | defaultBackend.image.image | string | `"defaultbackend-amd64"` |  |
 | defaultBackend.image.pullPolicy | string | `"IfNotPresent"` |  |
 | defaultBackend.image.readOnlyRootFilesystem | bool | `true` |  |
-| defaultBackend.image.registry | string | `"registry.k8s.io"` |  |
+| defaultBackend.image.runAsGroup | int | `65534` |  |
 | defaultBackend.image.runAsNonRoot | bool | `true` |  |
 | defaultBackend.image.runAsUser | int | `65534` |  |
 | defaultBackend.image.seccompProfile.type | string | `"RuntimeDefault"` |  |
@@ -505,7 +519,7 @@
 | defaultBackend.livenessProbe.periodSeconds | int | `10` |  |
 | defaultBackend.livenessProbe.successThreshold | int | `1` |  |
 | defaultBackend.livenessProbe.timeoutSeconds | int | `5` |  |
-| defaultBackend.minAvailable | int | `1` |  |
+| defaultBackend.minAvailable | int | `1` | Minimum available pods set in PodDisruptionBudget. Define either 'minAvailable' or 'maxUnavailable', never both. |
 | defaultBackend.minReadySeconds | int | `0` | `minReadySeconds` to avoid killing pods before we are ready # |
 | defaultBackend.name | string | `"defaultbackend"` |  |
 | defaultBackend.networkPolicy.enabled | bool | `false` | Enable 'networkPolicy' or not |
@@ -531,11 +545,13 @@
 | defaultBackend.serviceAccount.create | bool | `true` |  |
 | defaultBackend.serviceAccount.name | string | `""` |  |
 | defaultBackend.tolerations | list | `[]` | Node tolerations for server scheduling to nodes with taints # Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ # |
+| defaultBackend.topologySpreadConstraints | list | `[]` | Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in. Ref.: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ |
+| defaultBackend.unhealthyPodEvictionPolicy | string | `""` | Eviction policy for unhealthy pods guarded by PodDisruptionBudget. Ref: https://kubernetes.io/blog/2023/01/06/unhealthy-pod-eviction-policy-for-pdbs/ |
 | defaultBackend.updateStrategy | object | `{}` | The update strategy to apply to the Deployment or DaemonSet # |
 | dhParam | string | `""` | A base64-encoded Diffie-Hellman parameter. This can be generated with: `openssl dhparam 4096 2> /dev/null | base64` # Ref: https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples/customization/ssl-dh-param |
+| global.image.registry | string | `"registry.k8s.io"` | Registry host to pull images from. |
 | imagePullSecrets | list | `[]` | Optional array of imagePullSecrets containing private registry credentials # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ |
 | namespaceOverride | string | `""` | Override the deployment namespace; defaults to .Release.Namespace |
-| podSecurityPolicy.enabled | bool | `false` |  |
 | portNamePrefix | string | `""` | Prefix for TCP and UDP ports names in ingress controller service # Some cloud providers, like Yandex Cloud may have a requirements for a port name regex to support cloud load balancer integration |
 | rbac.create | bool | `true` |  |
 | rbac.scope | bool | `false` |  |
diff --git a/charts/ingress-nginx/README.md.gotmpl b/charts/ingress-nginx/README.md.gotmpl
index 17b029b..3cb9d56 100644
--- a/charts/ingress-nginx/README.md.gotmpl
+++ b/charts/ingress-nginx/README.md.gotmpl
@@ -226,4 +226,22 @@
 
 As of version `1.26.0` of this chart, by simply not providing any clusterIP value, `invalid: spec.clusterIP: Invalid value: "": field is immutable` will no longer occur since `clusterIP: ""` will not be rendered.
 
+### Pod Security Admission
+
+You can use Pod Security Admission by applying labels to the `ingress-nginx` namespace as instructed by the [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels).
+
+Example:
+
+```yaml
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: ingress-nginx
+  labels:
+    kubernetes.io/metadata.name: ingress-nginx
+    name: ingress-nginx
+    pod-security.kubernetes.io/enforce: restricted
+    pod-security.kubernetes.io/enforce-version: v1.31
+```
+
 {{ template "chart.valuesSection" . }}
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.1.2.md b/charts/ingress-nginx/changelog/helm-chart-4.1.2.md
index 0a1d80c..2061855 100644
--- a/charts/ingress-nginx/changelog/helm-chart-4.1.2.md
+++ b/charts/ingress-nginx/changelog/helm-chart-4.1.2.md
@@ -5,7 +5,7 @@
 ### 4.1.2
 
 * [8587](https://github.com/kubernetes/ingress-nginx/pull/8587) Add CAP_SYS_CHROOT to DS/PSP when needed
-* [8458](https://github.com/kubernetes/ingress-nginx/pull/8458) Add portNamePreffix Helm chart parameter
+* [8458](https://github.com/kubernetes/ingress-nginx/pull/8458) Add portNamePrefix Helm chart parameter
 * [8522](https://github.com/kubernetes/ingress-nginx/pull/8522) Add documentation for controller.service.loadBalancerIP in Helm chart
 
 **Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.1.0...helm-chart-4.1.2
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.10.2.md b/charts/ingress-nginx/changelog/helm-chart-4.10.2.md
new file mode 100644
index 0000000..399bd98
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.10.2.md
@@ -0,0 +1,18 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.10.2
+
+* Chores: Align security contacts & chart maintainers to actual owners. (#11480)
+* Fix helm install on cloud provider admonition block (#11412)
+* edited helm-install tips (#11411)
+* added info for aws helm install (#11410)
+* add workflow to helm release and update ct for branch (#11317)
+* Merge pull request #11277 from strongjz/chart-1.10.1 (#11314)
+* release helm chart from release branch (#11278)
+* update post submit helm ci and clean up (#11221)
+* refactor helm ci tests part I (#11188)
+* Update Ingress-Nginx version controller-v1.10.2
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.10.1...helm-chart-4.10.2
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.10.3.md b/charts/ingress-nginx/changelog/helm-chart-4.10.3.md
new file mode 100644
index 0000000..3f77d40
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.10.3.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.10.3
+
+* Update Ingress-Nginx version controller-v1.10.3
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.10.2...helm-chart-4.10.3
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.10.4.md b/charts/ingress-nginx/changelog/helm-chart-4.10.4.md
new file mode 100644
index 0000000..661d3c9
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.10.4.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.10.4
+
+* Update Ingress-Nginx version controller-v1.10.4
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.10.3...helm-chart-4.10.4
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.11.0.md b/charts/ingress-nginx/changelog/helm-chart-4.11.0.md
new file mode 100644
index 0000000..64108c0
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.11.0.md
@@ -0,0 +1,18 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.11.0
+
+* Chores: Align security contacts & chart maintainers to actual owners. (#11465)
+* Merge pull request #11277 from strongjz/chart-1.10.1 (#11415)
+* Fix helm install on cloud provider admonition block (#11394)
+* edited helm-install tips (#11393)
+* added info for aws helm install (#11390)
+* add workflow to helm release and update ct for branch (#11378)
+* release helm chart from release branch (#11276)
+* update post submit helm ci and clean up (#11220)
+* refactor helm ci tests part I (#11178)
+* Update Ingress-Nginx version controller-v1.11.0
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.10.2...helm-chart-4.11.0
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.11.1.md b/charts/ingress-nginx/changelog/helm-chart-4.11.1.md
new file mode 100644
index 0000000..281513e
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.11.1.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.11.1
+
+* Update Ingress-Nginx version controller-v1.11.1
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.11.0...helm-chart-4.11.1
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.11.2.md b/charts/ingress-nginx/changelog/helm-chart-4.11.2.md
new file mode 100644
index 0000000..c7645a5
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.11.2.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.11.2
+
+* Update Ingress-Nginx version controller-v1.11.2
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.11.1...helm-chart-4.11.2
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.12.0-beta.0.md b/charts/ingress-nginx/changelog/helm-chart-4.12.0-beta.0.md
new file mode 100644
index 0000000..fa980f1
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.12.0-beta.0.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.12.0-beta.0
+
+* Update Ingress-Nginx version controller-v1.12.0-beta.0
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.11.0...helm-chart-4.12.0-beta.0
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.12.0.md b/charts/ingress-nginx/changelog/helm-chart-4.12.0.md
new file mode 100644
index 0000000..f8f36d4
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.12.0.md
@@ -0,0 +1,10 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.12.0
+
+* CI: Fix chart testing. (#12258)
+* Update Ingress-Nginx version controller-v1.12.0
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.11.0...helm-chart-4.12.0
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.12.1.md b/charts/ingress-nginx/changelog/helm-chart-4.12.1.md
new file mode 100644
index 0000000..4d44373
--- /dev/null
+++ b/charts/ingress-nginx/changelog/helm-chart-4.12.1.md
@@ -0,0 +1,9 @@
+# Changelog
+
+This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
+
+### 4.12.1
+
+* Update Ingress-Nginx version controller-v1.12.1
+
+**Full Changelog**: https://github.com/kubernetes/ingress-nginx/compare/helm-chart-4.12.0...helm-chart-4.12.1
diff --git a/charts/ingress-nginx/changelog/helm-chart-4.7.0.md b/charts/ingress-nginx/changelog/helm-chart-4.7.0.md
index 7399da7..9d54070 100644
--- a/charts/ingress-nginx/changelog/helm-chart-4.7.0.md
+++ b/charts/ingress-nginx/changelog/helm-chart-4.7.0.md
@@ -6,7 +6,7 @@
 
 * helm: Fix opentelemetry module installation for daemonset (#9792)
 * Update charts/* to keep project name display aligned (#9931)
-* HPA: Use capabilites & align manifests. (#9521)
+* HPA: Use capabilities & align manifests. (#9521)
 * PodDisruptionBudget spec logic update (#9904)
 * add option for annotations in PodDisruptionBudget (#9843)
 * Update Ingress-Nginx version controller-v1.8.0
diff --git a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml b/charts/ingress-nginx/ci/admission-webhooks-cert-manager-values.yaml
similarity index 79%
copy from charts/ingress-nginx/ci/deamonset-webhook-values.yaml
copy to charts/ingress-nginx/ci/admission-webhooks-cert-manager-values.yaml
index 54d364d..7eafd0c 100644
--- a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml
+++ b/charts/ingress-nginx/ci/admission-webhooks-cert-manager-values.yaml
@@ -1,10 +1,12 @@
 controller:
-  kind: DaemonSet
   image:
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: true
+
   service:
     type: ClusterIP
+
+  admissionWebhooks:
+    certManager:
+      enabled: true
diff --git a/charts/ingress-nginx/ci/controller-admission-tls-cert-manager-values.yaml b/charts/ingress-nginx/ci/controller-admission-tls-cert-manager-values.yaml
deleted file mode 100644
index a13241c..0000000
--- a/charts/ingress-nginx/ci/controller-admission-tls-cert-manager-values.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-controller:
-  admissionWebhooks:
-    certManager:
-      enabled: true
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/controller-configmap-addheaders-values.yaml
similarity index 76%
copy from charts/ingress-nginx/ci/deployment-psp-values.yaml
copy to charts/ingress-nginx/ci/controller-configmap-addheaders-values.yaml
index 2f332a7..460a610 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/controller-configmap-addheaders-values.yaml
@@ -3,8 +3,9 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
+
   service:
     type: ClusterIP
 
-podSecurityPolicy:
-  enabled: true
+  addHeaders:
+    X-Frame-Options: deny
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/controller-configmap-proxyheaders-values.yaml
similarity index 73%
copy from charts/ingress-nginx/ci/deployment-psp-values.yaml
copy to charts/ingress-nginx/ci/controller-configmap-proxyheaders-values.yaml
index 2f332a7..e23a13c 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/controller-configmap-proxyheaders-values.yaml
@@ -3,8 +3,9 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
+
   service:
     type: ClusterIP
 
-podSecurityPolicy:
-  enabled: true
+  proxySetHeaders:
+    X-Forwarded-Proto: https
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/controller-configmap-values.yaml
similarity index 76%
copy from charts/ingress-nginx/ci/deployment-psp-values.yaml
copy to charts/ingress-nginx/ci/controller-configmap-values.yaml
index 2f332a7..a702989 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/controller-configmap-values.yaml
@@ -3,8 +3,9 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
+
   service:
     type: ClusterIP
 
-podSecurityPolicy:
-  enabled: true
+  config:
+    use-proxy-protocol: "true"
diff --git a/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml b/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml
deleted file mode 100644
index b28a232..0000000
--- a/charts/ingress-nginx/ci/controller-custom-ingressclass-flags.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-controller:
-  watchIngressWithoutClass: true
-  ingressClassResource:
-    name: custom-nginx
-    enabled: true
-    default: true
-    controllerValue: "k8s.io/custom-nginx"
diff --git a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml b/charts/ingress-nginx/ci/controller-daemonset-metrics-values.yaml
similarity index 88%
rename from charts/ingress-nginx/ci/deamonset-webhook-values.yaml
rename to charts/ingress-nginx/ci/controller-daemonset-metrics-values.yaml
index 54d364d..7a98580 100644
--- a/charts/ingress-nginx/ci/deamonset-webhook-values.yaml
+++ b/charts/ingress-nginx/ci/controller-daemonset-metrics-values.yaml
@@ -1,10 +1,13 @@
 controller:
-  kind: DaemonSet
   image:
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: true
+
   service:
     type: ClusterIP
+
+  kind: DaemonSet
+
+  metrics:
+    enabled: true
diff --git a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml b/charts/ingress-nginx/ci/controller-daemonset-podannotations-values.yaml
similarity index 81%
rename from charts/ingress-nginx/ci/daemonset-podannotations-values.yaml
rename to charts/ingress-nginx/ci/controller-daemonset-podannotations-values.yaml
index 0b55306..405992e 100644
--- a/charts/ingress-nginx/ci/daemonset-podannotations-values.yaml
+++ b/charts/ingress-nginx/ci/controller-daemonset-podannotations-values.yaml
@@ -1,17 +1,16 @@
 controller:
-  kind: DaemonSet
   image:
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: false
-  metrics:
-    enabled: true
+
   service:
     type: ClusterIP
+
+  kind: DaemonSet
+
   podAnnotations:
-    prometheus.io/path: /metrics
+    prometheus.io/scrape: "true"
     prometheus.io/port: "10254"
     prometheus.io/scheme: http
-    prometheus.io/scrape: "true"
+    prometheus.io/path: /metrics
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/controller-daemonset-values.yaml
similarity index 79%
rename from charts/ingress-nginx/ci/deployment-psp-values.yaml
rename to charts/ingress-nginx/ci/controller-daemonset-values.yaml
index 2f332a7..d34025c 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/controller-daemonset-values.yaml
@@ -3,8 +3,8 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
+
   service:
     type: ClusterIP
 
-podSecurityPolicy:
-  enabled: true
+  kind: DaemonSet
diff --git a/charts/ingress-nginx/ci/deployment-webhook-values.yaml b/charts/ingress-nginx/ci/controller-deployment-metrics-values.yaml
similarity index 81%
rename from charts/ingress-nginx/ci/deployment-webhook-values.yaml
rename to charts/ingress-nginx/ci/controller-deployment-metrics-values.yaml
index 76669a5..9c95d34 100644
--- a/charts/ingress-nginx/ci/deployment-webhook-values.yaml
+++ b/charts/ingress-nginx/ci/controller-deployment-metrics-values.yaml
@@ -3,7 +3,11 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: true
+
   service:
     type: ClusterIP
+
+  kind: Deployment
+
+  metrics:
+    enabled: true
diff --git a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml b/charts/ingress-nginx/ci/controller-deployment-podannotations-values.yaml
similarity index 80%
rename from charts/ingress-nginx/ci/deployment-podannotations-values.yaml
rename to charts/ingress-nginx/ci/controller-deployment-podannotations-values.yaml
index b48d93c..cf1f261 100644
--- a/charts/ingress-nginx/ci/deployment-podannotations-values.yaml
+++ b/charts/ingress-nginx/ci/controller-deployment-podannotations-values.yaml
@@ -3,14 +3,14 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: false
-  metrics:
-    enabled: true
+
   service:
     type: ClusterIP
+
+  kind: Deployment
+
   podAnnotations:
-    prometheus.io/path: /metrics
+    prometheus.io/scrape: "true"
     prometheus.io/port: "10254"
     prometheus.io/scheme: http
-    prometheus.io/scrape: "true"
+    prometheus.io/path: /metrics
diff --git a/charts/ingress-nginx/ci/deployment-psp-values.yaml b/charts/ingress-nginx/ci/controller-deployment-values.yaml
similarity index 79%
copy from charts/ingress-nginx/ci/deployment-psp-values.yaml
copy to charts/ingress-nginx/ci/controller-deployment-values.yaml
index 2f332a7..1b092dc 100644
--- a/charts/ingress-nginx/ci/deployment-psp-values.yaml
+++ b/charts/ingress-nginx/ci/controller-deployment-values.yaml
@@ -3,8 +3,8 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
+
   service:
     type: ClusterIP
 
-podSecurityPolicy:
-  enabled: true
+  kind: Deployment
diff --git a/charts/ingress-nginx/ci/deployment-autoscaling-behavior-values.yaml b/charts/ingress-nginx/ci/controller-hpa-values.yaml
similarity index 71%
rename from charts/ingress-nginx/ci/deployment-autoscaling-behavior-values.yaml
rename to charts/ingress-nginx/ci/controller-hpa-values.yaml
index dca3f35..54a0d2f 100644
--- a/charts/ingress-nginx/ci/deployment-autoscaling-behavior-values.yaml
+++ b/charts/ingress-nginx/ci/controller-hpa-values.yaml
@@ -1,4 +1,12 @@
 controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
+
+  service:
+    type: ClusterIP
+
   autoscaling:
     enabled: true
     behavior:
@@ -8,7 +16,3 @@
         - type: Pods
           value: 1
           periodSeconds: 180
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/controller-ingressclass-values.yaml b/charts/ingress-nginx/ci/controller-ingressclass-values.yaml
new file mode 100644
index 0000000..c06429f
--- /dev/null
+++ b/charts/ingress-nginx/ci/controller-ingressclass-values.yaml
@@ -0,0 +1,15 @@
+controller:
+  image:
+    repository: ingress-controller/controller
+    tag: 1.0.0-dev
+    digest: null
+
+  service:
+    type: ClusterIP
+
+  ingressClassResource:
+    name: custom-nginx
+    default: true
+    controllerValue: k8s.io/custom-nginx
+
+  watchIngressWithoutClass: true
diff --git a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml b/charts/ingress-nginx/ci/controller-service-internal-values.yaml
similarity index 81%
rename from charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml
rename to charts/ingress-nginx/ci/controller-service-internal-values.yaml
index 0a200a7..11108fb 100644
--- a/charts/ingress-nginx/ci/daemonset-internal-lb-values.yaml
+++ b/charts/ingress-nginx/ci/controller-service-internal-values.yaml
@@ -1,13 +1,12 @@
 controller:
-  kind: DaemonSet
   image:
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: false
+
   service:
     type: ClusterIP
+
     internal:
       enabled: true
       annotations:
diff --git a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml b/charts/ingress-nginx/ci/controller-service-values.yaml
similarity index 69%
rename from charts/ingress-nginx/ci/deployment-customnodeport-values.yaml
rename to charts/ingress-nginx/ci/controller-service-values.yaml
index a564eaf..9039368 100644
--- a/charts/ingress-nginx/ci/deployment-customnodeport-values.yaml
+++ b/charts/ingress-nginx/ci/controller-service-values.yaml
@@ -3,18 +3,20 @@
     repository: ingress-controller/controller
     tag: 1.0.0-dev
     digest: null
-  admissionWebhooks:
-    enabled: false
+
   service:
     type: NodePort
+
     nodePorts:
       tcp:
         9000: 30090
       udp:
         9001: 30091
 
+portNamePrefix: port
+
 tcp:
-  9000: "default/test:8080"
+  9000: default/test:8080
 
 udp:
-  9001: "default/test:8080"
+  9001: default/test:8080
diff --git a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml b/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml
deleted file mode 100644
index 4393a5b..0000000
--- a/charts/ingress-nginx/ci/daemonset-customconfig-values.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  kind: DaemonSet
-  allowSnippetAnnotations: false
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-  config:
-    use-proxy-protocol: "true"
diff --git a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml
deleted file mode 100644
index 1d94be2..0000000
--- a/charts/ingress-nginx/ci/daemonset-customnodeport-values.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-
-  service:
-    type: NodePort
-    nodePorts:
-      tcp:
-        9000: 30090
-      udp:
-        9001: 30091
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/daemonset-extra-modules.yaml b/charts/ingress-nginx/ci/daemonset-extra-modules.yaml
deleted file mode 100644
index 52a32fc..0000000
--- a/charts/ingress-nginx/ci/daemonset-extra-modules.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-  service:
-    type: ClusterIP
-  extraModules:
-    - name: opentelemetry
-      image:
-        registry: registry.k8s.io
-        image: busybox
-        tag: latest
diff --git a/charts/ingress-nginx/ci/daemonset-headers-values.yaml b/charts/ingress-nginx/ci/daemonset-headers-values.yaml
deleted file mode 100644
index ab7d47b..0000000
--- a/charts/ingress-nginx/ci/daemonset-headers-values.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  addHeaders:
-    X-Frame-Options: deny
-  proxySetHeaders:
-    X-Forwarded-Proto: https
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml b/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml
deleted file mode 100644
index 3b7aa2f..0000000
--- a/charts/ingress-nginx/ci/daemonset-nodeport-values.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: NodePort
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml
deleted file mode 100644
index acd86a7..0000000
--- a/charts/ingress-nginx/ci/daemonset-tcp-udp-configMapNamespace-values.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-  tcp:
-    configMapNamespace: default
-  udp:
-    configMapNamespace: default
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-portNamePrefix-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-portNamePrefix-values.yaml
deleted file mode 100644
index 90b0f57..0000000
--- a/charts/ingress-nginx/ci/daemonset-tcp-udp-portNamePrefix-values.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
-
-portNamePrefix: "port"
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml
deleted file mode 100644
index 25ee64d..0000000
--- a/charts/ingress-nginx/ci/daemonset-tcp-udp-values.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml b/charts/ingress-nginx/ci/daemonset-tcp-values.yaml
deleted file mode 100644
index 380c8b4..0000000
--- a/charts/ingress-nginx/ci/daemonset-tcp-values.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/deamonset-default-values.yaml b/charts/ingress-nginx/ci/deamonset-default-values.yaml
deleted file mode 100644
index 82fa23e..0000000
--- a/charts/ingress-nginx/ci/deamonset-default-values.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml b/charts/ingress-nginx/ci/deamonset-metrics-values.yaml
deleted file mode 100644
index cb3cb54..0000000
--- a/charts/ingress-nginx/ci/deamonset-metrics-values.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  metrics:
-    enabled: true
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deamonset-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-psp-values.yaml
deleted file mode 100644
index 8026a63..0000000
--- a/charts/ingress-nginx/ci/deamonset-psp-values.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-podSecurityPolicy:
-  enabled: true
diff --git a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml
deleted file mode 100644
index fccdb13..0000000
--- a/charts/ingress-nginx/ci/deamonset-webhook-and-psp-values.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-controller:
-  kind: DaemonSet
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: true
-  service:
-    type: ClusterIP
-
-podSecurityPolicy:
-  enabled: true
diff --git a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml b/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml
deleted file mode 100644
index b8b3ac6..0000000
--- a/charts/ingress-nginx/ci/deployment-autoscaling-values.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  autoscaling:
-    enabled: true
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml b/charts/ingress-nginx/ci/deployment-customconfig-values.yaml
deleted file mode 100644
index 1749418..0000000
--- a/charts/ingress-nginx/ci/deployment-customconfig-values.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  config:
-    use-proxy-protocol: "true"
-  allowSnippetAnnotations: false
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-default-values.yaml b/charts/ingress-nginx/ci/deployment-default-values.yaml
deleted file mode 100644
index 9f46b4e..0000000
--- a/charts/ingress-nginx/ci/deployment-default-values.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# 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-extra-modules-default-container-sec-context.yaml b/charts/ingress-nginx/ci/deployment-extra-modules-default-container-sec-context.yaml
deleted file mode 100644
index 91b1b98..0000000
--- a/charts/ingress-nginx/ci/deployment-extra-modules-default-container-sec-context.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  service:
-    type: ClusterIP
-  containerSecurityContext:
-    allowPrivilegeEscalation: false
-  extraModules:
-    - name: opentelemetry
-      image:
-        registry: registry.k8s.io
-        image: busybox
-        tag: latest
diff --git a/charts/ingress-nginx/ci/deployment-extra-modules-specific-container-sec-context.yaml b/charts/ingress-nginx/ci/deployment-extra-modules-specific-container-sec-context.yaml
deleted file mode 100644
index b6013c7..0000000
--- a/charts/ingress-nginx/ci/deployment-extra-modules-specific-container-sec-context.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  service:
-    type: ClusterIP
-  extraModules:
-    - name: opentelemetry
-      image:
-        registry: registry.k8s.io
-        image: busybox
-        tag: latest
-      containerSecurityContext:
-        allowPrivilegeEscalation: false
diff --git a/charts/ingress-nginx/ci/deployment-extra-modules.yaml b/charts/ingress-nginx/ci/deployment-extra-modules.yaml
deleted file mode 100644
index 2fbe1cc..0000000
--- a/charts/ingress-nginx/ci/deployment-extra-modules.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  service:
-    type: ClusterIP
-  extraModules:
-    - name: opentelemetry
-      image:
-        registry: registry.k8s.io
-        image: busybox
-        tag: latest
diff --git a/charts/ingress-nginx/ci/deployment-headers-values.yaml b/charts/ingress-nginx/ci/deployment-headers-values.yaml
deleted file mode 100644
index 17a11ac..0000000
--- a/charts/ingress-nginx/ci/deployment-headers-values.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  addHeaders:
-    X-Frame-Options: deny
-  proxySetHeaders:
-    X-Forwarded-Proto: https
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml b/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml
deleted file mode 100644
index 663ccb9..0000000
--- a/charts/ingress-nginx/ci/deployment-internal-lb-values.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-    internal:
-      enabled: true
-      annotations:
-        service.beta.kubernetes.io/aws-load-balancer-internal: "true"
-      ports:
-        http: 443
-        https: 80
-      targetPorts:
-        http: 443
-        https: 80
diff --git a/charts/ingress-nginx/ci/deployment-metrics-values.yaml b/charts/ingress-nginx/ci/deployment-metrics-values.yaml
deleted file mode 100644
index 9209ad5..0000000
--- a/charts/ingress-nginx/ci/deployment-metrics-values.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  metrics:
-    enabled: true
-  service:
-    type: ClusterIP
diff --git a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml b/charts/ingress-nginx/ci/deployment-nodeport-values.yaml
deleted file mode 100644
index cd9b323..0000000
--- a/charts/ingress-nginx/ci/deployment-nodeport-values.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: NodePort
diff --git a/charts/ingress-nginx/ci/deployment-opentelemetry-customregistry-values.yaml b/charts/ingress-nginx/ci/deployment-opentelemetry-customregistry-values.yaml
deleted file mode 100644
index fb3ef44..0000000
--- a/charts/ingress-nginx/ci/deployment-opentelemetry-customregistry-values.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  service:
-    type: ClusterIP
-  opentelemetry:
-    enabled: true
diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml
deleted file mode 100644
index c51a4e9..0000000
--- a/charts/ingress-nginx/ci/deployment-tcp-udp-configMapNamespace-values.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-  tcp:
-    configMapNamespace: default
-  udp:
-    configMapNamespace: default
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-portNamePrefix-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-portNamePrefix-values.yaml
deleted file mode 100644
index 56323c5..0000000
--- a/charts/ingress-nginx/ci/deployment-tcp-udp-portNamePrefix-values.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
-
-portNamePrefix: "port"
diff --git a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml
deleted file mode 100644
index 5b45b69..0000000
--- a/charts/ingress-nginx/ci/deployment-tcp-udp-values.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: false
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-
-udp:
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/deployment-tcp-values.yaml b/charts/ingress-nginx/ci/deployment-tcp-values.yaml
deleted file mode 100644
index ac0b6e6..0000000
--- a/charts/ingress-nginx/ci/deployment-tcp-values.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  service:
-    type: ClusterIP
-
-tcp:
-  9000: "default/test:8080"
-  9001: "default/test:8080"
diff --git a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml
deleted file mode 100644
index 6195bb3..0000000
--- a/charts/ingress-nginx/ci/deployment-webhook-and-psp-values.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-controller:
-  image:
-    repository: ingress-controller/controller
-    tag: 1.0.0-dev
-    digest: null
-  admissionWebhooks:
-    enabled: true
-  service:
-    type: ClusterIP
-
-podSecurityPolicy:
-  enabled: true
diff --git a/charts/ingress-nginx/ci/deployment-webhook-extraEnvs-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-extraEnvs-values.yaml
deleted file mode 100644
index 95487b0..0000000
--- a/charts/ingress-nginx/ci/deployment-webhook-extraEnvs-values.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-controller:
-  service:
-    type: ClusterIP
-  admissionWebhooks:
-    enabled: true
-    extraEnvs:
-      - name: FOO
-        value: foo
-      - name: TEST
-        value: test
-    patch:
-      enabled: true
diff --git a/charts/ingress-nginx/ci/deployment-webhook-resources-values.yaml b/charts/ingress-nginx/ci/deployment-webhook-resources-values.yaml
deleted file mode 100644
index 49ebbb0..0000000
--- a/charts/ingress-nginx/ci/deployment-webhook-resources-values.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-controller:
-  service:
-    type: ClusterIP
-  admissionWebhooks:
-    enabled: true
-    createSecretJob:
-      resources:
-        limits:
-          cpu: 10m
-          memory: 20Mi
-        requests:
-          cpu: 10m
-          memory: 20Mi
-    patchWebhookJob:
-      resources:
-        limits:
-          cpu: 10m
-          memory: 20Mi
-        requests:
-          cpu: 10m
-          memory: 20Mi
-    patch:
-      enabled: true
diff --git a/charts/ingress-nginx/templates/_helpers.tpl b/charts/ingress-nginx/templates/_helpers.tpl
index 9ac2dc5..6cbda2d 100644
--- a/charts/ingress-nginx/templates/_helpers.tpl
+++ b/charts/ingress-nginx/templates/_helpers.tpl
@@ -47,6 +47,7 @@
 {{- else -}}
 runAsNonRoot: {{ .Values.controller.image.runAsNonRoot }}
 runAsUser: {{ .Values.controller.image.runAsUser }}
+runAsGroup: {{ .Values.controller.image.runAsGroup }}
 allowPrivilegeEscalation: {{ or .Values.controller.image.allowPrivilegeEscalation .Values.controller.image.chroot }}
 {{- if .Values.controller.image.seccompProfile }}
 seccompProfile: {{ toYaml .Values.controller.image.seccompProfile | nindent 2 }}
@@ -168,6 +169,17 @@
 {{- end -}}
 
 {{/*
+Create the name of the admission webhook patch job service account to use
+*/}}
+{{- define "ingress-nginx.admissionWebhooks.patch.serviceAccountName" -}}
+{{- if .Values.controller.admissionWebhooks.patch.serviceAccount.create -}}
+    {{ default (include "ingress-nginx.admissionWebhooks.fullname" .) .Values.controller.admissionWebhooks.patch.serviceAccount.name }}
+{{- else -}}
+    {{ default "default" .Values.controller.admissionWebhooks.patch.serviceAccount.name }}
+{{- end -}}
+{{- end -}}
+
+{{/*
 Create a default fully qualified admission webhook secret creation job name.
 We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
 */}}
@@ -192,7 +204,7 @@
 {{- end -}}
 
 {{/*
-Create the name of the backend service account to use - only used when podsecuritypolicy is also enabled
+Create the name of the default backend service account to use
 */}}
 {{- define "ingress-nginx.defaultBackend.serviceAccountName" -}}
 {{- if .Values.defaultBackend.serviceAccount.create -}}
@@ -211,6 +223,7 @@
 {{- else -}}
 runAsNonRoot: {{ .Values.defaultBackend.image.runAsNonRoot }}
 runAsUser: {{ .Values.defaultBackend.image.runAsUser }}
+runAsGroup: {{ .Values.defaultBackend.image.runAsGroup }}
 allowPrivilegeEscalation: {{ .Values.defaultBackend.image.allowPrivilegeEscalation }}
 {{- if .Values.defaultBackend.image.seccompProfile }}
 seccompProfile: {{ toYaml .Values.defaultBackend.image.seccompProfile | nindent 2 }}
@@ -223,26 +236,6 @@
 {{- end -}}
 
 {{/*
-Return the appropriate apiGroup for PodSecurityPolicy.
-*/}}
-{{- define "podSecurityPolicy.apiGroup" -}}
-{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
-{{- print "policy" -}}
-{{- else -}}
-{{- print "extensions" -}}
-{{- end -}}
-{{- end -}}
-
-{{/*
-Check the ingress controller version tag is at most three versions behind the last release
-*/}}
-{{- define "isControllerTagValid" -}}
-{{- if not (semverCompare ">=0.27.0-0" .Values.controller.image.tag) -}}
-{{- fail "Controller container image tag should be 0.27.0 or higher" -}}
-{{- end -}}
-{{- end -}}
-
-{{/*
 Extra modules.
 */}}
 {{- define "extraModules" -}}
diff --git a/charts/ingress-nginx/templates/_params.tpl b/charts/ingress-nginx/templates/_params.tpl
index 0ddef0a..0051dc9 100644
--- a/charts/ingress-nginx/templates/_params.tpl
+++ b/charts/ingress-nginx/templates/_params.tpl
@@ -1,7 +1,7 @@
 {{- define "ingress-nginx.params" -}}
 - /nginx-ingress-controller
-{{- if .Values.controller.enableAnnotationValidations }}
-- --enable-annotation-validation=true
+{{- if not .Values.controller.enableAnnotationValidations }}
+- --enable-annotation-validation=false
 {{- end }}
 {{- if .Values.defaultBackend.enabled }}
 - --default-backend-service=$(POD_NAMESPACE)/{{ include "ingress-nginx.defaultBackend.fullname" . }}
@@ -54,12 +54,18 @@
 {{- if .Values.controller.watchIngressWithoutClass }}
 - --watch-ingress-without-class=true
 {{- end }}
-{{- if not .Values.controller.metrics.enabled }}
+{{- if .Values.controller.metrics.enabled }}
 - --enable-metrics={{ .Values.controller.metrics.enabled }}
 {{- end }}
 {{- if .Values.controller.enableTopologyAwareRouting }}
 - --enable-topology-aware-routing=true
 {{- end }}
+{{- if .Values.controller.disableLeaderElection }}
+- --disable-leader-election=true
+{{- end }}
+{{- if .Values.controller.electionTTL }}
+- --election-ttl={{ .Values.controller.electionTTL }}
+{{- 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/admission-webhooks/job-patch/clusterrole.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml
index 8271dc4..54af7ab 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
+{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled .Values.controller.admissionWebhooks.patch.rbac.create (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
@@ -20,14 +20,4 @@
     verbs:
       - get
       - update
-{{- if .Values.podSecurityPolicy.enabled }}
-  - apiGroups:      [{{ template "podSecurityPolicy.apiGroup" . }}]
-    resources:      ['podsecuritypolicies']
-    verbs:          ['use']
-    {{- with .Values.controller.admissionWebhooks.existingPsp }}
-    resourceNames:  [{{ . }}]
-    {{- else }}
-    resourceNames:  [{{ include "ingress-nginx.admissionWebhooks.fullname" . }}]
-    {{- end }}
-{{- end }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
index 3fe842d..b893884 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
+{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled .Values.controller.admissionWebhooks.patch.rbac.create (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRoleBinding
 metadata:
@@ -18,6 +18,6 @@
   name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
 subjects:
   - kind: ServiceAccount
-    name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
+    name: {{ include "ingress-nginx.admissionWebhooks.patch.serviceAccountName" . }}
     namespace: {{ include "ingress-nginx.namespace" . }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
index 0a21f85..af3ea12 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
@@ -42,7 +42,7 @@
     {{- end }}
       containers:
         - name: create
-          {{- with .Values.controller.admissionWebhooks.patch.image }}
+          {{- with (merge .Values.controller.admissionWebhooks.patch.image .Values.global.image) }}
           image: {{ if .repository }}{{ .repository }}{{ else }}{{ .registry }}/{{ .image }}{{ end }}:{{ .tag }}{{ if .digest }}@{{ .digest }}{{ end }}
           {{- end }}
           imagePullPolicy: {{ .Values.controller.admissionWebhooks.patch.image.pullPolicy }}
@@ -66,7 +66,7 @@
           resources: {{ toYaml .Values.controller.admissionWebhooks.createSecretJob.resources | nindent 12 }}
           {{- end }}
       restartPolicy: OnFailure
-      serviceAccountName: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
+      serviceAccountName: {{ include "ingress-nginx.admissionWebhooks.patch.serviceAccountName" . }}
     {{- if .Values.controller.admissionWebhooks.patch.nodeSelector }}
       nodeSelector: {{ toYaml .Values.controller.admissionWebhooks.patch.nodeSelector | nindent 8 }}
     {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
index ce9985a..87dd2c2 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
@@ -42,7 +42,7 @@
     {{- end }}
       containers:
         - name: patch
-          {{- with .Values.controller.admissionWebhooks.patch.image }}
+          {{- with (merge .Values.controller.admissionWebhooks.patch.image .Values.global.image) }}
           image: {{ if .repository }}{{ .repository }}{{ else }}{{ .registry }}/{{ .image }}{{ end }}:{{ .tag }}{{ if .digest }}@{{ .digest }}{{ end }}
           {{- end }}
           imagePullPolicy: {{ .Values.controller.admissionWebhooks.patch.image.pullPolicy }}
@@ -68,7 +68,7 @@
           resources: {{ toYaml .Values.controller.admissionWebhooks.patchWebhookJob.resources | nindent 12 }}
           {{- end }}
       restartPolicy: OnFailure
-      serviceAccountName: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
+      serviceAccountName: {{ include "ingress-nginx.admissionWebhooks.patch.serviceAccountName" . }}
     {{- if .Values.controller.admissionWebhooks.patch.nodeSelector }}
       nodeSelector: {{ toYaml .Values.controller.admissionWebhooks.patch.nodeSelector | nindent 8 }}
     {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/psp.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/psp.yaml
deleted file mode 100644
index 8e5dc72..0000000
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/psp.yaml
+++ /dev/null
@@ -1,52 +0,0 @@
-{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
-{{- if and .Values.podSecurityPolicy.enabled .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (empty .Values.controller.admissionWebhooks.existingPsp) -}}
-apiVersion: policy/v1beta1
-kind: PodSecurityPolicy
-metadata:
-  name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
-  annotations:
-    "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
-    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
-    seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
-  labels:
-    {{- include "ingress-nginx.labels" . | nindent 4 }}
-    app.kubernetes.io/component: admission-webhook
-    {{- with .Values.controller.admissionWebhooks.patch.labels }}
-    {{- toYaml . | nindent 4 }}
-    {{- end }}
-spec:
-  privileged: false
-  hostPID: false
-  hostIPC: false
-  hostNetwork: false
-  volumes:
-    - configMap
-    - downwardAPI
-    - emptyDir
-    - secret
-    - projected
-  fsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  readOnlyRootFilesystem: true
-  runAsUser:
-    rule: MustRunAsNonRoot
-  runAsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  supplementalGroups:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  allowPrivilegeEscalation: false
-  requiredDropCapabilities:
-    - ALL
-  seLinux:
-    rule: RunAsAny
-{{- end }}
-{{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/role.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/role.yaml
index 5b05d9b..c4b23aa 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/role.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/role.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
+{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled .Values.controller.admissionWebhooks.patch.rbac.create (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml
index 48a1755..425e8d8 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
+{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled .Values.controller.admissionWebhooks.patch.rbac.create (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
 apiVersion: rbac.authorization.k8s.io/v1
 kind: RoleBinding
 metadata:
@@ -19,6 +19,6 @@
   name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
 subjects:
   - kind: ServiceAccount
-    name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
+    name: {{ include "ingress-nginx.admissionWebhooks.patch.serviceAccountName" . }}
     namespace: {{ include "ingress-nginx.namespace" . }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml b/charts/ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
index 91bbf22..52f94dc 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
@@ -1,8 +1,8 @@
-{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
+{{- if and .Values.controller.admissionWebhooks.enabled .Values.controller.admissionWebhooks.patch.enabled .Values.controller.admissionWebhooks.patch.serviceAccount.create (not .Values.controller.admissionWebhooks.certManager.enabled) -}}
 apiVersion: v1
 kind: ServiceAccount
 metadata:
-  name: {{ include "ingress-nginx.admissionWebhooks.fullname" . }}
+  name: {{ include "ingress-nginx.admissionWebhooks.patch.serviceAccountName" . }}
   namespace: {{ include "ingress-nginx.namespace" . }}
   annotations:
     "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
@@ -13,4 +13,5 @@
     {{- with .Values.controller.admissionWebhooks.patch.labels }}
     {{- toYaml . | nindent 4 }}
     {{- end }}
+automountServiceAccountToken: {{ .Values.controller.admissionWebhooks.patch.serviceAccount.automountServiceAccountToken }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml b/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
index 4cd36a6..0949cea 100644
--- a/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
+++ b/charts/ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
@@ -40,6 +40,7 @@
       service:
         name: {{ include "ingress-nginx.controller.fullname" . }}-admission
         namespace: {{ include "ingress-nginx.namespace" . }}
+        port: {{ .Values.controller.admissionWebhooks.service.servicePort }}
         path: /networking/v1/ingresses
     {{- if .Values.controller.admissionWebhooks.timeoutSeconds }}
     timeoutSeconds: {{ .Values.controller.admissionWebhooks.timeoutSeconds }}
diff --git a/charts/ingress-nginx/templates/controller-configmap.yaml b/charts/ingress-nginx/templates/controller-configmap.yaml
index 662a162..b73cdc2 100644
--- a/charts/ingress-nginx/templates/controller-configmap.yaml
+++ b/charts/ingress-nginx/templates/controller-configmap.yaml
@@ -13,7 +13,9 @@
   name: {{ include "ingress-nginx.controller.fullname" . }}
   namespace: {{ include "ingress-nginx.namespace" . }}
 data:
-  allow-snippet-annotations: "{{ .Values.controller.allowSnippetAnnotations }}"
+{{- if .Values.controller.allowSnippetAnnotations }}
+  allow-snippet-annotations: "true"
+{{- end }}
 {{- if .Values.controller.addHeaders }}
   add-headers: {{ include "ingress-nginx.namespace" . }}/{{ include "ingress-nginx.fullname" . }}-custom-add-headers
 {{- end }}
@@ -24,5 +26,5 @@
   ssl-dh-param: {{ include "ingress-nginx.namespace" . }}/{{ include "ingress-nginx.controller.fullname" . }}
 {{- end }}
 {{- range $key, $value := .Values.controller.config }}
-  {{- $key | nindent 2 }}: {{ $value | quote }}
+  {{- $key | nindent 2 }}: {{ tpl (toString $value) $ | quote }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-daemonset.yaml b/charts/ingress-nginx/templates/controller-daemonset.yaml
index 718e20c..fd1b132 100644
--- a/charts/ingress-nginx/templates/controller-daemonset.yaml
+++ b/charts/ingress-nginx/templates/controller-daemonset.yaml
@@ -1,5 +1,4 @@
 {{- if eq .Values.controller.kind "DaemonSet" -}}
-{{- include  "isControllerTagValid" . -}}
 apiVersion: apps/v1
 kind: DaemonSet
 metadata:
@@ -76,7 +75,7 @@
     {{- end }}
       containers:
         - name: {{ .Values.controller.containerName }}
-          {{- with .Values.controller.image }}
+          {{- with (merge .Values.controller.image .Values.global.image) }}
           image: {{ if .repository }}{{ .repository }}{{ else }}{{ .registry }}/{{ include "ingress-nginx.image" . }}{{ end }}:{{ .tag }}{{ include "ingress-nginx.imageDigest" . }}
           {{- end }}
           imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
@@ -145,9 +144,9 @@
               hostPort: {{ $key }}
               {{- end }}
           {{- end }}
-        {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+        {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraModules) }}
           volumeMounts:
-          {{- if (or .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+          {{- if .Values.controller.extraModules }}
             - name: modules
             {{- if .Values.controller.image.chroot }}
               mountPath: /chroot/modules_mount
@@ -175,7 +174,7 @@
       {{- if .Values.controller.extraContainers }}
         {{- toYaml .Values.controller.extraContainers | nindent 8 }}
       {{- end }}
-    {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+    {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules) }}
       initContainers:
       {{- if .Values.controller.extraInitContainers }}
         {{- toYaml .Values.controller.extraInitContainers | nindent 8 }}
@@ -183,13 +182,7 @@
       {{- if .Values.controller.extraModules }}
         {{- range .Values.controller.extraModules }}
           {{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
-          {{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
-        {{- end }}
-      {{- end }}
-      {{- if .Values.controller.opentelemetry.enabled }}
-        {{- with .Values.controller.opentelemetry }}
-          {{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
-          {{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
+          {{- include "extraModules" (dict "name" .name "image" (merge .image $.Values.global.image) "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
         {{- end }}
       {{- end }}
     {{- end }}
@@ -203,16 +196,16 @@
       tolerations: {{ toYaml .Values.controller.tolerations | nindent 8 }}
     {{- end }}
     {{- if .Values.controller.affinity }}
-      affinity: {{ toYaml .Values.controller.affinity | nindent 8 }}
+      affinity: {{ tpl (toYaml .Values.controller.affinity) $ | nindent 8 }}
     {{- end }}
     {{- if .Values.controller.topologySpreadConstraints }}
       topologySpreadConstraints: {{ tpl (toYaml .Values.controller.topologySpreadConstraints) $ | nindent 8 }}
     {{- end }}
       serviceAccountName: {{ template "ingress-nginx.serviceAccountName" . }}
       terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }}
-    {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraVolumes .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+    {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraVolumes .Values.controller.extraModules) }}
       volumes:
-      {{- if (or .Values.controller.extraModules .Values.controller.opentelemetry.enabled)}}
+      {{- if .Values.controller.extraModules }}
         - name: modules
           emptyDir: {}
       {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-deployment.yaml b/charts/ingress-nginx/templates/controller-deployment.yaml
index 8798027..cc41bfb 100644
--- a/charts/ingress-nginx/templates/controller-deployment.yaml
+++ b/charts/ingress-nginx/templates/controller-deployment.yaml
@@ -1,5 +1,4 @@
 {{- if eq .Values.controller.kind "Deployment" -}}
-{{- include  "isControllerTagValid" . -}}
 apiVersion: apps/v1
 kind: Deployment
 metadata:
@@ -23,6 +22,9 @@
   replicas: {{ .Values.controller.replicaCount }}
   {{- end }}
   revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
+  {{- if .Values.controller.progressDeadlineSeconds }}
+  progressDeadlineSeconds: {{ .Values.controller.progressDeadlineSeconds }}
+  {{- end }}
   {{- if .Values.controller.updateStrategy }}
   strategy: {{ toYaml .Values.controller.updateStrategy | nindent 4 }}
   {{- end }}
@@ -79,7 +81,7 @@
     {{- end }}
       containers:
         - name: {{ .Values.controller.containerName }}
-          {{- with .Values.controller.image }}
+          {{- with (merge .Values.controller.image .Values.global.image) }}
           image: {{ if .repository }}{{ .repository }}{{ else }}{{ .registry }}/{{ include "ingress-nginx.image" . }}{{ end }}:{{ .tag }}{{ include "ingress-nginx.imageDigest" . }}
           {{- end }}
           imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
@@ -148,9 +150,9 @@
               hostPort: {{ $key }}
               {{- end }}
           {{- end }}
-        {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+        {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraModules) }}
           volumeMounts:
-          {{- if (or .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+          {{- if .Values.controller.extraModules }}
             - name: modules
             {{- if .Values.controller.image.chroot }}
               mountPath: /chroot/modules_mount
@@ -178,7 +180,7 @@
       {{- if .Values.controller.extraContainers }}
         {{- toYaml .Values.controller.extraContainers | nindent 8 }}
       {{- end }}
-    {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+    {{- if (or .Values.controller.extraInitContainers .Values.controller.extraModules) }}
       initContainers:
       {{- if .Values.controller.extraInitContainers }}
         {{- toYaml .Values.controller.extraInitContainers | nindent 8 }}
@@ -186,13 +188,7 @@
       {{- if .Values.controller.extraModules }}
         {{- range .Values.controller.extraModules }}
           {{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
-          {{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
-        {{- end }}
-      {{- end }}
-      {{- if .Values.controller.opentelemetry.enabled }}
-        {{- with .Values.controller.opentelemetry }}
-          {{- $containerSecurityContext := .containerSecurityContext | default $.Values.controller.containerSecurityContext }}
-          {{- include "extraModules" (dict "name" .name "image" .image "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
+          {{- include "extraModules" (dict "name" .name "image" (merge .image $.Values.global.image) "containerSecurityContext" $containerSecurityContext "resources" .resources) | nindent 8 }}
         {{- end }}
       {{- end }}
     {{- end }}
@@ -206,16 +202,16 @@
       tolerations: {{ toYaml .Values.controller.tolerations | nindent 8 }}
     {{- end }}
     {{- if .Values.controller.affinity }}
-      affinity: {{ toYaml .Values.controller.affinity | nindent 8 }}
+      affinity: {{ tpl (toYaml .Values.controller.affinity) $ | nindent 8 }}
     {{- end }}
     {{- if .Values.controller.topologySpreadConstraints }}
       topologySpreadConstraints: {{ tpl (toYaml .Values.controller.topologySpreadConstraints) $ | nindent 8 }}
     {{- end }}
       serviceAccountName: {{ template "ingress-nginx.serviceAccountName" . }}
       terminationGracePeriodSeconds: {{ .Values.controller.terminationGracePeriodSeconds }}
-    {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraVolumes .Values.controller.extraModules .Values.controller.opentelemetry.enabled) }}
+    {{- if (or .Values.controller.customTemplate.configMapName .Values.controller.extraVolumeMounts .Values.controller.admissionWebhooks.enabled .Values.controller.extraVolumes .Values.controller.extraModules) }}
       volumes:
-      {{- if (or .Values.controller.extraModules .Values.controller.opentelemetry.enabled)}}
+      {{- if .Values.controller.extraModules }}
         - name: modules
           emptyDir: {}
       {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-ingressclass-aliases.yaml b/charts/ingress-nginx/templates/controller-ingressclass-aliases.yaml
new file mode 100644
index 0000000..ffe2231
--- /dev/null
+++ b/charts/ingress-nginx/templates/controller-ingressclass-aliases.yaml
@@ -0,0 +1,23 @@
+{{- if .Values.controller.ingressClassResource.enabled -}}
+{{- range .Values.controller.ingressClassResource.aliases }}
+---
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  labels:
+    {{- include "ingress-nginx.labels" $ | nindent 4 }}
+    app.kubernetes.io/component: controller
+    {{- with $.Values.controller.labels }}
+    {{- toYaml . | nindent 4 }}
+    {{- end }}
+  name: {{ . }}
+  {{- if $.Values.controller.ingressClassResource.annotations }}
+  annotations: {{ toYaml $.Values.controller.ingressClassResource.annotations | nindent 4 }}
+  {{- end }}
+spec:
+  controller: {{ $.Values.controller.ingressClassResource.controllerValue }}
+  {{- with $.Values.controller.ingressClassResource.parameters }}
+  parameters: {{ toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/ingress-nginx/templates/controller-ingressclass.yaml b/charts/ingress-nginx/templates/controller-ingressclass.yaml
index e439e0a..98479a5 100644
--- a/charts/ingress-nginx/templates/controller-ingressclass.yaml
+++ b/charts/ingress-nginx/templates/controller-ingressclass.yaml
@@ -9,9 +9,14 @@
     {{- toYaml . | nindent 4 }}
     {{- end }}
   name: {{ .Values.controller.ingressClassResource.name }}
-  {{- if .Values.controller.ingressClassResource.default }}
+  {{- if or .Values.controller.ingressClassResource.default .Values.controller.ingressClassResource.annotations }}
   annotations:
+    {{- if .Values.controller.ingressClassResource.default }}
     ingressclass.kubernetes.io/is-default-class: "true"
+    {{- end }}
+    {{- if .Values.controller.ingressClassResource.annotations }}
+    {{- toYaml .Values.controller.ingressClassResource.annotations | nindent 4 }}
+    {{- end }}
   {{- end }}
 spec:
   controller: {{ .Values.controller.ingressClassResource.controllerValue }}
diff --git a/charts/ingress-nginx/templates/controller-poddisruptionbudget.yaml b/charts/ingress-nginx/templates/controller-poddisruptionbudget.yaml
index 8e0181f..a1f5fbb 100644
--- a/charts/ingress-nginx/templates/controller-poddisruptionbudget.yaml
+++ b/charts/ingress-nginx/templates/controller-poddisruptionbudget.yaml
@@ -32,5 +32,8 @@
   {{- else if .Values.controller.maxUnavailable }}
   maxUnavailable: {{ .Values.controller.maxUnavailable }}
   {{- end }}
+  {{- if .Values.controller.unhealthyPodEvictionPolicy }}
+  unhealthyPodEvictionPolicy: {{ .Values.controller.unhealthyPodEvictionPolicy }}
+  {{- end }}
 {{- end }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-prometheusrules.yaml b/charts/ingress-nginx/templates/controller-prometheusrule.yaml
similarity index 84%
rename from charts/ingress-nginx/templates/controller-prometheusrules.yaml
rename to charts/ingress-nginx/templates/controller-prometheusrule.yaml
index 41684c3..4a9357f 100644
--- a/charts/ingress-nginx/templates/controller-prometheusrules.yaml
+++ b/charts/ingress-nginx/templates/controller-prometheusrule.yaml
@@ -14,6 +14,9 @@
   {{- if .Values.controller.metrics.prometheusRule.additionalLabels }}
     {{- toYaml .Values.controller.metrics.prometheusRule.additionalLabels | nindent 4 }}
   {{- end }}
+  {{- if .Values.controller.metrics.prometheusRule.annotations }}
+  annotations: {{ toYaml .Values.controller.metrics.prometheusRule.annotations | nindent 4 }}
+  {{- end }}
 spec:
 {{- if .Values.controller.metrics.prometheusRule.rules }}
   groups:
diff --git a/charts/ingress-nginx/templates/controller-psp.yaml b/charts/ingress-nginx/templates/controller-psp.yaml
deleted file mode 100644
index aad1d27..0000000
--- a/charts/ingress-nginx/templates/controller-psp.yaml
+++ /dev/null
@@ -1,100 +0,0 @@
-{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
-{{- if and .Values.podSecurityPolicy.enabled (empty .Values.controller.existingPsp) -}}
-apiVersion: policy/v1beta1
-kind: PodSecurityPolicy
-metadata:
-  name: {{ include "ingress-nginx.fullname" . }}
-  annotations:
-    seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
-  labels:
-    {{- include "ingress-nginx.labels" . | nindent 4 }}
-    app.kubernetes.io/component: controller
-    {{- with .Values.controller.labels }}
-    {{- toYaml . | nindent 4 }}
-    {{- end }}
-spec:
-  privileged: false
-  hostPID: false
-  hostIPC: false
-  hostNetwork: {{ .Values.controller.hostNetwork }}
-{{- if or .Values.controller.hostNetwork .Values.controller.hostPort.enabled }}
-  hostPorts:
-  {{- if .Values.controller.hostNetwork }}
-  {{- range $key, $value := .Values.controller.containerPort }}
-    # controller.containerPort.{{ $key }}
-    - min: {{ $value }}
-      max: {{ $value }}
-  {{- end }}
-  {{- else if .Values.controller.hostPort.enabled }}
-  {{- range $key, $value := .Values.controller.hostPort.ports }}
-    # controller.hostPort.ports.{{ $key }}
-    - min: {{ $value }}
-      max: {{ $value }}
-  {{- end }}
-  {{- end }}
-  {{- if .Values.controller.metrics.enabled }}
-    # controller.metrics.port
-    - min: {{ .Values.controller.metrics.port }}
-      max: {{ .Values.controller.metrics.port }}
-  {{- end }}
-  {{- if .Values.controller.admissionWebhooks.enabled }}
-    # controller.admissionWebhooks.port
-    - min: {{ .Values.controller.admissionWebhooks.port }}
-      max: {{ .Values.controller.admissionWebhooks.port }}
-  {{- end }}
-  {{- range $key, $value := .Values.tcp }}
-    # tcp.{{ $key }}
-    - min: {{ $key }}
-      max: {{ $key }}
-  {{- end }}
-  {{- range $key, $value := .Values.udp }}
-    # udp.{{ $key }}
-    - min: {{ $key }}
-      max: {{ $key }}
-  {{- end }}
-{{- end }}
-  volumes:
-    - configMap
-    - downwardAPI
-    - emptyDir
-    - secret
-    - projected
-  fsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  readOnlyRootFilesystem: false
-  runAsUser:
-    rule: MustRunAsNonRoot
-  runAsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  supplementalGroups:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  allowPrivilegeEscalation: {{ or .Values.controller.image.allowPrivilegeEscalation .Values.controller.image.chroot }}
-  requiredDropCapabilities:
-    - ALL
-  allowedCapabilities:
-    - NET_BIND_SERVICE
-  {{- if .Values.controller.image.chroot }}
-  {{- if .Values.controller.image.seccompProfile }}
-    - SYS_ADMIN
-  {{- end }}
-    - SYS_CHROOT
-  {{- end }}
-  seLinux:
-    rule: RunAsAny
-{{- if .Values.controller.sysctls }}
-  allowedUnsafeSysctls:
-  {{- range $sysctl, $value := .Values.controller.sysctls }}
-    - {{ $sysctl }}
-  {{- end }}
-{{- end }}
-{{- end }}
-{{- end }}
diff --git a/charts/ingress-nginx/templates/controller-role.yaml b/charts/ingress-nginx/templates/controller-role.yaml
index a94b399..127b368 100644
--- a/charts/ingress-nginx/templates/controller-role.yaml
+++ b/charts/ingress-nginx/templates/controller-role.yaml
@@ -91,14 +91,4 @@
       - list
       - watch
       - get
-{{- if .Values.podSecurityPolicy.enabled }}
-  - apiGroups:      [{{ template "podSecurityPolicy.apiGroup" . }}]
-    resources:      ['podsecuritypolicies']
-    verbs:          ['use']
-    {{- with .Values.controller.existingPsp }}
-    resourceNames:  [{{ . }}]
-    {{- else }}
-    resourceNames:  [{{ include "ingress-nginx.fullname" . }}]
-    {{- end }}
-{{- end }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/controller-service-metrics.yaml b/charts/ingress-nginx/templates/controller-service-metrics.yaml
index 7c15329..4b25a84 100644
--- a/charts/ingress-nginx/templates/controller-service-metrics.yaml
+++ b/charts/ingress-nginx/templates/controller-service-metrics.yaml
@@ -1,4 +1,4 @@
-{{- if .Values.controller.metrics.enabled -}}
+{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.service.enabled -}}
 apiVersion: v1
 kind: Service
 metadata:
diff --git a/charts/ingress-nginx/templates/controller-service-webhook.yaml b/charts/ingress-nginx/templates/controller-service-webhook.yaml
index 6dcf1a1..67aac0d 100644
--- a/charts/ingress-nginx/templates/controller-service-webhook.yaml
+++ b/charts/ingress-nginx/templates/controller-service-webhook.yaml
@@ -29,7 +29,7 @@
 {{- end }}
   ports:
     - name: https-webhook
-      port: 443
+      port: {{ .Values.controller.admissionWebhooks.service.servicePort }}
       targetPort: webhook
     {{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version }}
       appProtocol: https
diff --git a/charts/ingress-nginx/templates/controller-servicemonitor.yaml b/charts/ingress-nginx/templates/controller-servicemonitor.yaml
index 62301da..93ab4d2 100644
--- a/charts/ingress-nginx/templates/controller-servicemonitor.yaml
+++ b/charts/ingress-nginx/templates/controller-servicemonitor.yaml
@@ -3,51 +3,48 @@
 kind: ServiceMonitor
 metadata:
   name: {{ include "ingress-nginx.controller.fullname" . }}
-{{- if .Values.controller.metrics.serviceMonitor.namespace }}
+  {{- if .Values.controller.metrics.serviceMonitor.namespace }}
   namespace: {{ .Values.controller.metrics.serviceMonitor.namespace }}
-{{- else }}
+  {{- else }}
   namespace: {{ include "ingress-nginx.namespace" . }}
-{{- end }}
+  {{- end }}
   labels:
     {{- include "ingress-nginx.labels" . | nindent 4 }}
     app.kubernetes.io/component: controller
-  {{- if .Values.controller.metrics.serviceMonitor.additionalLabels }}
+    {{- if .Values.controller.metrics.serviceMonitor.additionalLabels }}
     {{- toYaml .Values.controller.metrics.serviceMonitor.additionalLabels | nindent 4 }}
-  {{- end }}
+    {{- end }}
   {{- if .Values.controller.metrics.serviceMonitor.annotations }}
   annotations: {{ toYaml .Values.controller.metrics.serviceMonitor.annotations | nindent 4 }}
   {{- end }}
 spec:
-  endpoints:
-    - port: {{ .Values.controller.metrics.portName }}
-      interval: {{ .Values.controller.metrics.serviceMonitor.scrapeInterval }}
-    {{- if .Values.controller.metrics.serviceMonitor.honorLabels }}
-      honorLabels: true
-    {{- end }}
-    {{- if .Values.controller.metrics.serviceMonitor.relabelings }}
-      relabelings: {{ toYaml .Values.controller.metrics.serviceMonitor.relabelings | nindent 8 }}
-    {{- end }}
-    {{- if .Values.controller.metrics.serviceMonitor.metricRelabelings }}
-      metricRelabelings: {{ toYaml .Values.controller.metrics.serviceMonitor.metricRelabelings | nindent 8 }}
-    {{- end }}
-{{- if .Values.controller.metrics.serviceMonitor.jobLabel }}
-  jobLabel: {{ .Values.controller.metrics.serviceMonitor.jobLabel | quote }}
-{{- end }}
-{{- if .Values.controller.metrics.serviceMonitor.namespaceSelector }}
+  {{- if .Values.controller.metrics.serviceMonitor.namespaceSelector }}
   namespaceSelector: {{ toYaml .Values.controller.metrics.serviceMonitor.namespaceSelector | nindent 4 }}
-{{- else }}
+  {{- else }}
   namespaceSelector:
     matchNames:
-      - {{ include "ingress-nginx.namespace" . }}
-{{- end }}
-{{- if .Values.controller.metrics.serviceMonitor.targetLabels }}
-  targetLabels:
-  {{- range .Values.controller.metrics.serviceMonitor.targetLabels }}
-    - {{ . }}
+    - {{ include "ingress-nginx.namespace" . }}
   {{- end }}
-{{- end }}
   selector:
     matchLabels:
       {{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
       app.kubernetes.io/component: controller
+  endpoints:
+  - port: {{ .Values.controller.metrics.portName }}
+    interval: {{ .Values.controller.metrics.serviceMonitor.scrapeInterval }}
+    {{- if .Values.controller.metrics.serviceMonitor.honorLabels }}
+    honorLabels: true
+    {{- end }}
+    {{- if .Values.controller.metrics.serviceMonitor.relabelings }}
+    relabelings: {{ toYaml .Values.controller.metrics.serviceMonitor.relabelings | nindent 4 }}
+    {{- end }}
+    {{- if .Values.controller.metrics.serviceMonitor.metricRelabelings }}
+    metricRelabelings: {{ toYaml .Values.controller.metrics.serviceMonitor.metricRelabelings | nindent 4 }}
+    {{- end }}
+  {{- if .Values.controller.metrics.serviceMonitor.jobLabel }}
+  jobLabel: {{ .Values.controller.metrics.serviceMonitor.jobLabel | quote }}
+  {{- end }}
+  {{- if .Values.controller.metrics.serviceMonitor.targetLabels }}
+  targetLabels: {{ toYaml .Values.controller.metrics.serviceMonitor.targetLabels | nindent 2 }}
+  {{- end }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/default-backend-deployment.yaml b/charts/ingress-nginx/templates/default-backend-deployment.yaml
index d342c8c..f7d9de1 100644
--- a/charts/ingress-nginx/templates/default-backend-deployment.yaml
+++ b/charts/ingress-nginx/templates/default-backend-deployment.yaml
@@ -50,7 +50,7 @@
     {{- end }}
       containers:
         - name: {{ template "ingress-nginx.name" . }}-default-backend
-          {{- with .Values.defaultBackend.image }}
+          {{- with (merge .Values.defaultBackend.image .Values.global.image) }}
           image: {{ if .repository }}{{ .repository }}{{ else }}{{ .registry }}/{{ .image }}{{ end }}:{{ .tag }}{{ if .digest }}@{{ .digest }}{{ end }}
           {{- end }}
           imagePullPolicy: {{ .Values.defaultBackend.image.pullPolicy }}
@@ -102,12 +102,15 @@
     {{- if .Values.defaultBackend.nodeSelector }}
       nodeSelector: {{ toYaml .Values.defaultBackend.nodeSelector | nindent 8 }}
     {{- end }}
-      serviceAccountName: {{ template "ingress-nginx.defaultBackend.serviceAccountName" . }}
+      serviceAccountName: {{ include "ingress-nginx.defaultBackend.serviceAccountName" . }}
     {{- if .Values.defaultBackend.tolerations }}
       tolerations: {{ toYaml .Values.defaultBackend.tolerations | nindent 8 }}
     {{- end }}
     {{- if .Values.defaultBackend.affinity }}
-      affinity: {{ toYaml .Values.defaultBackend.affinity | nindent 8 }}
+      affinity: {{ tpl (toYaml .Values.defaultBackend.affinity) $ | nindent 8 }}
+    {{- end }}
+    {{- if .Values.defaultBackend.topologySpreadConstraints }}
+      topologySpreadConstraints: {{ tpl (toYaml .Values.defaultBackend.topologySpreadConstraints) $ | nindent 8 }}
     {{- end }}
       terminationGracePeriodSeconds: 60
     {{- if .Values.defaultBackend.extraVolumes }}
diff --git a/charts/ingress-nginx/templates/default-backend-poddisruptionbudget.yaml b/charts/ingress-nginx/templates/default-backend-poddisruptionbudget.yaml
index f869e45..e399ea8 100644
--- a/charts/ingress-nginx/templates/default-backend-poddisruptionbudget.yaml
+++ b/charts/ingress-nginx/templates/default-backend-poddisruptionbudget.yaml
@@ -1,5 +1,9 @@
 {{- if .Values.defaultBackend.enabled -}}
-{{- if or (gt (.Values.defaultBackend.replicaCount | int) 1) (gt (.Values.defaultBackend.autoscaling.minReplicas | int) 1) }}
+{{- $replicas := .Values.defaultBackend.replicaCount }}
+{{- if .Values.defaultBackend.autoscaling.enabled }}
+{{- $replicas = .Values.defaultBackend.autoscaling.minReplicas }}
+{{- end }}
+{{- if gt ($replicas | int) 1 }}
 apiVersion: {{ ternary "policy/v1" "policy/v1beta1" (semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version) }}
 kind: PodDisruptionBudget
 metadata:
@@ -16,6 +20,13 @@
     matchLabels:
       {{- include "ingress-nginx.selectorLabels" . | nindent 6 }}
       app.kubernetes.io/component: default-backend
+  {{- if and .Values.defaultBackend.minAvailable (not (hasKey .Values.defaultBackend "maxUnavailable")) }}
   minAvailable: {{ .Values.defaultBackend.minAvailable }}
+  {{- else if .Values.defaultBackend.maxUnavailable }}
+  maxUnavailable: {{ .Values.defaultBackend.maxUnavailable }}
+  {{- end }}
+  {{- if .Values.defaultBackend.unhealthyPodEvictionPolicy }}
+  unhealthyPodEvictionPolicy: {{ .Values.defaultBackend.unhealthyPodEvictionPolicy }}
+  {{- end }}
 {{- end }}
 {{- end }}
diff --git a/charts/ingress-nginx/templates/default-backend-psp.yaml b/charts/ingress-nginx/templates/default-backend-psp.yaml
deleted file mode 100644
index 4241091..0000000
--- a/charts/ingress-nginx/templates/default-backend-psp.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-{{- if (semverCompare "<1.25.0-0" .Capabilities.KubeVersion.Version) }}
-{{- if and .Values.podSecurityPolicy.enabled .Values.defaultBackend.enabled (empty .Values.defaultBackend.existingPsp) -}}
-apiVersion: policy/v1beta1
-kind: PodSecurityPolicy
-metadata:
-  name: {{ include "ingress-nginx.fullname" . }}-backend
-  annotations:
-    seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
-  labels:
-    {{- include "ingress-nginx.labels" . | nindent 4 }}
-    app.kubernetes.io/component: default-backend
-    {{- with .Values.defaultBackend.labels }}
-    {{- toYaml . | nindent 4 }}
-    {{- end }}
-spec:
-  privileged: false
-  hostPID: false
-  hostIPC: false
-  hostNetwork: false
-  volumes:
-    - configMap
-    - downwardAPI
-    - emptyDir
-    - secret
-    - projected
-  fsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  readOnlyRootFilesystem: true
-  runAsUser:
-    rule: MustRunAsNonRoot
-  runAsGroup:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  supplementalGroups:
-    rule: MustRunAs
-    ranges:
-      - min: 1
-        max: 65535
-  allowPrivilegeEscalation: false
-  requiredDropCapabilities:
-    - ALL
-  seLinux:
-    rule: RunAsAny
-{{- end }}
-{{- end }}
diff --git a/charts/ingress-nginx/templates/default-backend-role.yaml b/charts/ingress-nginx/templates/default-backend-role.yaml
deleted file mode 100644
index dd7868a..0000000
--- a/charts/ingress-nginx/templates/default-backend-role.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled .Values.defaultBackend.enabled -}}
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  labels:
-    {{- include "ingress-nginx.labels" . | nindent 4 }}
-    app.kubernetes.io/component: default-backend
-    {{- with .Values.defaultBackend.labels }}
-    {{- toYaml . | nindent 4 }}
-    {{- end }}
-  name: {{ include "ingress-nginx.fullname" . }}-backend
-  namespace: {{ include "ingress-nginx.namespace" . }}
-rules:
-  - apiGroups:      [{{ template "podSecurityPolicy.apiGroup" . }}]
-    resources:      ['podsecuritypolicies']
-    verbs:          ['use']
-    {{- with .Values.defaultBackend.existingPsp }}
-    resourceNames:  [{{ . }}]
-    {{- else }}
-    resourceNames:  [{{ include "ingress-nginx.fullname" . }}-backend]
-    {{- end }}
-{{- end }}
diff --git a/charts/ingress-nginx/templates/default-backend-rolebinding.yaml b/charts/ingress-nginx/templates/default-backend-rolebinding.yaml
deleted file mode 100644
index 3203b6f..0000000
--- a/charts/ingress-nginx/templates/default-backend-rolebinding.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-{{- if and .Values.rbac.create .Values.podSecurityPolicy.enabled .Values.defaultBackend.enabled -}}
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  labels:
-    {{- include "ingress-nginx.labels" . | nindent 4 }}
-    app.kubernetes.io/component: default-backend
-    {{- with .Values.defaultBackend.labels }}
-    {{- toYaml . | nindent 4 }}
-    {{- end }}
-  name: {{ include "ingress-nginx.fullname" . }}-backend
-  namespace: {{ include "ingress-nginx.namespace" . }}
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: {{ include "ingress-nginx.fullname" . }}-backend
-subjects:
-  - kind: ServiceAccount
-    name: {{ template "ingress-nginx.defaultBackend.serviceAccountName" . }}
-    namespace: {{ include "ingress-nginx.namespace" . }}
-{{- end }}
diff --git a/charts/ingress-nginx/templates/default-backend-serviceaccount.yaml b/charts/ingress-nginx/templates/default-backend-serviceaccount.yaml
index 2afaf0c..6fd2d62 100644
--- a/charts/ingress-nginx/templates/default-backend-serviceaccount.yaml
+++ b/charts/ingress-nginx/templates/default-backend-serviceaccount.yaml
@@ -1,4 +1,4 @@
-{{- if and .Values.defaultBackend.enabled  .Values.defaultBackend.serviceAccount.create -}}
+{{- if and .Values.defaultBackend.enabled .Values.defaultBackend.serviceAccount.create -}}
 apiVersion: v1
 kind: ServiceAccount
 metadata:
@@ -8,7 +8,7 @@
     {{- with .Values.defaultBackend.labels }}
     {{- toYaml . | nindent 4 }}
     {{- end }}
-  name: {{ template "ingress-nginx.defaultBackend.serviceAccountName" . }}
+  name: {{ include "ingress-nginx.defaultBackend.serviceAccountName" . }}
   namespace: {{ include "ingress-nginx.namespace" . }}
 automountServiceAccountToken: {{ .Values.defaultBackend.serviceAccount.automountServiceAccountToken }}
 {{- end }}
diff --git a/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrole_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrole_test.yaml
new file mode 100644
index 0000000..d7a8b88
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrole_test.yaml
@@ -0,0 +1,11 @@
+suite: Admission Webhooks > Patch Job > ClusterRole
+templates:
+  - admission-webhooks/job-patch/clusterrole.yaml
+
+tests:
+  - it: should not create a ClusterRole if `controller.admissionWebhooks.patch.rbac.create` is false
+    set:
+      controller.admissionWebhooks.patch.rbac.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrolebinding_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrolebinding_test.yaml
new file mode 100644
index 0000000..d7c3266
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/job-patch/clusterrolebinding_test.yaml
@@ -0,0 +1,11 @@
+suite: Admission Webhooks > Patch Job > ClusterRoleBinding
+templates:
+  - admission-webhooks/job-patch/clusterrolebinding.yaml
+
+tests:
+  - it: should not create a ClusterRoleBinding if `controller.admissionWebhooks.patch.rbac.create` is false
+    set:
+      controller.admissionWebhooks.patch.rbac.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/charts/ingress-nginx/tests/admission-webhooks/job-patch/role_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/job-patch/role_test.yaml
new file mode 100644
index 0000000..a236f3d
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/job-patch/role_test.yaml
@@ -0,0 +1,11 @@
+suite: Admission Webhooks > Patch Job > Role
+templates:
+  - admission-webhooks/job-patch/role.yaml
+
+tests:
+  - it: should not create a Role if `controller.admissionWebhooks.patch.rbac.create` is false
+    set:
+      controller.admissionWebhooks.patch.rbac.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/charts/ingress-nginx/tests/admission-webhooks/job-patch/rolebinding_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/job-patch/rolebinding_test.yaml
new file mode 100644
index 0000000..74abaa1
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/job-patch/rolebinding_test.yaml
@@ -0,0 +1,11 @@
+suite: Admission Webhooks > Patch Job > RoleBinding
+templates:
+  - admission-webhooks/job-patch/rolebinding.yaml
+
+tests:
+  - it: should not create a RoleBinding if `controller.admissionWebhooks.patch.rbac.create` is false
+    set:
+      controller.admissionWebhooks.patch.rbac.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/charts/ingress-nginx/tests/admission-webhooks/job-patch/serviceaccount_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/job-patch/serviceaccount_test.yaml
new file mode 100644
index 0000000..f72bc43
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/job-patch/serviceaccount_test.yaml
@@ -0,0 +1,47 @@
+suite: Admission Webhooks > Patch Job > ServiceAccount
+templates:
+  - admission-webhooks/job-patch/serviceaccount.yaml
+
+tests:
+  - it: should not create a ServiceAccount if `controller.admissionWebhooks.patch.serviceAccount.create` is false
+    set:
+      controller.admissionWebhooks.patch.serviceAccount.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a ServiceAccount if `controller.admissionWebhooks.patch.serviceAccount.create` is true
+    set:
+      controller.admissionWebhooks.patch.serviceAccount.create: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-admission
+
+  - it: should create a ServiceAccount with specified name if `controller.admissionWebhooks.patch.serviceAccount.name` is set
+    set:
+      controller.admissionWebhooks.patch.serviceAccount.name: ingress-nginx-admission-test-sa
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: ingress-nginx-admission-test-sa
+
+  - it: should create a ServiceAccount with token auto-mounting disabled if `controller.admissionWebhooks.patch.serviceAccount.automountServiceAccountToken` is false
+    set:
+      controller.admissionWebhooks.patch.serviceAccount.automountServiceAccountToken: false
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: automountServiceAccountToken
+          value: false
diff --git a/charts/ingress-nginx/tests/admission-webhooks/validating-webhook_test.yaml b/charts/ingress-nginx/tests/admission-webhooks/validating-webhook_test.yaml
new file mode 100644
index 0000000..47b6b68
--- /dev/null
+++ b/charts/ingress-nginx/tests/admission-webhooks/validating-webhook_test.yaml
@@ -0,0 +1,32 @@
+suite: Admission Webhooks > ValidatingWebhookConfiguration
+templates:
+  - admission-webhooks/validating-webhook.yaml
+
+tests:
+  - it: should not create a ValidatingWebhookConfiguration if `controller.admissionWebhooks.enabled` is false
+    set:
+      controller.admissionWebhooks.enabled: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a ValidatingWebhookConfiguration if `controller.admissionWebhooks.enabled` is true
+    set:
+      controller.admissionWebhooks.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ValidatingWebhookConfiguration
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-admission
+
+  - it: should create a ValidatingWebhookConfiguration with a custom port if `controller.admissionWebhooks.service.servicePort` is set
+    set:
+      controller.admissionWebhooks.enabled: true
+      controller.admissionWebhooks.service.servicePort: 9443
+    asserts:
+      - equal:
+          path: webhooks[0].clientConfig.service.port
+          value: 9443
diff --git a/charts/ingress-nginx/tests/controller-configmap_test.yaml b/charts/ingress-nginx/tests/controller-configmap_test.yaml
index 0387603..168b657 100644
--- a/charts/ingress-nginx/tests/controller-configmap_test.yaml
+++ b/charts/ingress-nginx/tests/controller-configmap_test.yaml
@@ -12,3 +12,20 @@
       - equal:
           path: metadata.name
           value: RELEASE-NAME-ingress-nginx-controller
+
+  - it: should create a ConfigMap with templated values if `controller.config` contains templates
+    set:
+      controller.config:
+        template: "test.{{ .Release.Namespace }}.svc.kubernetes.local"
+        integer: 12345
+        boolean: true
+    asserts:
+      - equal:
+          path: data.template
+          value: test.NAMESPACE.svc.kubernetes.local
+      - equal:
+          path: data.integer
+          value: "12345"
+      - equal:
+          path: data.boolean
+          value: "true"
diff --git a/charts/ingress-nginx/tests/controller-daemonset_test.yaml b/charts/ingress-nginx/tests/controller-daemonset_test.yaml
index 29359fd..d2d77be 100644
--- a/charts/ingress-nginx/tests/controller-daemonset_test.yaml
+++ b/charts/ingress-nginx/tests/controller-daemonset_test.yaml
@@ -15,23 +15,23 @@
           path: metadata.name
           value: RELEASE-NAME-ingress-nginx-controller
 
-  - it: should create a DaemonSet with argument `--enable-metrics=false` if `controller.metrics.enabled` is false
-    set:
-      controller.kind: DaemonSet
-      controller.metrics.enabled: false
-    asserts:
-      - contains:
-          path: spec.template.spec.containers[0].args
-          content: --enable-metrics=false
-
-  - it: should create a DaemonSet without argument `--enable-metrics=false` if `controller.metrics.enabled` is true
+  - it: should create a DaemonSet with argument `--enable-metrics=true` if `controller.metrics.enabled` is true
     set:
       controller.kind: DaemonSet
       controller.metrics.enabled: true
     asserts:
+      - contains:
+          path: spec.template.spec.containers[0].args
+          content: --enable-metrics=true
+
+  - it: should create a DaemonSet without argument `--enable-metrics=true` if `controller.metrics.enabled` is false
+    set:
+      controller.kind: DaemonSet
+      controller.metrics.enabled: false
+    asserts:
       - notContains:
           path: spec.template.spec.containers[0].args
-          content: --enable-metrics=false
+          content: --enable-metrics=true
 
   - it: should create a DaemonSet with argument `--controller-class=k8s.io/ingress-nginx-internal` if `controller.ingressClassResource.controllerValue` is "k8s.io/ingress-nginx-internal"
     set:
@@ -95,3 +95,98 @@
               topologyKey: kubernetes.io/hostname
               maxSkew: 1
               whenUnsatisfiable: ScheduleAnyway
+
+  - it: should create a DaemonSet with affinity if `controller.affinity` is set
+    set:
+      controller.kind: DaemonSet
+      controller.affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - '{{ include "ingress-nginx.name" . }}'
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - '{{ .Release.Name }}'
+                  - key: app.kubernetes.io/component
+                    operator: In
+                    values:
+                      - controller
+              topologyKey: kubernetes.io/hostname
+    asserts:
+      - equal:
+          path: spec.template.spec.affinity
+          value:
+            podAntiAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                - labelSelector:
+                    matchExpressions:
+                      - key: app.kubernetes.io/name
+                        operator: In
+                        values:
+                          - ingress-nginx
+                      - key: app.kubernetes.io/instance
+                        operator: In
+                        values:
+                          - RELEASE-NAME
+                      - key: app.kubernetes.io/component
+                        operator: In
+                        values:
+                          - controller
+                  topologyKey: kubernetes.io/hostname
+
+  - it: should create a DaemonSet with `runAsGroup` if `controller.image.runAsGroup` is set
+    set:
+      controller.kind: DaemonSet
+      controller.image.runAsGroup: 1000
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsGroup
+          value: 1000
+
+  - it: should create a DaemonSet with a custom registry if `global.image.registry` is set
+    set:
+      global.image.registry: custom.registry.io
+      controller.kind: DaemonSet
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/ingress-nginx/controller:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a DaemonSet with a custom registry if `controller.image.registry` is set
+    set:
+      controller.kind: DaemonSet
+      controller.image.registry: custom.registry.io
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/ingress-nginx/controller:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a DaemonSet with a custom image if `controller.image.image` is set
+    set:
+      controller.kind: DaemonSet
+      controller.image.image: custom-repo/custom-image
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/custom-repo/custom-image:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a DaemonSet with a custom tag if `controller.image.tag` is set
+    set:
+      controller.kind: DaemonSet
+      controller.image.tag: custom-tag
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/ingress-nginx/controller:custom-tag@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
diff --git a/charts/ingress-nginx/tests/controller-deployment_test.yaml b/charts/ingress-nginx/tests/controller-deployment_test.yaml
index d0330db..1cc9c93 100644
--- a/charts/ingress-nginx/tests/controller-deployment_test.yaml
+++ b/charts/ingress-nginx/tests/controller-deployment_test.yaml
@@ -43,21 +43,21 @@
       - exists:
           path: spec.replicas
 
-  - it: should create a Deployment with argument `--enable-metrics=false` if `controller.metrics.enabled` is false
-    set:
-      controller.metrics.enabled: false
-    asserts:
-      - contains:
-          path: spec.template.spec.containers[0].args
-          content: --enable-metrics=false
-
-  - it: should create a Deployment without argument `--enable-metrics=false` if `controller.metrics.enabled` is true
+  - it: should create a Deployment with argument `--enable-metrics=true` if `controller.metrics.enabled` is true
     set:
       controller.metrics.enabled: true
     asserts:
+      - contains:
+          path: spec.template.spec.containers[0].args
+          content: --enable-metrics=true
+
+  - it: should create a Deployment without argument `--enable-metrics=true` if `controller.metrics.enabled` is false
+    set:
+      controller.metrics.enabled: false
+    asserts:
       - notContains:
           path: spec.template.spec.containers[0].args
-          content: --enable-metrics=false
+          content: --enable-metrics=true
 
   - it: should create a Deployment with argument `--controller-class=k8s.io/ingress-nginx-internal` if `controller.ingressClassResource.controllerValue` is "k8s.io/ingress-nginx-internal"
     set:
@@ -118,3 +118,100 @@
               topologyKey: kubernetes.io/hostname
               maxSkew: 1
               whenUnsatisfiable: ScheduleAnyway
+
+  - it: should create a Deployment with affinity if `controller.affinity` is set
+    set:
+      controller.affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - '{{ include "ingress-nginx.name" . }}'
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - '{{ .Release.Name }}'
+                  - key: app.kubernetes.io/component
+                    operator: In
+                    values:
+                      - controller
+              topologyKey: kubernetes.io/hostname
+    asserts:
+      - equal:
+          path: spec.template.spec.affinity
+          value:
+            podAntiAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                - labelSelector:
+                    matchExpressions:
+                      - key: app.kubernetes.io/name
+                        operator: In
+                        values:
+                          - ingress-nginx
+                      - key: app.kubernetes.io/instance
+                        operator: In
+                        values:
+                          - RELEASE-NAME
+                      - key: app.kubernetes.io/component
+                        operator: In
+                        values:
+                          - controller
+                  topologyKey: kubernetes.io/hostname
+
+  - it: should create a Deployment with `runAsGroup` if `controller.image.runAsGroup` is set
+    set:
+      controller.image.runAsGroup: 1000
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsGroup
+          value: 1000
+
+  - it: should create a Deployment with a custom registry if `global.image.registry` is set
+    set:
+      global.image.registry: custom.registry.io
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/ingress-nginx/controller:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom registry if `controller.image.registry` is set
+    set:
+      controller.image.registry: custom.registry.io
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/ingress-nginx/controller:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom image if `controller.image.image` is set
+    set:
+      controller.image.image: custom-repo/custom-image
+      controller.image.tag: v1.0.0-dev
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/custom-repo/custom-image:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom tag if `controller.image.tag` is set
+    set:
+      controller.image.tag: custom-tag
+      controller.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/ingress-nginx/controller:custom-tag@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with `progressDeadlineSeconds` if `controller.progressDeadlineSeconds` is set
+    set:
+      controller.progressDeadlineSeconds: 111
+    asserts:
+      - equal:
+          path: spec.progressDeadlineSeconds
+          value: 111
diff --git a/charts/ingress-nginx/tests/controller-ingressclass-aliases_test.yaml b/charts/ingress-nginx/tests/controller-ingressclass-aliases_test.yaml
new file mode 100644
index 0000000..9a4a576
--- /dev/null
+++ b/charts/ingress-nginx/tests/controller-ingressclass-aliases_test.yaml
@@ -0,0 +1,110 @@
+suite: Controller > IngressClass > Aliases
+templates:
+  - controller-ingressclass-aliases.yaml
+
+tests:
+  - it: should not create IngressClass aliases
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create an IngressClass alias with name "nginx-alias" if `controller.ingressClassResource.aliases` is set
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx-alias
+
+  - it: should create an IngressClass alias without annotation `ingressclass.kubernetes.io/is-default-class` if `controller.ingressClassResource.default` is true
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias
+      controller.ingressClassResource.default: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx-alias
+      - notExists:
+          path: metadata.annotations["ingressclass.kubernetes.io/is-default-class"]
+
+  - it: should create an IngressClass alias with annotations if `controller.ingressClassResource.annotations` is set
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias
+      controller.ingressClassResource.annotations:
+        my-fancy-annotation: has-a-value
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx-alias
+      - equal:
+          path: metadata.annotations.my-fancy-annotation
+          value: has-a-value
+
+  - it: should create an IngressClass alias with controller "k8s.io/ingress-nginx-internal" if `controller.ingressClassResource.controllerValue` is "k8s.io/ingress-nginx-internal"
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias
+      controller.ingressClassResource.controllerValue: k8s.io/ingress-nginx-internal
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx-alias
+      - equal:
+          path: spec.controller
+          value: k8s.io/ingress-nginx-internal
+
+  - it: should create an IngressClass alias with parameters if `controller.ingressClassResource.parameters` is set
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias
+      controller.ingressClassResource.parameters:
+        apiGroup: k8s.example.com
+        kind: IngressParameters
+        name: external-lb
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx-alias
+      - equal:
+          path: spec.parameters
+          value:
+            apiGroup: k8s.example.com
+            kind: IngressParameters
+            name: external-lb
+
+  - it: should create two IngressClass aliases if `controller.ingressClassResource.aliases` has two elements
+    set:
+      controller.ingressClassResource.aliases:
+        - nginx-alias-1
+        - nginx-alias-2
+    asserts:
+      - hasDocuments:
+          count: 2
+      - isKind:
+          of: IngressClass
+      - matchRegex:
+          path: metadata.name
+          pattern: nginx-alias-(1|2)
diff --git a/charts/ingress-nginx/tests/controller-ingressclass_test.yaml b/charts/ingress-nginx/tests/controller-ingressclass_test.yaml
index f766f92..b3384af 100644
--- a/charts/ingress-nginx/tests/controller-ingressclass_test.yaml
+++ b/charts/ingress-nginx/tests/controller-ingressclass_test.yaml
@@ -40,6 +40,22 @@
           path: metadata.annotations["ingressclass.kubernetes.io/is-default-class"]
           value: "true"
 
+  - it: should create an IngressClass with annotations if `controller.ingressClassResource.annotations` is set
+    set:
+      controller.ingressClassResource.annotations:
+        my-fancy-annotation: has-a-value
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: IngressClass
+      - equal:
+          path: metadata.name
+          value: nginx
+      - equal:
+          path: metadata.annotations.my-fancy-annotation
+          value: has-a-value
+
   - it: should create an IngressClass with controller "k8s.io/ingress-nginx-internal" if `controller.ingressClassResource.controllerValue` is "k8s.io/ingress-nginx-internal"
     set:
       controller.ingressClassResource.controllerValue: k8s.io/ingress-nginx-internal
diff --git a/charts/ingress-nginx/tests/controller-poddisruptionbudget_test.yaml b/charts/ingress-nginx/tests/controller-poddisruptionbudget_test.yaml
index 48b4faf..5ac986f 100644
--- a/charts/ingress-nginx/tests/controller-poddisruptionbudget_test.yaml
+++ b/charts/ingress-nginx/tests/controller-poddisruptionbudget_test.yaml
@@ -71,3 +71,32 @@
     asserts:
       - hasDocuments:
           count: 0
+
+  - it: should create a PodDisruptionBudget without `minAvailable` and with `maxUnavailable` if `controller.minAvailable` and `controller.maxUnavailable` are set
+    set:
+      controller.replicaCount: 2
+      controller.minAvailable: 1
+      controller.maxUnavailable: 1
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - notExists:
+          path: spec.minAvailable
+      - equal:
+          path: spec.maxUnavailable
+          value: 1
+
+  - it: should create a PodDisruptionBudget with `unhealthyPodEvictionPolicy` if `controller.unhealthyPodEvictionPolicy` is set
+    set:
+      controller.replicaCount: 2
+      controller.unhealthyPodEvictionPolicy: IfHealthyBudget
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - equal:
+          path: spec.unhealthyPodEvictionPolicy
+          value: IfHealthyBudget
diff --git a/charts/ingress-nginx/tests/controller-prometheusrule_test.yaml b/charts/ingress-nginx/tests/controller-prometheusrule_test.yaml
new file mode 100644
index 0000000..2d33091
--- /dev/null
+++ b/charts/ingress-nginx/tests/controller-prometheusrule_test.yaml
@@ -0,0 +1,29 @@
+suite: Controller > PrometheusRule
+templates:
+  - controller-prometheusrule.yaml
+
+tests:
+  - it: should create a PrometheusRule if `controller.metrics.prometheusRule.enabled` is true
+    set:
+      controller.metrics.enabled: true
+      controller.metrics.prometheusRule.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PrometheusRule
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-controller
+
+  - it: should create a PrometheusRule with annotations if `controller.metrics.prometheusRule.annotations` is set
+    set:
+      controller.metrics.enabled: true
+      controller.metrics.prometheusRule.enabled: true
+      controller.metrics.prometheusRule.annotations:
+        my-little-annotation: test-value
+    asserts:
+      - equal:
+          path: metadata.annotations
+          value:
+            my-little-annotation: test-value
diff --git a/charts/ingress-nginx/tests/controller-service-metrics_test.yaml b/charts/ingress-nginx/tests/controller-service-metrics_test.yaml
index afdb940..ddb412e 100644
--- a/charts/ingress-nginx/tests/controller-service-metrics_test.yaml
+++ b/charts/ingress-nginx/tests/controller-service-metrics_test.yaml
@@ -3,16 +3,34 @@
   - controller-service-metrics.yaml
 
 tests:
-  - it: should not create a metrics Service if `controller.metrics.enabled` is false
+  - it: should not create a metrics Service if `controller.metrics.enabled` is false and `controller.metrics.service.enabled` is false
     set:
       controller.metrics.enabled: false
+      controller.metrics.service.enabled: false
     asserts:
       - hasDocuments:
           count: 0
 
-  - it: should create a metrics Service if `controller.metrics.enabled` is true
+  - it: should not create a metrics Service if `controller.metrics.enabled` is false and `controller.metrics.service.enabled` is true
+    set:
+      controller.metrics.enabled: false
+      controller.metrics.service.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should not create a metrics Service if `controller.metrics.enabled` is true and `controller.metrics.service.enabled` is false
     set:
       controller.metrics.enabled: true
+      controller.metrics.service.enabled: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a metrics Service if `controller.metrics.enabled` is true and `controller.metrics.service.enabled` is true
+    set:
+      controller.metrics.enabled: true
+      controller.metrics.service.enabled: true
     asserts:
       - hasDocuments:
           count: 1
diff --git a/charts/ingress-nginx/tests/controller-service-webhook_test.yaml b/charts/ingress-nginx/tests/controller-service-webhook_test.yaml
new file mode 100644
index 0000000..1c759ed
--- /dev/null
+++ b/charts/ingress-nginx/tests/controller-service-webhook_test.yaml
@@ -0,0 +1,32 @@
+suite: Controller > Service > Webhook
+templates:
+  - controller-service-webhook.yaml
+
+tests:
+  - it: should not create a webhook Service if `controller.admissionWebhooks.enabled` is false
+    set:
+      controller.admissionWebhooks.enabled: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a webhook Service if `controller.admissionWebhooks.enabled` is true
+    set:
+      controller.admissionWebhooks.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: Service
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-controller-admission
+
+  - it: should create a webhook Service with a custom port if `controller.admissionWebhooks.service.servicePort` is set
+    set:
+      controller.admissionWebhooks.enabled: true
+      controller.admissionWebhooks.service.servicePort: 9443
+    asserts:
+      - equal:
+          path: spec.ports[0].port
+          value: 9443
diff --git a/charts/ingress-nginx/tests/controller-serviceaccount_test.yaml b/charts/ingress-nginx/tests/controller-serviceaccount_test.yaml
new file mode 100644
index 0000000..928e537
--- /dev/null
+++ b/charts/ingress-nginx/tests/controller-serviceaccount_test.yaml
@@ -0,0 +1,47 @@
+suite: Controller > ServiceAccount
+templates:
+  - controller-serviceaccount.yaml
+
+tests:
+  - it: should not create a ServiceAccount if `serviceAccount.create` is false
+    set:
+      serviceAccount.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a ServiceAccount if `serviceAccount.create` is true
+    set:
+      serviceAccount.create: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx
+
+  - it: should create a ServiceAccount with specified name if `serviceAccount.name` is set
+    set:
+      serviceAccount.name: ingress-nginx-admission-test-sa
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: ingress-nginx-admission-test-sa
+
+  - it: should create a ServiceAccount with token auto-mounting disabled if `serviceAccount.automountServiceAccountToken` is false
+    set:
+      serviceAccount.automountServiceAccountToken: false
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: automountServiceAccountToken
+          value: false
diff --git a/charts/ingress-nginx/tests/controller-servicemonitor_test.yaml b/charts/ingress-nginx/tests/controller-servicemonitor_test.yaml
new file mode 100644
index 0000000..310097c
--- /dev/null
+++ b/charts/ingress-nginx/tests/controller-servicemonitor_test.yaml
@@ -0,0 +1,29 @@
+suite: Controller > ServiceMonitor
+templates:
+  - controller-servicemonitor.yaml
+
+tests:
+  - it: should create a ServiceMonitor if `controller.metrics.serviceMonitor.enabled` is true
+    set:
+      controller.metrics.enabled: true
+      controller.metrics.serviceMonitor.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceMonitor
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-controller
+
+  - it: should create a ServiceMonitor with annotations if `controller.metrics.serviceMonitor.annotations` is set
+    set:
+      controller.metrics.enabled: true
+      controller.metrics.serviceMonitor.enabled: true
+      controller.metrics.serviceMonitor.annotations:
+        my-little-annotation: test-value
+    asserts:
+      - equal:
+          path: metadata.annotations
+          value:
+            my-little-annotation: test-value
diff --git a/charts/ingress-nginx/tests/default-backend-deployment_test.yaml b/charts/ingress-nginx/tests/default-backend-deployment_test.yaml
index 0593cfb..c3fa339 100644
--- a/charts/ingress-nginx/tests/default-backend-deployment_test.yaml
+++ b/charts/ingress-nginx/tests/default-backend-deployment_test.yaml
@@ -51,3 +51,139 @@
       - equal:
           path: spec.template.spec.containers[0].resources.limits.memory
           value: 512Mi
+
+  - it: should create a Deployment with topology spread constraints if `defaultBackend.topologySpreadConstraints` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.topologySpreadConstraints:
+        - labelSelector:
+            matchLabels:
+              app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
+              app.kubernetes.io/instance: '{{ .Release.Name }}'
+              app.kubernetes.io/component: default-backend
+          topologyKey: topology.kubernetes.io/zone
+          maxSkew: 1
+          whenUnsatisfiable: ScheduleAnyway
+        - labelSelector:
+            matchLabels:
+              app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
+              app.kubernetes.io/instance: '{{ .Release.Name }}'
+              app.kubernetes.io/component: default-backend
+          topologyKey: kubernetes.io/hostname
+          maxSkew: 1
+          whenUnsatisfiable: ScheduleAnyway
+    asserts:
+      - equal:
+          path: spec.template.spec.topologySpreadConstraints
+          value:
+            - labelSelector:
+                matchLabels:
+                  app.kubernetes.io/name: ingress-nginx
+                  app.kubernetes.io/instance: RELEASE-NAME
+                  app.kubernetes.io/component: default-backend
+              topologyKey: topology.kubernetes.io/zone
+              maxSkew: 1
+              whenUnsatisfiable: ScheduleAnyway
+            - labelSelector:
+                matchLabels:
+                  app.kubernetes.io/name: ingress-nginx
+                  app.kubernetes.io/instance: RELEASE-NAME
+                  app.kubernetes.io/component: default-backend
+              topologyKey: kubernetes.io/hostname
+              maxSkew: 1
+              whenUnsatisfiable: ScheduleAnyway
+
+  - it: should create a Deployment with affinity if `defaultBackend.affinity` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchExpressions:
+                  - key: app.kubernetes.io/name
+                    operator: In
+                    values:
+                      - '{{ include "ingress-nginx.name" . }}'
+                  - key: app.kubernetes.io/instance
+                    operator: In
+                    values:
+                      - '{{ .Release.Name }}'
+                  - key: app.kubernetes.io/component
+                    operator: In
+                    values:
+                      - default-backend
+              topologyKey: kubernetes.io/hostname
+    asserts:
+      - equal:
+          path: spec.template.spec.affinity
+          value:
+            podAntiAffinity:
+              requiredDuringSchedulingIgnoredDuringExecution:
+                - labelSelector:
+                    matchExpressions:
+                      - key: app.kubernetes.io/name
+                        operator: In
+                        values:
+                          - ingress-nginx
+                      - key: app.kubernetes.io/instance
+                        operator: In
+                        values:
+                          - RELEASE-NAME
+                      - key: app.kubernetes.io/component
+                        operator: In
+                        values:
+                          - default-backend
+                  topologyKey: kubernetes.io/hostname
+
+  - it: should create a Deployment with `runAsGroup` if `defaultBackend.image.runAsGroup` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.image.runAsGroup: 1000
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsGroup
+          value: 1000
+
+  - it: should create a Deployment with a custom registry if `global.image.registry` is set
+    set:
+      global.image.registry: custom.registry.io
+      defaultBackend.enabled: true
+      defaultBackend.image.tag: v1.0.0-dev
+      defaultBackend.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/defaultbackend-amd64:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom registry if `defaultBackend.image.registry` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.image.registry: custom.registry.io
+      defaultBackend.image.tag: v1.0.0-dev
+      defaultBackend.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: custom.registry.io/defaultbackend-amd64:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom image if `defaultBackend.image.image` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.image.image: custom-repo/custom-image
+      defaultBackend.image.tag: v1.0.0-dev
+      defaultBackend.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/custom-repo/custom-image:v1.0.0-dev@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+
+  - it: should create a Deployment with a custom tag if `defaultBackend.image.tag` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.image.tag: custom-tag
+      defaultBackend.image.digest: sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].image
+          value: registry.k8s.io/defaultbackend-amd64:custom-tag@sha256:faa2d18687f734994b6bd9e309e7a73852a81c30e1b8f63165fcd4f0a087e3cd
diff --git a/charts/ingress-nginx/tests/default-backend-poddisruptionbudget_test.yaml b/charts/ingress-nginx/tests/default-backend-poddisruptionbudget_test.yaml
new file mode 100644
index 0000000..bfe98e8
--- /dev/null
+++ b/charts/ingress-nginx/tests/default-backend-poddisruptionbudget_test.yaml
@@ -0,0 +1,79 @@
+suite: Default Backend > PodDisruptionBudget
+templates:
+  - default-backend-poddisruptionbudget.yaml
+
+tests:
+  - it: should create a PodDisruptionBudget if `defaultBackend.replicaCount` is greater than 1
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.replicaCount: 2
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-defaultbackend
+
+  - it: should not create a PodDisruptionBudget if `defaultBackend.replicaCount` is less than or equal 1
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.replicaCount: 1
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a PodDisruptionBudget if `defaultBackend.autoscaling.enabled` is true and `defaultBackend.autoscaling.minReplicas` is greater than 1
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.autoscaling.enabled: true
+      defaultBackend.autoscaling.minReplicas: 2
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-defaultbackend
+
+  - it: should not create a PodDisruptionBudget if `defaultBackend.autoscaling.enabled` is true and `defaultBackend.autoscaling.minReplicas` is less than or equal 1
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.autoscaling.enabled: true
+      defaultBackend.autoscaling.minReplicas: 1
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a PodDisruptionBudget without `minAvailable` and with `maxUnavailable` if `defaultBackend.minAvailable` and `defaultBackend.maxUnavailable` are set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.replicaCount: 2
+      defaultBackend.minAvailable: 1
+      defaultBackend.maxUnavailable: 1
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - notExists:
+          path: spec.minAvailable
+      - equal:
+          path: spec.maxUnavailable
+          value: 1
+
+  - it: should create a PodDisruptionBudget with `unhealthyPodEvictionPolicy` if `defaultBackend.unhealthyPodEvictionPolicy` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.replicaCount: 2
+      defaultBackend.unhealthyPodEvictionPolicy: IfHealthyBudget
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: PodDisruptionBudget
+      - equal:
+          path: spec.unhealthyPodEvictionPolicy
+          value: IfHealthyBudget
diff --git a/charts/ingress-nginx/tests/default-backend-serviceaccount_test.yaml b/charts/ingress-nginx/tests/default-backend-serviceaccount_test.yaml
new file mode 100644
index 0000000..05a815d
--- /dev/null
+++ b/charts/ingress-nginx/tests/default-backend-serviceaccount_test.yaml
@@ -0,0 +1,51 @@
+suite: Default Backend > ServiceAccount
+templates:
+  - default-backend-serviceaccount.yaml
+
+tests:
+  - it: should not create a ServiceAccount if `defaultBackend.serviceAccount.create` is false
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.serviceAccount.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should create a ServiceAccount if `defaultBackend.serviceAccount.create` is true
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.serviceAccount.create: true
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-ingress-nginx-backend
+
+  - it: should create a ServiceAccount with specified name if `defaultBackend.serviceAccount.name` is set
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.serviceAccount.name: ingress-nginx-admission-test-sa
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: ingress-nginx-admission-test-sa
+
+  - it: should create a ServiceAccount with token auto-mounting disabled if `defaultBackend.serviceAccount.automountServiceAccountToken` is false
+    set:
+      defaultBackend.enabled: true
+      defaultBackend.serviceAccount.automountServiceAccountToken: false
+    asserts:
+      - hasDocuments:
+          count: 1
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: automountServiceAccountToken
+          value: false
diff --git a/charts/ingress-nginx/values.yaml b/charts/ingress-nginx/values.yaml
index 68f8b58..5da493d 100644
--- a/charts/ingress-nginx/values.yaml
+++ b/charts/ingress-nginx/values.yaml
@@ -2,6 +2,10 @@
 ## Ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/index.md
 ##
 
+global:
+  image:
+    # -- Registry host to pull images from.
+    registry: registry.k8s.io
 ## Overrides for generated resource names
 # See templates/_helpers.tpl
 # nameOverride:
@@ -17,35 +21,38 @@
 
 controller:
   name: controller
-  enableAnnotationValidations: false
+  enableAnnotationValidations: true
   image:
     ## Keep false as default for now!
     chroot: false
-    registry: registry.k8s.io
+    # registry: registry.k8s.io
     image: ingress-nginx/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: "v1.10.1"
-    digest: sha256:e24f39d3eed6bcc239a56f20098878845f62baa34b9f2be2fd2c38ce9fb0f29e
-    digestChroot: sha256:c155954116b397163c88afcb3252462771bd7867017e8a17623e83601bab7ac7
+    tag: "v1.12.1"
+    digest: sha256:d2fbc4ec70d8aa2050dd91a91506e998765e86c96f32cffb56c503c9c34eed5b
+    digestChroot: sha256:90155c86548e0bb95b3abf1971cd687d8f5d43f340cfca0ad3484e2b8351096e
     pullPolicy: IfNotPresent
     runAsNonRoot: true
-    # www-data -> uid 101
+    # -- This value must not be changed using the official image.
+    # uid=101(www-data) gid=82(www-data) groups=82(www-data)
     runAsUser: 101
+    # -- This value must not be changed using the official image.
+    # uid=101(www-data) gid=82(www-data) groups=82(www-data)
+    runAsGroup: 82
     allowPrivilegeEscalation: false
     seccompProfile:
       type: RuntimeDefault
     readOnlyRootFilesystem: false
-  # -- Use an existing PSP instead of creating one
-  existingPsp: ""
   # -- Configures the controller container name
   containerName: controller
   # -- Configures the ports that the nginx-controller listens on
   containerPort:
     http: 80
     https: 443
-  # -- Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
+  # -- Global configuration passed to the ConfigMap consumed by the controller. Values may contain Helm templates.
+  # Ref.: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
   config: {}
   # -- Annotations to be added to the controller config configuration configmap.
   configAnnotations: {}
@@ -83,6 +90,10 @@
   # -- This configuration enables Topology Aware Routing feature, used together with service annotation service.kubernetes.io/topology-mode="auto"
   # Defaults to false
   enableTopologyAwareRouting: false
+  # -- This configuration disable Nginx Controller Leader Election
+  disableLeaderElection: false
+  # -- Duration a leader election is valid before it's getting re-elected, e.g. `15s`, `10m` or `1h`. (Default: 30s)
+  electionTTL: ""
   # -- This configuration defines if Ingress Controller should allow users to set
   # their own *-snippet annotations, otherwise this is forbidden / dropped
   # when users add those annotations.
@@ -120,10 +131,19 @@
     # Ingress creation gets rejected if there are multiple default IngressClasses.
     # Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#default-ingress-class
     default: false
+    # -- Annotations to be added to the IngressClass resource.
+    annotations: {}
     # -- Controller of the IngressClass. An Ingress Controller looks for IngressClasses it should reconcile by this value.
     # This value is also being set as the `--controller-class` argument of this Ingress Controller.
     # Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class
     controllerValue: k8s.io/ingress-nginx
+    # -- Aliases of this IngressClass. Creates copies with identical settings but the respective alias as name.
+    # Useful for development environments with only one Ingress Controller but production-like Ingress resources.
+    # `default` gets enabled on the original IngressClass only.
+    aliases: []
+    # aliases:
+    # - nginx-alias-1
+    # - nginx-alias-2
     # -- A link to a custom resource containing additional configuration for the controller.
     # This is optional if the controller consuming this IngressClass does not require additional parameters.
     # Ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class
@@ -180,7 +200,7 @@
     # -- Annotations to be added to the udp config configmap
     annotations: {}
   # -- Maxmind license key to download GeoLite2 Databases.
-  ## https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-geolite2-databases
+  ## https://blog.maxmind.com/2019/12/significant-changes-to-accessing-and-using-geolite2-databases/
   maxmindLicenseKey: ""
   # -- Additional command line arguments to pass to Ingress-Nginx Controller
   # E.g. to specify the default SSL certificate you can use
@@ -220,6 +240,9 @@
   #    maxUnavailable: 1
   #  type: RollingUpdate
 
+  # -- Specifies the number of seconds you want to wait for the controller deployment to progress before the system reports back that it has failed.
+  # Ref.: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#progress-deadline-seconds
+  progressDeadlineSeconds: 0
   # -- `minReadySeconds` to avoid killing pods before we are ready
   ##
   minReadySeconds: 0
@@ -246,11 +269,11 @@
   #         - key: app.kubernetes.io/name
   #           operator: In
   #           values:
-  #           - ingress-nginx
+  #           - '{{ include "ingress-nginx.name" . }}'
   #         - key: app.kubernetes.io/instance
   #           operator: In
   #           values:
-  #           - ingress-nginx
+  #           - '{{ .Release.Name }}'
   #         - key: app.kubernetes.io/component
   #           operator: In
   #           values:
@@ -265,16 +288,16 @@
   #       - key: app.kubernetes.io/name
   #         operator: In
   #         values:
-  #         - ingress-nginx
+  #         - '{{ include "ingress-nginx.name" . }}'
   #       - key: app.kubernetes.io/instance
   #         operator: In
   #         values:
-  #         - ingress-nginx
+  #         - '{{ .Release.Name }}'
   #       - key: app.kubernetes.io/component
   #         operator: In
   #         values:
   #         - controller
-  #     topologyKey: "kubernetes.io/hostname"
+  #     topologyKey: kubernetes.io/hostname
 
   # -- Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in.
   ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
@@ -285,6 +308,8 @@
   #       app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
   #       app.kubernetes.io/instance: '{{ .Release.Name }}'
   #       app.kubernetes.io/component: controller
+  #   matchLabelKeys:
+  #   - pod-template-hash
   #   topologyKey: topology.kubernetes.io/zone
   #   maxSkew: 1
   #   whenUnsatisfiable: ScheduleAnyway
@@ -293,6 +318,8 @@
   #       app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
   #       app.kubernetes.io/instance: '{{ .Release.Name }}'
   #       app.kubernetes.io/component: controller
+  #   matchLabelKeys:
+  #   - pod-template-hash
   #   topologyKey: kubernetes.io/hostname
   #   maxSkew: 1
   #   whenUnsatisfiable: ScheduleAnyway
@@ -358,7 +385,9 @@
   minAvailable: 1
   # -- Maximum unavailable pods set in PodDisruptionBudget. If set, 'minAvailable' is ignored.
   # maxUnavailable: 1
-
+  # -- Eviction policy for unhealthy pods guarded by PodDisruptionBudget.
+  # Ref: https://kubernetes.io/blog/2023/01/06/unhealthy-pod-eviction-policy-for-pdbs/
+  unhealthyPodEvictionPolicy: ""
   ## Define requests resources to avoid probe issues due to CPU utilization in busy nodes
   ## ref: https://github.com/kubernetes/ingress-nginx/issues/4735#issuecomment-551204903
   ## Ideally, there should be no limits.
@@ -659,11 +688,11 @@
   #   image: busybox
   #   command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
 
-  # -- Modules, which are mounted into the core nginx image. See values.yaml for a sample to add opentelemetry module
+  # -- Modules, which are mounted into the core nginx image.
   extraModules: []
   # - name: mytestmodule
   #   image:
-  #     registry: registry.k8s.io
+  #     # registry: registry.k8s.io
   #     image: ingress-nginx/mytestmodule
   #     ## 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
@@ -674,6 +703,7 @@
   #   containerSecurityContext:
   #     runAsNonRoot: true
   #     runAsUser: <user-id>
+  #     runAsGroup: <group-id>
   #     allowPrivilegeEscalation: false
   #     seccompProfile:
   #       type: RuntimeDefault
@@ -687,30 +717,6 @@
   # will be executed as initContainers, to move its config files within the
   # mounted volume.
 
-  opentelemetry:
-    enabled: false
-    name: opentelemetry
-    image:
-      registry: registry.k8s.io
-      image: ingress-nginx/opentelemetry
-      ## 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: "v20230721-3e2062ee5"
-      digest: sha256:13bee3f5223883d3ca62fee7309ad02d22ec00ff0d7033e3e9aca7a9f60fd472
-      distroless: true
-    containerSecurityContext:
-      runAsNonRoot: true
-      # -- The image's default user, inherited from its base image `cgr.dev/chainguard/static`.
-      runAsUser: 65532
-      allowPrivilegeEscalation: false
-      seccompProfile:
-        type: RuntimeDefault
-      capabilities:
-        drop:
-          - ALL
-      readOnlyRootFilesystem: true
-    resources: {}
   admissionWebhooks:
     name: admission
     annotations: {}
@@ -738,8 +744,6 @@
     objectSelector: {}
     # -- Labels to be added to admission webhooks
     labels: {}
-    # -- Use an existing PSP instead of creating one
-    existingPsp: ""
     service:
       annotations: {}
       # clusterIP: ""
@@ -754,6 +758,7 @@
       securityContext:
         runAsNonRoot: true
         runAsUser: 65532
+        runAsGroup: 65532
         allowPrivilegeEscalation: false
         seccompProfile:
           type: RuntimeDefault
@@ -774,6 +779,7 @@
       securityContext:
         runAsNonRoot: true
         runAsUser: 65532
+        runAsGroup: 65532
         allowPrivilegeEscalation: false
         seccompProfile:
           type: RuntimeDefault
@@ -785,13 +791,13 @@
     patch:
       enabled: true
       image:
-        registry: registry.k8s.io
+        # registry: registry.k8s.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.4.1
-        digest: sha256:36d05b4077fb8e3d13663702fa337f124675ba8667cbd949c03a8e8ea6fa4366
+        tag: v1.5.2
+        digest: sha256:e8825994b7a2c7497375a9b945f386506ca6a3eda80b89b74ef2db743f66a5ea
         pullPolicy: IfNotPresent
       # -- Provide a priority class name to the webhook patching job
       ##
@@ -808,6 +814,18 @@
       labels: {}
       # -- Security context for secret creation & webhook patch pods
       securityContext: {}
+      # -- Admission webhook patch job RBAC
+      rbac:
+        # -- Create RBAC or not
+        create: true
+      # -- Admission webhook patch job service account
+      serviceAccount:
+        # -- Create a service account or not
+        create: true
+        # -- Custom service account name
+        name: ""
+        # -- Auto-mount service account token or not
+        automountServiceAccountToken: true
     # Use certmanager to generate webhook certs
     certManager:
       enabled: false
@@ -827,6 +845,8 @@
     # if this port is changed, change healthz-port: in extraArgs: accordingly
     enabled: false
     service:
+      # -- Enable the metrics service or not.
+      enabled: true
       annotations: {}
       # prometheus.io/scrape: "true"
       # prometheus.io/port: "10254"
@@ -847,6 +867,7 @@
     serviceMonitor:
       enabled: false
       additionalLabels: {}
+      # -- Annotations to be added to the ServiceMonitor.
       annotations: {}
       ## The label to use to retrieve the job name from.
       ## jobLabel: "app.kubernetes.io/name"
@@ -864,6 +885,8 @@
     prometheusRule:
       enabled: false
       additionalLabels: {}
+      # -- Annotations to be added to the PrometheusRule.
+      annotations: {}
       # namespace: ""
       rules: []
       # # These are just examples rules, please adapt them to your needs
@@ -927,7 +950,7 @@
   enabled: false
   name: defaultbackend
   image:
-    registry: registry.k8s.io
+    # registry: registry.k8s.io
     image: defaultbackend-amd64
     ## 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
@@ -937,12 +960,11 @@
     runAsNonRoot: true
     # nobody user -> uid 65534
     runAsUser: 65534
+    runAsGroup: 65534
     allowPrivilegeEscalation: false
     seccompProfile:
       type: RuntimeDefault
     readOnlyRootFilesystem: true
-  # -- Use an existing PSP instead of creating one
-  existingPsp: ""
   extraArgs: {}
   serviceAccount:
     create: true
@@ -985,7 +1007,72 @@
   #    value: "value"
   #    effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)"
 
+  # -- Affinity and anti-affinity rules for server scheduling to nodes
+  ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
   affinity: {}
+  # # An example of preferred pod anti-affinity, weight is in the range 1-100
+  # podAntiAffinity:
+  #   preferredDuringSchedulingIgnoredDuringExecution:
+  #   - weight: 100
+  #     podAffinityTerm:
+  #       labelSelector:
+  #         matchExpressions:
+  #         - key: app.kubernetes.io/name
+  #           operator: In
+  #           values:
+  #           - '{{ include "ingress-nginx.name" . }}'
+  #         - key: app.kubernetes.io/instance
+  #           operator: In
+  #           values:
+  #           - '{{ .Release.Name }}'
+  #         - key: app.kubernetes.io/component
+  #           operator: In
+  #           values:
+  #           - default-backend
+  #       topologyKey: kubernetes.io/hostname
+
+  # # An example of required pod anti-affinity
+  # podAntiAffinity:
+  #   requiredDuringSchedulingIgnoredDuringExecution:
+  #   - labelSelector:
+  #       matchExpressions:
+  #       - key: app.kubernetes.io/name
+  #         operator: In
+  #         values:
+  #         - '{{ include "ingress-nginx.name" . }}'
+  #       - key: app.kubernetes.io/instance
+  #         operator: In
+  #         values:
+  #         - '{{ .Release.Name }}'
+  #       - key: app.kubernetes.io/component
+  #         operator: In
+  #         values:
+  #         - default-backend
+  #     topologyKey: kubernetes.io/hostname
+
+  # -- Topology spread constraints rely on node labels to identify the topology domain(s) that each Node is in.
+  # Ref.: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/
+  topologySpreadConstraints: []
+  # - labelSelector:
+  #     matchLabels:
+  #       app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
+  #       app.kubernetes.io/instance: '{{ .Release.Name }}'
+  #       app.kubernetes.io/component: default-backend
+  #   matchLabelKeys:
+  #   - pod-template-hash
+  #   topologyKey: topology.kubernetes.io/zone
+  #   maxSkew: 1
+  #   whenUnsatisfiable: ScheduleAnyway
+  # - labelSelector:
+  #     matchLabels:
+  #       app.kubernetes.io/name: '{{ include "ingress-nginx.name" . }}'
+  #       app.kubernetes.io/instance: '{{ .Release.Name }}'
+  #       app.kubernetes.io/component: default-backend
+  #   matchLabelKeys:
+  #   - pod-template-hash
+  #   topologyKey: kubernetes.io/hostname
+  #   maxSkew: 1
+  #   whenUnsatisfiable: ScheduleAnyway
   # -- Security context for default backend pods
   podSecurityContext: {}
   # -- Security context for default backend containers
@@ -1003,7 +1090,14 @@
   ##
   podAnnotations: {}
   replicaCount: 1
+  # -- Minimum available pods set in PodDisruptionBudget.
+  # Define either 'minAvailable' or 'maxUnavailable', never both.
   minAvailable: 1
+  # -- Maximum unavailable pods set in PodDisruptionBudget. If set, 'minAvailable' is ignored.
+  # maxUnavailable: 1
+  # -- Eviction policy for unhealthy pods guarded by PodDisruptionBudget.
+  # Ref: https://kubernetes.io/blog/2023/01/06/unhealthy-pod-eviction-policy-for-pdbs/
+  unhealthyPodEvictionPolicy: ""
   resources: {}
   # limits:
   #   cpu: 10m
@@ -1067,10 +1161,6 @@
 rbac:
   create: true
   scope: false
-## If true, create & use Pod Security Policy resources
-## https://kubernetes.io/docs/concepts/policy/pod-security-policy/
-podSecurityPolicy:
-  enabled: false
 serviceAccount:
   create: true
   name: ""
diff --git a/releasenotes/notes/update-nginx-ingress-for-cve-6c2aea8e2c530421.yaml b/releasenotes/notes/update-nginx-ingress-for-cve-6c2aea8e2c530421.yaml
new file mode 100644
index 0000000..f704650
--- /dev/null
+++ b/releasenotes/notes/update-nginx-ingress-for-cve-6c2aea8e2c530421.yaml
@@ -0,0 +1,5 @@
+---
+security:
+  - |
+    Upgrade nginx ingress controller from 1.10.1 to 1.12.1 to fix CVE-2025-1097
+    CVE-2025-1098, CVE-2025-1974, CVE-2025-24513, CVE-2025-24514.
diff --git a/roles/defaults/vars/main.yml b/roles/defaults/vars/main.yml
index cf83407..85f2703 100644
--- a/roles/defaults/vars/main.yml
+++ b/roles/defaults/vars/main.yml
@@ -85,9 +85,9 @@
   ibm_block_csi_resizer: "{{ atmosphere_image_prefix }}registry.k8s.io/sig-storage/csi-resizer:v1.7.0"
   ibm_block_csi_snapshotter: "{{ atmosphere_image_prefix }}registry.k8s.io/sig-storage/csi-snapshotter:v6.2.1"
   ibm_block_csi_volume_group: "{{ atmosphere_image_prefix }}quay.io/ibmcsiblock/csi-volume-group-operator:v0.9.1"
-  ingress_nginx_controller: "{{ atmosphere_image_prefix }}registry.k8s.io/ingress-nginx/controller:v1.10.1"
+  ingress_nginx_controller: "{{ atmosphere_image_prefix }}registry.k8s.io/ingress-nginx/controller:v1.12.1"
   ingress_nginx_default_backend: "{{ atmosphere_image_prefix }}registry.k8s.io/defaultbackend-amd64:1.5"
-  ingress_nginx_kube_webhook_certgen: "{{ atmosphere_image_prefix }}registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.4.1"
+  ingress_nginx_kube_webhook_certgen: "{{ atmosphere_image_prefix }}registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.5.2"
   ironic_api: "{{ atmosphere_image_prefix }}registry.atmosphere.dev/library/ironic:{{ atmosphere_release }}"
   ironic_conductor: "{{ atmosphere_image_prefix }}registry.atmosphere.dev/library/ironic:{{ atmosphere_release }}"
   ironic_db_sync: "{{ atmosphere_image_prefix }}registry.atmosphere.dev/library/ironic:{{ atmosphere_release }}"