Support Nginx upstream-vhost annotation

This commit is contained in:
Nándor Kollár
2025-12-17 16:42:04 +01:00
committed by GitHub
parent 4854dee208
commit 704f69272c
5 changed files with 94 additions and 1 deletions
@@ -292,6 +292,7 @@ The following annotations are organized by category for easier navigation.
| <a id="opt-nginx-ingress-kubernetes-ioload-balance" href="#opt-nginx-ingress-kubernetes-ioload-balance" title="#opt-nginx-ingress-kubernetes-ioload-balance">`nginx.ingress.kubernetes.io/load-balance`</a> | Only round_robin supported; ewma and IP hash not supported. |
| <a id="opt-nginx-ingress-kubernetes-iobackend-protocol" href="#opt-nginx-ingress-kubernetes-iobackend-protocol" title="#opt-nginx-ingress-kubernetes-iobackend-protocol">`nginx.ingress.kubernetes.io/backend-protocol`</a> | FCGI and AUTO_HTTP not supported. |
| <a id="opt-nginx-ingress-kubernetes-ioservice-upstream" href="#opt-nginx-ingress-kubernetes-ioservice-upstream" title="#opt-nginx-ingress-kubernetes-ioservice-upstream">`nginx.ingress.kubernetes.io/service-upstream`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioupstream-vhost" href="#opt-nginx-ingress-kubernetes-ioupstream-vhost" title="#opt-nginx-ingress-kubernetes-ioupstream-vhost">`nginx.ingress.kubernetes.io/upstream-vhost`</a> | |
### CORS
@@ -420,7 +421,6 @@ The following annotations are organized by category for easier navigation.
| <a id="opt-nginx-ingress-kubernetes-iomirror-host" href="#opt-nginx-ingress-kubernetes-iomirror-host" title="#opt-nginx-ingress-kubernetes-iomirror-host">`nginx.ingress.kubernetes.io/mirror-host`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iox-forwarded-prefix" href="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix" title="#opt-nginx-ingress-kubernetes-iox-forwarded-prefix">`nginx.ingress.kubernetes.io/x-forwarded-prefix`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioupstream-hash-by" href="#opt-nginx-ingress-kubernetes-ioupstream-hash-by" title="#opt-nginx-ingress-kubernetes-ioupstream-hash-by">`nginx.ingress.kubernetes.io/upstream-hash-by`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioupstream-vhost" href="#opt-nginx-ingress-kubernetes-ioupstream-vhost" title="#opt-nginx-ingress-kubernetes-ioupstream-vhost">`nginx.ingress.kubernetes.io/upstream-vhost`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iodenylist-source-range" href="#opt-nginx-ingress-kubernetes-iodenylist-source-range" title="#opt-nginx-ingress-kubernetes-iodenylist-source-range">`nginx.ingress.kubernetes.io/denylist-source-range`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iowhitelist-source-range" href="#opt-nginx-ingress-kubernetes-iowhitelist-source-range" title="#opt-nginx-ingress-kubernetes-iowhitelist-source-range">`nginx.ingress.kubernetes.io/whitelist-source-range`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioproxy-buffering" href="#opt-nginx-ingress-kubernetes-ioproxy-buffering" title="#opt-nginx-ingress-kubernetes-ioproxy-buffering">`nginx.ingress.kubernetes.io/proxy-buffering`</a> | |
@@ -49,6 +49,8 @@ type ingressConfig struct {
CORSAllowMethods *[]string `annotation:"nginx.ingress.kubernetes.io/cors-allow-methods"`
CORSAllowOrigin *[]string `annotation:"nginx.ingress.kubernetes.io/cors-allow-origin"`
CORSMaxAge *int `annotation:"nginx.ingress.kubernetes.io/cors-max-age"`
UpstreamVhost *string `annotation:"nginx.ingress.kubernetes.io/upstream-vhost"`
}
// parseIngressConfig parses the annotations from an Ingress object into an ingressConfig struct.
@@ -0,0 +1,22 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-with-upstream-vhost
namespace: default
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: "upstream-host-header-value"
spec:
ingressClassName: nginx
rules:
- host: upstream-vhost.localhost
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: whoami
port:
number: 80
@@ -800,6 +800,8 @@ func (p *Provider) applyMiddlewares(namespace, routerKey string, ingressConfig i
// TODO: check how to remove this, and create the HTTP router elsewhere.
applySSLRedirectConfiguration(routerKey, ingressConfig, hasTLS, rt, conf)
applyUpstreamVhost(routerKey, ingressConfig, rt, conf)
return nil
}
@@ -934,6 +936,21 @@ func applyCORSConfiguration(routerName string, ingressConfig ingressConfig, rt *
rt.Middlewares = append(rt.Middlewares, corsMiddlewareName)
}
func applyUpstreamVhost(routerName string, ingressConfig ingressConfig, rt *dynamic.Router, conf *dynamic.Configuration) {
if ingressConfig.UpstreamVhost == nil {
return
}
vHostMiddlewareName := routerName + "-vhost"
conf.HTTP.Middlewares[vHostMiddlewareName] = &dynamic.Middleware{
Headers: &dynamic.Headers{
CustomRequestHeaders: map[string]string{"Host": *ingressConfig.UpstreamVhost},
},
}
rt.Middlewares = append(rt.Middlewares, vHostMiddlewareName)
}
func applySSLRedirectConfiguration(routerName string, ingressConfig ingressConfig, hasTLS bool, rt *dynamic.Router, conf *dynamic.Configuration) {
var forceSSLRedirect bool
if ingressConfig.ForceSSLRedirect != nil {
@@ -504,6 +504,58 @@ func TestLoadIngresses(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Upstream vhost",
paths: []string{
"services.yml",
"ingressclasses.yml",
"ingresses/10-ingress-with-upstream-vhost.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-upstream-vhost-rule-0-path-0": {
Rule: "Host(`upstream-vhost.localhost`) && Path(`/`)",
RuleSyntax: "default",
Middlewares: []string{"default-ingress-with-upstream-vhost-rule-0-path-0-vhost"},
Service: "default-whoami-80",
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-ingress-with-upstream-vhost-rule-0-path-0-vhost": {
Headers: &dynamic.Headers{
CustomRequestHeaders: map[string]string{"Host": "upstream-host-header-value"},
},
},
},
Services: map[string]*dynamic.Service{
"default-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",