Repository: traefik/traefik (language: go)

Issue:
Ingressclasses not available on namespace scope level
Hi traefik community,

After upgrading of k8s cluster to  **v1.18+**  we get the following error during startup of traefik **v2.3+**

`E0107` 06:45:40.895430       1 reflector.go:178] pkg/mod/k8s.io/client-go@v0.18.2/tools/cache/reflector.go:125: Failed to list *v1beta1.IngressClass: ingressclasses.networking.k8s.io is forbidden: User "system:serviceaccount:traefik:traefik" cannot list resource "ingressclasses" in API group "networking.k8s.io" at the cluster scope`

**The problem:**
Within k8s v1.18+ the "IngressClass" was introduced to avoid bad annotations on "Ingress" resource objects themselves (see [here)](https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/) . However,  the idea of that concept is pretty cool but lacks in implementation because it requires access on cluster scope level. Hence, developers or teams which can only work on namespace scope cannot use traefik ingress > 2.3.x on gke > 1.18.x.

**Possible solutions could be:**

- Introduce a configuration switch to disable the listing/ usage of ingressclasses during startup of traefik  v2.3+
OR
- Raise this issue to k8s community so that they can work on the cluster scope issue of "ingressclasses" on k8s v1.18+. In my opinion it must be possible to define ingressclasses also on namespace scope.


**Temporary Solution** 

Currently we downgraded our traefik to **v2.2.11** where lisitng of "ingressclasses" is not implemented and treafik starts up correctly also on gke 1.18+





Discussion / hints:
Having the same issue when trying to run the latest Helm chart using namespaced deployment.
Just ran into the same issue, running Kubernetes 1.19.3.

Downgrading Traefik for now.

Note: 2.3.7 is working for me, whereas the 2.4.0 upgrade breaks it, there was no need for me to downgrade all the way to v2.2.11 per @bschoenbach's comment
Hello, any update on this issue?

We are unable to patch Traefik for security releases until this is resolved.

Thank you,
Also experiencing this issue on Kubernetes 1.19.7 with Traefik 2.3.3.

Possibly related issue posted [on Stack Overflow](https://stackoverflow.com/q/63109422/6651) but the suggested fix was already in the helm chart.
Hello @bschoenbach @nustiueudinastea @joeldeteves @alexangas,

Thanks for your interest in Traefik!

This error can happen because Traefik, as a Kubernetes client, has no rights to fetch resources.
As mentioned in the [migration guide](https://doc.traefik.io/traefik/v2.4/migration/v2/#ingressclass), when updating to Traefik v2.3+, the support of IngressClasses makes necessary to update the RBACs.

Can you please check that your RBACs granted to Traefik contains:
```
- apiGroups:
      - extensions
      - networking.k8s.io
    resources:
      - ingresses
      - ingressclasses
    verbs:
      - get
      - list
      - watch
```

More generally you can find up-to-date RBACs in the documentation in the [dynamic-configuration reference](https://doc.traefik.io/traefik/v2.4/reference/dynamic-configuration/kubernetes-crd/#rbac) for Kubernetes CRD provider page.
> Hello @bschoenbach @nustiueudinastea @joeldeteves @alexangas,
> 
> Thanks for your interest in Traefik!
> 
> This error can happen because Traefik, as a Kubernetes client, has no rights to fetch resources.
> As mentioned in the [migration guide](https://doc.traefik.io/traefik/v2.4/migration/v2/#ingressclass), when updating to Traefik v2.3+, the support of IngressClasses makes necessary to update the RBACs.
> 
> Can you please check that your RBACs granted to Traefik contains:
> 
> ```
> - apiGroups:
>       - extensions
>       - networking.k8s.io
>     resources:
>       - ingresses
>       - ingressclasses
>     verbs:
>       - get
>       - list
>       - watch
> ```
> 
> More generally you can find up-to-date RBACs in the documentation in the [dynamic-configuration reference](https://doc.traefik.io/traefik/v2.4/reference/dynamic-configuration/kubernetes-crd/#rbac) for Kubernetes CRD provider page.

Thank you, I see the documentation was recently updated to reflect this change: https://doc.traefik.io/traefik/migration/v2/

Note: I also had to add the following to my CRD:
```
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: serverstransports.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: ServersTransport
    plural: serverstransports
    singular: serverstransport
  scope: Namespaced
