mirror of
https://github.com/traefik/traefik
synced 2026-02-03 08:50:32 +00:00
Add rewrite-target nginx annotations support
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
@@ -316,6 +316,7 @@ The following annotations are organized by category for easier navigation.
|
||||
| Annotation | Limitations / Notes |
|
||||
|-------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
| <a id="opt-nginx-ingress-kubernetes-iouse-regex" href="#opt-nginx-ingress-kubernetes-iouse-regex" title="#opt-nginx-ingress-kubernetes-iouse-regex">`nginx.ingress.kubernetes.io/use-regex`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iorewrite-target" href="#opt-nginx-ingress-kubernetes-iorewrite-target" title="#opt-nginx-ingress-kubernetes-iorewrite-target">`nginx.ingress.kubernetes.io/rewrite-target`</a> | |
|
||||
|
||||
### IP Whitelist
|
||||
|
||||
@@ -411,7 +412,6 @@ The following annotations are organized by category for easier navigation.
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-verify-depth">`nginx.ingress.kubernetes.io/proxy-ssl-verify-depth`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" href="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols" title="#opt-nginx-ingress-kubernetes-ioproxy-ssl-protocols">`nginx.ingress.kubernetes.io/proxy-ssl-protocols`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioenable-rewrite-log" href="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log" title="#opt-nginx-ingress-kubernetes-ioenable-rewrite-log">`nginx.ingress.kubernetes.io/enable-rewrite-log`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iorewrite-target" href="#opt-nginx-ingress-kubernetes-iorewrite-target" title="#opt-nginx-ingress-kubernetes-iorewrite-target">`nginx.ingress.kubernetes.io/rewrite-target`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-iosatisfy" href="#opt-nginx-ingress-kubernetes-iosatisfy" title="#opt-nginx-ingress-kubernetes-iosatisfy">`nginx.ingress.kubernetes.io/satisfy`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-alias" href="#opt-nginx-ingress-kubernetes-ioserver-alias" title="#opt-nginx-ingress-kubernetes-ioserver-alias">`nginx.ingress.kubernetes.io/server-alias`</a> | |
|
||||
| <a id="opt-nginx-ingress-kubernetes-ioserver-snippet" href="#opt-nginx-ingress-kubernetes-ioserver-snippet" title="#opt-nginx-ingress-kubernetes-ioserver-snippet">`nginx.ingress.kubernetes.io/server-snippet`</a> | |
|
||||
|
||||
@@ -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"`
|
||||
|
||||
+23
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user