diff --git a/docs/content/reference/routing-configuration/kubernetes/ingress-nginx.md b/docs/content/reference/routing-configuration/kubernetes/ingress-nginx.md
index 412cdb5e5..31a11d6e6 100644
--- a/docs/content/reference/routing-configuration/kubernetes/ingress-nginx.md
+++ b/docs/content/reference/routing-configuration/kubernetes/ingress-nginx.md
@@ -316,6 +316,7 @@ The following annotations are organized by category for easier navigation.
| Annotation | Limitations / Notes |
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
| `nginx.ingress.kubernetes.io/use-regex` | |
+| `nginx.ingress.kubernetes.io/rewrite-target` | |
### IP Whitelist
@@ -411,7 +412,6 @@ The following annotations are organized by category for easier navigation.
| `nginx.ingress.kubernetes.io/proxy-ssl-verify-depth` | |
| `nginx.ingress.kubernetes.io/proxy-ssl-protocols` | |
| `nginx.ingress.kubernetes.io/enable-rewrite-log` | |
-| `nginx.ingress.kubernetes.io/rewrite-target` | |
| `nginx.ingress.kubernetes.io/satisfy` | |
| `nginx.ingress.kubernetes.io/server-alias` | |
| `nginx.ingress.kubernetes.io/server-snippet` | |
diff --git a/pkg/provider/kubernetes/ingress-nginx/annotations.go b/pkg/provider/kubernetes/ingress-nginx/annotations.go
index 06edd65d9..60401399f 100644
--- a/pkg/provider/kubernetes/ingress-nginx/annotations.go
+++ b/pkg/provider/kubernetes/ingress-nginx/annotations.go
@@ -23,7 +23,8 @@ type ingressConfig struct {
SSLPassthrough *bool `annotation:"nginx.ingress.kubernetes.io/ssl-passthrough"`
- UseRegex *bool `annotation:"nginx.ingress.kubernetes.io/use-regex"`
+ UseRegex *bool `annotation:"nginx.ingress.kubernetes.io/use-regex"`
+ RewriteTarget *string `annotation:"nginx.ingress.kubernetes.io/rewrite-target"`
Affinity *string `annotation:"nginx.ingress.kubernetes.io/affinity"`
SessionCookieName *string `annotation:"nginx.ingress.kubernetes.io/session-cookie-name"`
diff --git a/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/11-ingress-with-rewrite-target.yml b/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/11-ingress-with-rewrite-target.yml
new file mode 100644
index 000000000..fd94661aa
--- /dev/null
+++ b/pkg/provider/kubernetes/ingress-nginx/fixtures/ingresses/11-ingress-with-rewrite-target.yml
@@ -0,0 +1,23 @@
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: ingress-with-rewrite-target
+ namespace: default
+ annotations:
+ nginx.ingress.kubernetes.io/use-regex: "true"
+ nginx.ingress.kubernetes.io/rewrite-target: /$2
+
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: rewrite-target.localhost
+ http:
+ paths:
+ - path: /something(/|$)(.*)
+ pathType: ImplementationSpecific
+ backend:
+ service:
+ name: whoami
+ port:
+ number: 80
diff --git a/pkg/provider/kubernetes/ingress-nginx/kubernetes.go b/pkg/provider/kubernetes/ingress-nginx/kubernetes.go
index f9360fbbd..294206796 100644
--- a/pkg/provider/kubernetes/ingress-nginx/kubernetes.go
+++ b/pkg/provider/kubernetes/ingress-nginx/kubernetes.go
@@ -317,7 +317,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
Service: defaultBackendName,
}
- if err := p.applyMiddlewares(ingress.Namespace, defaultBackendName, ingressConfig, hasTLS, rt, conf); err != nil {
+ if err := p.applyMiddlewares(ingress.Namespace, defaultBackendName, "", ingressConfig, hasTLS, rt, conf); err != nil {
logger.Error().Err(err).Msg("Error applying middlewares")
}
@@ -332,7 +332,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
TLS: &dynamic.RouterTLSConfig{},
}
- if err := p.applyMiddlewares(ingress.Namespace, defaultBackendTLSName, ingressConfig, false, rtTLS, conf); err != nil {
+ if err := p.applyMiddlewares(ingress.Namespace, defaultBackendTLSName, "", ingressConfig, false, rtTLS, conf); err != nil {
logger.Error().Err(err).Msg("Error applying middlewares")
}
@@ -409,7 +409,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
Service: key,
}
- if err := p.applyMiddlewares(ingress.Namespace, key, ingressConfig, hasTLS, rt, conf); err != nil {
+ if err := p.applyMiddlewares(ingress.Namespace, key, "", ingressConfig, hasTLS, rt, conf); err != nil {
logger.Error().Err(err).Msg("Error applying middlewares")
}
@@ -423,7 +423,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
TLS: &dynamic.RouterTLSConfig{},
}
- if err := p.applyMiddlewares(ingress.Namespace, key+"-tls", ingressConfig, false, rtTLS, conf); err != nil {
+ if err := p.applyMiddlewares(ingress.Namespace, key+"-tls", "", ingressConfig, false, rtTLS, conf); err != nil {
logger.Error().Err(err).Msg("Error applying middlewares")
}
@@ -488,7 +488,7 @@ func (p *Provider) loadConfiguration(ctx context.Context) *dynamic.Configuration
conf.HTTP.ServersTransports[namedServersTransport.Name] = namedServersTransport.ServersTransport
}
- if err := p.applyMiddlewares(ingress.Namespace, routerKey, ingressConfig, hasTLS, rt, conf); err != nil {
+ if err := p.applyMiddlewares(ingress.Namespace, routerKey, pa.Path, ingressConfig, hasTLS, rt, conf); err != nil {
logger.Error().Err(err).Msg("Error applying middlewares")
}
}
@@ -788,7 +788,7 @@ func (p *Provider) loadCertificates(ctx context.Context, ingress *netv1.Ingress,
return nil
}
-func (p *Provider) applyMiddlewares(namespace, routerKey string, ingressConfig ingressConfig, hasTLS bool, rt *dynamic.Router, conf *dynamic.Configuration) error {
+func (p *Provider) applyMiddlewares(namespace, routerKey, rulePath string, ingressConfig ingressConfig, hasTLS bool, rt *dynamic.Router, conf *dynamic.Configuration) error {
if err := p.applyBasicAuthConfiguration(namespace, routerKey, ingressConfig, rt, conf); err != nil {
return fmt.Errorf("applying basic auth configuration: %w", err)
}
@@ -801,6 +801,8 @@ func (p *Provider) applyMiddlewares(namespace, routerKey string, ingressConfig i
applyCORSConfiguration(routerKey, ingressConfig, rt, conf)
+ applyRewriteTargetConfiguration(rulePath, routerKey, ingressConfig, rt, conf)
+
// Apply SSL redirect is mandatory to be applied after all other middlewares.
// TODO: check how to remove this, and create the HTTP router elsewhere.
p.applySSLRedirectConfiguration(routerKey, ingressConfig, hasTLS, rt, conf)
@@ -844,6 +846,22 @@ func (p *Provider) applyCustomHeaders(routerName string, ingressConfig ingressCo
return nil
}
+func applyRewriteTargetConfiguration(rulePath, routerName string, ingressConfig ingressConfig, rt *dynamic.Router, conf *dynamic.Configuration) {
+ if ingressConfig.RewriteTarget == nil || !ptr.Deref(ingressConfig.UseRegex, false) {
+ return
+ }
+
+ rewriteTargetMiddlewareName := routerName + "-rewrite-target"
+ conf.HTTP.Middlewares[rewriteTargetMiddlewareName] = &dynamic.Middleware{
+ ReplacePathRegex: &dynamic.ReplacePathRegex{
+ Regex: rulePath,
+ Replacement: *ingressConfig.RewriteTarget,
+ },
+ }
+
+ rt.Middlewares = append(rt.Middlewares, rewriteTargetMiddlewareName)
+}
+
func (p *Provider) applyBasicAuthConfiguration(namespace, routerName string, ingressConfig ingressConfig, rt *dynamic.Router, conf *dynamic.Configuration) error {
if ingressConfig.AuthType == nil {
return nil
diff --git a/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go b/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go
index 88383f464..115693ca9 100644
--- a/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go
+++ b/pkg/provider/kubernetes/ingress-nginx/kubernetes_test.go
@@ -754,6 +754,59 @@ func TestLoadIngresses(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
+ {
+ desc: "Rewrite Target",
+ paths: []string{
+ "services.yml",
+ "ingressclasses.yml",
+ "ingresses/11-ingress-with-rewrite-target.yml",
+ },
+ expected: &dynamic.Configuration{
+ TCP: &dynamic.TCPConfiguration{
+ Routers: map[string]*dynamic.TCPRouter{},
+ Services: map[string]*dynamic.TCPService{},
+ },
+ HTTP: &dynamic.HTTPConfiguration{
+ Routers: map[string]*dynamic.Router{
+ "default-ingress-with-rewrite-target-rule-0-path-0": {
+ Rule: "Host(`rewrite-target.localhost`) && PathRegexp(`^/something(/|$)(.*)`)",
+ RuleSyntax: "default",
+ Service: "default-ingress-with-rewrite-target-whoami-80",
+ Middlewares: []string{"default-ingress-with-rewrite-target-rule-0-path-0-rewrite-target"},
+ },
+ },
+ Middlewares: map[string]*dynamic.Middleware{
+ "default-ingress-with-rewrite-target-rule-0-path-0-rewrite-target": {
+ ReplacePathRegex: &dynamic.ReplacePathRegex{
+ Regex: "/something(/|$)(.*)",
+ Replacement: "/$2",
+ },
+ },
+ },
+ Services: map[string]*dynamic.Service{
+ "default-ingress-with-rewrite-target-whoami-80": {
+ LoadBalancer: &dynamic.ServersLoadBalancer{
+ Servers: []dynamic.Server{
+ {
+ URL: "http://10.10.0.1:80",
+ },
+ {
+ URL: "http://10.10.0.2:80",
+ },
+ },
+ Strategy: "wrr",
+ PassHostHeader: ptr.To(true),
+ ResponseForwarding: &dynamic.ResponseForwarding{
+ FlushInterval: dynamic.DefaultFlushInterval,
+ },
+ },
+ },
+ },
+ ServersTransports: map[string]*dynamic.ServersTransport{},
+ },
+ TLS: &dynamic.TLSConfiguration{},
+ },
+ },
{
desc: "Default Backend",
defaultBackendServiceName: "whoami",