```

This worked for me, I believe this issue can be closed
Unfortunately I'm still experiencing this issue.

First thing to say is that I'm using the traefik-helm-chart and am increasingly wondering if the issue lies there, specifically this one already logged: https://github.com/traefik/traefik-helm-chart/issues/358. The RBACs for ClusterRole that @rtribotte points to when setting namespaced = false are in the chart, but it does not contain them for Role which is used when namespaced = true. I tried adding them and still had the same error. Happy for this issue to be closed if the problem is the chart.

By the way, I tried updating to the Traefik 2.4.6 version of the chart and found the CRD missing that @joeldeteves provided (thanks!).
> Unfortunately I'm still experiencing this issue.
> 
> First thing to say is that I'm using the traefik-helm-chart and am increasingly wondering if the issue lies there, specifically this one already logged: [traefik/traefik-helm-chart#358](https://github.com/traefik/traefik-helm-chart/issues/358). The RBACs for ClusterRole that @rtribotte points to when setting namespaced = false are in the chart, but it does not contain them for Role which is used when namespaced = true. I tried adding them and still had the same error. Happy for this issue to be closed if the problem is the chart.
> 
> By the way, I tried updating to the Traefik 2.4.6 version of the chart and found the CRD missing that @joeldeteves provided (thanks!).

<strike>That does seem to be a separate issue with the helm chart. I will add my commentary there.</strike>

EDIT: I spoke to soon. After I looked at that error I saw it was the exact issue described by @bschoenbach:

> **The problem:**
> Within k8s v1.18+ the "IngressClass" was introduced to avoid bad annotations on "Ingress" resource objects themselves (see [here)](https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/) . However, the idea of that concept is pretty cool but lacks in implementation because it requires access on cluster scope level. Hence, developers or teams which can only work on namespace scope cannot use traefik ingress > 2.3.x on gke > 1.18.x.

Therefore this issue remains for users who use Traefik at the Namespaced level :(


Sorry guys, i was a little bit backed up by other k8s topics. However, Yes this issue remains for users on namespace scope. I raised this issue to the community themselves because the root-cause is placed within "ingressclasses" resource of k8s >= 1.18. See the issue below:

https://github.com/kubernetes/kubernetes/issues/99824

In the meantime I tried several other ingress-controllers (nginx etc.). The problem occurs, too.
Hi! I'm Træfiker :robot: the bot in charge of tidying up the issues.

I have to close this one because of its lack of activity :disappointed:

Feel free to re-open it or join our [Community Forum](https://community.containo.us/).
  
Hello, we are too stuck using v2.2.X versions of traefik for namespaced deployments - has there been any effort to add a flag to the controller to disable the use of `ingressClass` resources in namespaced mode?
Hello @joeldeteves @bschoenbach @YitzyD,

Traefik started to support the Kubernetes `IngressClass` resources in [v2.3.0](https://github.com/traefik/traefik/releases/tag/v2.3.0).

Thus, while this is the preferred way to scope the Ingress provider `ingresses` discovery process, it is still possible to rely on annotations.

For any Traefik upgrade in a Kubernetes cluster, the necessary actions to take are (depending on the provider):
- [Kubernetes Ingress](https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/) provider: update [RBACs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#rbac)
- [Kubernetes IngressRoute](https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/) provider: update [RBACs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#rbac) and [CRDs](https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions)

The reason is that without the appropriate rights needed to look up for resources in the cluster, nor the definitions of those resources (Kubernetes IngressRoute CRDs), Traefik will fail to start the providers.

In case one is using [Traefik HelmChart](https://github.com/traefik/traefik-helm-chart), upgrading it to the version supporting the targeted Traefik version should work.

Regarding the use of `ingressClass` in namespace mode, this is not supported because the `ingressClass` resource is by definition a cluster scoped resource.
Thus, as previously said, this is not mandatory to use an `ingressClass` resource with the 
[Kubernetes Ingress](https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/) provider.

Therefore, as this issue turned out to be a configuration issue, and as we think we addressed all the questions, we are going close this issue.
Feel free to reopen if you think we missed something.
Hi,

Problem still remains. As long as traefik controller scrapes for ingressClass resources during startup the proposed solution (updating RBACs etc) does not work on namespace scope. As mentioned by @YitzyD implementation of a dedicated configuration switch is still necessary to avoid scraping ingressClass resources (i.e. listing of all ingressClass objects via kube api during startup procedure within traefik) when using old annotation scheme with kubernetes ingress provider instead of ingressClass.

@rtribotte please re-open to keep discussion ongoing
Hello @bschoenbach,

Thanks for your feedback.

I understand that you are requesting an option to disable the ingressClass feature globally.

Nonetheless, would defining a cluster role with only rights to discover ingressClasses for Traefik be an acceptable/sufficient solution? What would be the downside of that?

I'm reopening the issue to discuss further the proposal to solve that use case.
Hi @rtribotte 

> Nonetheless, would defining a cluster role with only rights to discover ingressClasses for Traefik be an acceptable/sufficient solution? What would be the downside of that?

Unfortunately not, we (our company) work on namespace scope only. This means we are not authorized to create cluster roles/rolebindings. For sure we could ask our k8s system administrators to do so but this will the end up to work directly on cluster scope level. Besides, this would be a global setting for the whole cluster (valid for all namespaces). Hence, a dedicated configuration switch to disable ingressClass scraping would be very helpful for the namespace scope.



Thanks for the explanation, we think it makes sense and we are then labeling the issue as an enhancement.

Unfortunately, this would not make it to our roadmap for a while as we are focused elsewhere.  If you or another community member would like to build it, let us know and we will work with you to make sure you have all the information needed so that it can be merged.
I agree with the necessity. Especially with the namespace "scope" becoming GA in Ingress Classes in 1.23, but without dedicated namespaced rbac, a flag to disable listing the clusterscoped Ingress Class in the controller is required for backwards compatability. 
If namespaced rbac is added for Ingress Classes in the future that would be the best solution but does not seem to be planned.

Fix patch:
diff --git a/docs/content/providers/kubernetes-ingress.md b/docs/content/providers/kubernetes-ingress.md
index a35017cc5d..4d915a596e 100644
--- a/docs/content/providers/kubernetes-ingress.md
+++ b/docs/content/providers/kubernetes-ingress.md
@@ -344,6 +344,35 @@ providers:
 --providers.kubernetesingress.ingressclass=traefik-internal
 ```
 
+### `disableIngressClassLookup`
+
+_Optional, Default: false_
+
+If the parameter is set to `true`,
+Traefik will not discover IngressClasses in the cluster.
+By doing so, it alleviates the requirement of giving Traefik the rights to look IngressClasses up.
+Furthermore, when this option is set to `true`,
+Traefik is not able to handle Ingresses with IngressClass references,
+therefore such Ingresses will be ignored.
+Please note that annotations are not affected by this option.
+
+```yaml tab="File (YAML)"
+providers:
+  kubernetesIngress:
+    disableIngressClassLookup: true
+    # ...
+```
+
+```toml tab="File (TOML)"
+[providers.kubernetesIngress]
+  disableIngressClassLookup = true
+  # ...
+```
+
+```bash tab="CLI"
+--providers.kubernetesingress.disableingressclasslookup=true
+```
+
 ### `ingressEndpoint`
 
 #### `hostname`
diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md
index 00bb3af7fc..fa5c9759f6 100644
--- a/docs/content/reference/static-configuration/cli-ref.md
+++ b/docs/content/reference/static-configuration/cli-ref.md
@@ -735,6 +735,9 @@ Allow ExternalName services. (Default: ```false```)
 `--providers.kubernetesingress.certauthfilepath`:  
 Kubernetes certificate authority file path (not needed for in-cluster client).
 
+`--providers.kubernetesingress.disableingressclasslookup`:  
+Disables the lookup of IngressClasses. (Default: ```false```)
+
 `--providers.kubernetesingress.endpoint`:  
 Kubernetes server endpoint (required for external cluster client).
 
diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md
index b6a7429a8a..4a951b4620 100644
--- a/docs/content/reference/static-configuration/env-ref.md
+++ b/docs/content/reference/static-configuration/env-ref.md
@@ -735,6 +735,9 @@ Allow ExternalName services. (Default: ```false```)
 `TRAEFIK_PROVIDERS_KUBERNETESINGRESS_CERTAUTHFILEPATH`:  
 Kubernetes certificate authority file path (not needed for in-cluster client).
 
+`TRAEFIK_PROVIDERS_KUBERNETESINGRESS_DISABLEINGRESSCLASSLOOKUP`:  
+Disables the lookup of IngressClasses. (Default: ```false```)
+
 `TRAEFIK_PROVIDERS_KUBERNETESINGRESS_ENDPOINT`:  
 Kubernetes server endpoint (required for external cluster client).
 
diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml
index 29ccadce71..8bff3f0a22 100644
--- a/docs/content/reference/static-configuration/file.toml
+++ b/docs/content/reference/static-configuration/file.toml
@@ -108,6 +108,7 @@
     throttleDuration = "42s"
     allowEmptyServices = true
     allowExternalNameServices = true
+    disableIngressClassLookup = true
     [providers.kubernetesIngress.ingressEndpoint]
       ip = "foobar"
       hostname = "foobar"
diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml
index 10284c874f..e6b1006322 100644
--- a/docs/content/reference/static-configuration/file.yaml
+++ b/docs/content/reference/static-configuration/file.yaml
@@ -117,6 +117,7 @@ providers:
     throttleDuration: 42s
     allowEmptyServices: true
     allowExternalNameServices: true
+    disableIngressClassLookup: true
     ingressEndpoint:
       ip: foobar
       hostname: foobar
diff --git a/integration/fixtures/k8s_ingressclass_disabled.toml b/integration/fixtures/k8s_ingressclass_disabled.toml
new file mode 100644
index 0000000000..8afc19e971
--- /dev/null
+++ b/integration/fixtures/k8s_ingressclass_disabled.toml
@@ -0,0 +1,18 @@
+[global]
+  checkNewVersion = false
+  sendAnonymousUsage = false
+
+[log]
+  level = "DEBUG"
+  noColor = true
+
+[api]
+  insecure = true
+
+[entryPoints]
+  [entryPoints.web]
+    address = ":8000"
+
+[providers.kubernetesIngress]
+  ingressClass = "traefik-keep"
+  disableIngressClassLookup = true
diff --git a/pkg/provider/kubernetes/ingress/client.go b/pkg/provider/kubernetes/ingress/client.go
index eccd396571..2ac4867246 100644
--- a/pkg/provider/kubernetes/ingress/client.go
+++ b/pkg/provider/kubernetes/ingress/client.go
@@ -50,15 +50,16 @@ type Client interface {
 }
 
 type clientWrapper struct {
-	clientset            kubernetes.Interface
-	factoriesKube        map[string]informers.SharedInformerFactory
-	factoriesSecret      map[string]informers.SharedInformerFactory
-	factoriesIngress     map[string]informers.SharedInformerFactory
-	clusterFactory       informers.SharedInformerFactory
-	ingressLabelSelector string
-	isNamespaceAll       bool
-	watchedNamespaces    []string
-	serverVersion        *version.Version
+	clientset                   kubernetes.Interface
+	factoriesKube               map[string]informers.SharedInformerFactory
+	factoriesSecret             map[string]informers.SharedInformerFactory
+	factoriesIngress            map[string]informers.SharedInformerFactory
+	clusterFactory              informers.SharedInformerFactory
+	ingressLabelSelector        string
+	isNamespaceAll              bool
+	disableIngressClassInformer bool
+	watchedNamespaces           []string
+	serverVersion               *version.Version
 }
 
 // newInClusterClient returns a new Provider client that is expected to run
@@ -214,7 +215,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
 		}
 	}
 
-	if supportsIngressClass(serverVersion) {
+	if !c.disableIngressClassInformer && supportsIngressClass(serverVersion) {
 		c.clusterFactory = informers.NewSharedInformerFactoryWithOptions(c.clientset, resyncPeriod)
 
 		if supportsNetworkingV1Ingress(serverVersion) {
diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go
index 95a71c12d6..54a4be3953 100644
--- a/pkg/provider/kubernetes/ingress/kubernetes.go
+++ b/pkg/provider/kubernetes/ingress/kubernetes.go
@@ -48,6 +48,7 @@ type Provider struct {
 	ThrottleDuration          ptypes.Duration  `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
 	AllowEmptyServices        bool             `description:"Allow creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"`
 	AllowExternalNameServices bool             `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"`
+	DisableIngressClassLookup bool             `description:"Disables the lookup of IngressClasses." json:"disableIngressClassLookup,omitempty" toml:"disableIngressClassLookup,omitempty" yaml:"disableIngressClassLookup,omitempty" export:"true"`
 	lastConfiguration         safe.Safe
 }
 
@@ -91,6 +92,7 @@ func (p *Provider) newK8sClient(ctx context.Context) (*clientWrapper, error) {
 	}
 
 	cl.ingressLabelSelector = p.LabelSelector
+	cl.disableIngressClassInformer = p.DisableIngressClassLookup
 	return cl, nil
 }
 
@@ -195,7 +197,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
 
 	var ingressClasses []*networkingv1.IngressClass
 
-	if supportsIngressClass(serverVersion) {
+	if !p.DisableIngressClassLookup && supportsIngressClass(serverVersion) {
 		ics, err := client.GetIngressClasses()
 		if err != nil {
 			log.Ctx(ctx).Warn().Err(err).Msg("Failed to list ingress classes")


Test patch:
diff --git a/integration/k8s_test.go b/integration/k8s_test.go
index bfb73d93cc..13c64a2e0c 100644
--- a/integration/k8s_test.go
+++ b/integration/k8s_test.go
@@ -128,6 +128,17 @@ func (s *K8sSuite) TestIngressclass(c *check.C) {
 	testConfiguration(c, "testdata/rawdata-ingressclass.json", "8080")
 }
 
+func (s *K8sSuite) TestDisableIngressclassLookup(c *check.C) {
+	cmd, display := s.traefikCmd(withConfigFile("fixtures/k8s_ingressclass_disabled.toml"))
+	defer display(c)
+
+	err := cmd.Start()
+	c.Assert(err, checker.IsNil)
+	defer s.killCmd(cmd)
+
+	testConfiguration(c, "testdata/rawdata-ingressclass-disabled.json", "8080")
+}
+
 func testConfiguration(c *check.C, path, apiPort string) {
 	err := try.GetRequest("http://127.0.0.1:"+apiPort+"/api/entrypoints", 20*time.Second, try.BodyContains(`"name":"web"`))
 	c.Assert(err, checker.IsNil)
diff --git a/integration/testdata/rawdata-ingressclass-disabled.json b/integration/testdata/rawdata-ingressclass-disabled.json
new file mode 100644
index 0000000000..14649419c6
--- /dev/null
+++ b/integration/testdata/rawdata-ingressclass-disabled.json
@@ -0,0 +1,74 @@
+{
+	"routers": {
+		"api@internal": {
+			"entryPoints": [
+				"traefik"
+			],
+			"service": "api@internal",
+			"rule": "PathPrefix(`/api`)",
+			"priority": 2147483646,
+			"status": "enabled",
+			"using": [
+				"traefik"
+			]
+		},
+		"dashboard@internal": {
+			"entryPoints": [
+				"traefik"
+			],
+			"middlewares": [
+				"dashboard_redirect@internal",
+				"dashboard_stripprefix@internal"
+			],
+			"service": "dashboard@internal",
+			"rule": "PathPrefix(`/`)",
+			"priority": 2147483645,
+			"status": "enabled",
+			"using": [
+				"traefik"
+			]
+		}
+	},
+	"middlewares": {
+		"dashboard_redirect@internal": {
+			"redirectRegex": {
+				"regex": "^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$",
+				"replacement": "${1}/dashboard/",
+				"permanent": true
+			},
+			"status": "enabled",
+			"usedBy": [
+				"dashboard@internal"
+			]
+		},
+		"dashboard_stripprefix@internal": {
+			"stripPrefix": {
+				"prefixes": [
+					"/dashboard/",
+					"/dashboard"
+				]
+			},
+			"status": "enabled",
+			"usedBy": [
+				"dashboard@internal"
+			]
+		}
+	},
+	"services": {
+		"api@internal": {
+			"status": "enabled",
+			"usedBy": [
+				"api@internal"
+			]
+		},
+		"dashboard@internal": {
+			"status": "enabled",
+			"usedBy": [
+				"dashboard@internal"
+			]
+		},
+		"noop@internal": {
+			"status": "enabled"
+		}
+	}
+}
\ No newline at end of file
diff --git a/pkg/provider/kubernetes/ingress/kubernetes_test.go b/pkg/provider/kubernetes/ingress/kubernetes_test.go
index 3b032f9961..3c21f15192 100644
--- a/pkg/provider/kubernetes/ingress/kubernetes_test.go
+++ b/pkg/provider/kubernetes/ingress/kubernetes_test.go
@@ -26,11 +26,12 @@ func Bool(v bool) *bool { return &v }
 
 func TestLoadConfigurationFromIngresses(t *testing.T) {
 	testCases := []struct {
-		desc               string
-		ingressClass       string
-		serverVersion      string
-		expected           *dynamic.Configuration
-		allowEmptyServices bool
+		desc                      string
+		ingressClass              string
+		serverVersion             string
+		expected                  *dynamic.Configuration
+		allowEmptyServices        bool
+		disableIngressClassLookup bool
 	}{
 		{
 			desc: "Empty ingresses",
@@ -1392,6 +1393,40 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
 				},
 			},
 		},
+		{
+			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
+			// Showing that disabling the ingressClass discovery still allow the discovery of ingresses with ingress annotation.
+			desc:                      "v18 Ingress with ingress annotation",
+			serverVersion:             "v1.18",
+			disableIngressClassLookup: true,
+			expected: &dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{},
+				HTTP: &dynamic.HTTPConfiguration{
+					Middlewares: map[string]*dynamic.Middleware{},
+					Routers: map[string]*dynamic.Router{
+						"testing-bar": {
+							Rule:    "PathPrefix(`/bar`)",
+							Service: "testing-service1-80",
+						},
+					},
+					Services: map[string]*dynamic.Service{
+						"testing-service1-80": {
+							LoadBalancer: &dynamic.ServersLoadBalancer{
+								PassHostHeader: Bool(true),
+								ResponseForwarding: &dynamic.ResponseForwarding{
+									FlushInterval: ptypes.Duration(100 * time.Millisecond),
+								},
+								Servers: []dynamic.Server{
+									{
+										URL: "http://10.10.0.1:8080",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			desc:          "v18 Ingress with ingressClasses filter",
 			serverVersion: "v1.18",
@@ -1424,6 +1459,22 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
 				},
 			},
 		},
+		{
+			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
+			// Showing that disabling the ingressClass discovery avoid discovering Ingresses with an IngressClass.
+			desc:                      "v18 Ingress with ingressClasses filter",
+			serverVersion:             "v1.18",
+			ingressClass:              "traefik-lb2",
+			disableIngressClassLookup: true,
+			expected: &dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{},
+				HTTP: &dynamic.HTTPConfiguration{
+					Middlewares: map[string]*dynamic.Middleware{},
+					Routers:     map[string]*dynamic.Router{},
+					Services:    map[string]*dynamic.Service{},
+				},
+			},
+		},
 		{
 			desc:          "v19 Ingress with prefix pathType",
 			serverVersion: "v1.19",
@@ -1610,6 +1661,39 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
 				},
 			},
 		},
+		{
+			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
+			// Showing that disabling the ingressClass discovery still allow the discovery of ingresses with ingress annotation.
+			desc:          "v19 Ingress with ingress annotation",
+			serverVersion: "v1.19",
+			expected: &dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{},
+				HTTP: &dynamic.HTTPConfiguration{
+					Middlewares: map[string]*dynamic.Middleware{},
+					Routers: map[string]*dynamic.Router{
+						"testing-bar": {
+							Rule:    "PathPrefix(`/bar`)",
+							Service: "testing-service1-80",
+						},
+					},
+					Services: map[string]*dynamic.Service{
+						"testing-service1-80": {
+							LoadBalancer: &dynamic.ServersLoadBalancer{
+								PassHostHeader: Bool(true),
+								ResponseForwarding: &dynamic.ResponseForwarding{
+									FlushInterval: ptypes.Duration(100 * time.Millisecond),
+								},
+								Servers: []dynamic.Server{
+									{
+										URL: "http://10.10.0.1:8080",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			desc:          "v19 Ingress with ingressClass",
 			serverVersion: "v1.19",
@@ -1641,6 +1725,21 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
 				},
 			},
 		},
+		{
+			// Duplicate test case with the same fixture as the one above, but with the disableIngressClassLookup option to true.
+			// Showing that disabling the ingressClass discovery avoid discovering Ingresses with an IngressClass.
+			desc:                      "v19 Ingress with ingressClass",
+			disableIngressClassLookup: true,
+			serverVersion:             "v1.19",
+			expected: &dynamic.Configuration{
+				TCP: &dynamic.TCPConfiguration{},
+				HTTP: &dynamic.HTTPConfiguration{
+					Middlewares: map[string]*dynamic.Middleware{},
+					Routers:     map[string]*dynamic.Router{},
+					Services:    map[string]*dynamic.Service{},
+				},
+			},
+		},
 		{
 			desc:          "v19 Ingress with ingressClassv1",
 			serverVersion: "v1.19",
@@ -1783,7 +1882,11 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
 			}
 
 			clientMock := newClientMock(serverVersion, paths...)
-			p := Provider{IngressClass: test.ingressClass, AllowEmptyServices: test.allowEmptyServices}
+			p := Provider{
+				IngressClass:              test.ingressClass,
+				AllowEmptyServices:        test.allowEmptyServices,
+				DisableIngressClassLookup: test.disableIngressClassLookup,
+			}
 			conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
 
 			assert.Equal(t, test.expected, conf)