From a24d65745efc757a76ef749b18a263cfb37d7f02 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Guerraz Date: Wed, 27 Sep 2017 16:10:16 +0200 Subject: [PATCH] Add support for proxy protocol decoding and encoding in TCP services --- controllers/nginx/README.md | 4 +-- .../rootfs/etc/nginx/template/nginx.tmpl | 11 +++++--- core/pkg/ingress/controller/controller.go | 25 +++++++++++-------- core/pkg/ingress/types.go | 8 +++++- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/controllers/nginx/README.md b/controllers/nginx/README.md index dabfcdc9d2..fea53c8148 100644 --- a/controllers/nginx/README.md +++ b/controllers/nginx/README.md @@ -334,8 +334,8 @@ version to fully support Kube-Lego is nginx Ingress controller 0.8. ## Exposing TCP services -Ingress does not support TCP services (yet). For this reason this Ingress controller uses the flag `--tcp-services-configmap` to point to an existing config map where the key is the external port to use and the value is `::[PROXY]` -It is possible to use a number or the name of the port. The last field is optional. Adding `PROXY` in the last field we can enable Proxy Protocol in a TCP service. +Ingress does not support TCP services (yet). For this reason this Ingress controller uses the flag `--tcp-services-configmap` to point to an existing config map where the key is the external port to use and the value is `::[PROXY]:[PROXY]` +It is possible to use a number or the name of the port. The two last fields are optional. Adding `PROXY` in either or both of the two last fields we can use Proxy Protocol decoding (listen) and/or encoding (proxy_pass) in a TCP service (https://www.nginx.com/resources/admin-guide/proxy-protocol/). The next example shows how to expose the service `example-go` running in the namespace `default` in the port `8080` using the port `9000` ``` diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index c2b933cdc9..8ff59ae989 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -434,19 +434,22 @@ stream { } server { {{ range $address := $all.Cfg.BindAddressIpv4 }} - listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }}; + listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }}; {{ else }} - listen {{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }}; + listen {{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }}; {{ end }} {{ if $IsIPV6Enabled }} {{ range $address := $all.Cfg.BindAddressIpv6 }} - listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }}; + listen {{ $address }}:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }}; {{ else }} - listen [::]:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.UseProxyProtocol }} proxy_protocol{{ end }}; + listen [::]:{{ $tcpServer.Port }}{{ if $tcpServer.Backend.ProxyProtocol.Decode }} proxy_protocol{{ end }}; {{ end }} {{ end }} proxy_timeout {{ $cfg.ProxyStreamTimeout }}; proxy_pass tcp-{{ $tcpServer.Port }}-{{ $tcpServer.Backend.Namespace }}-{{ $tcpServer.Backend.Name }}-{{ $tcpServer.Backend.Port }}; + {{ if $tcpServer.Backend.ProxyProtocol.Encode }} + proxy_protocol on; + {{ end }} } {{ end }} diff --git a/core/pkg/ingress/controller/controller.go b/core/pkg/ingress/controller/controller.go index f11192785c..01d8b8260d 100644 --- a/core/pkg/ingress/controller/controller.go +++ b/core/pkg/ingress/controller/controller.go @@ -346,6 +346,7 @@ func (ic *GenericController) getStreamServices(configmapName string, proto apiv1 } var svcs []ingress.L4Service + var svcProxyProtocol ingress.ProxyProtocol // k -> port to expose // v -> /: for k, v := range configmap.Data { @@ -363,18 +364,22 @@ func (ic *GenericController) getStreamServices(configmapName string, proto apiv1 nsSvcPort := strings.Split(v, ":") if len(nsSvcPort) < 2 { - glog.Warningf("invalid format (namespace/name:port:[PROXY]) '%v'", k) + glog.Warningf("invalid format (namespace/name:port:[PROXY]:[PROXY]) '%v'", k) continue } nsName := nsSvcPort[0] svcPort := nsSvcPort[1] - useProxyProtocol := false + svcProxyProtocol.Decode = false + svcProxyProtocol.Encode = false // Proxy protocol is possible if the service is TCP - if len(nsSvcPort) == 3 && proto == apiv1.ProtocolTCP { - if strings.ToUpper(nsSvcPort[2]) == "PROXY" { - useProxyProtocol = true + if len(nsSvcPort) >= 3 && proto == apiv1.ProtocolTCP { + if len(nsSvcPort) >= 3 && strings.ToUpper(nsSvcPort[2]) == "PROXY" { + svcProxyProtocol.Decode = true + } + if len(nsSvcPort) == 4 && strings.ToUpper(nsSvcPort[3]) == "PROXY" { + svcProxyProtocol.Encode = true } } @@ -432,11 +437,11 @@ func (ic *GenericController) getStreamServices(configmapName string, proto apiv1 svcs = append(svcs, ingress.L4Service{ Port: externalPort, Backend: ingress.L4Backend{ - Name: svcName, - Namespace: svcNs, - Port: intstr.FromString(svcPort), - Protocol: proto, - UseProxyProtocol: useProxyProtocol, + Name: svcName, + Namespace: svcNs, + Port: intstr.FromString(svcPort), + Protocol: proto, + ProxyProtocol: svcProxyProtocol, }, Endpoints: endps, }) diff --git a/core/pkg/ingress/types.go b/core/pkg/ingress/types.go index a24ed5c5b3..1a328d6473 100644 --- a/core/pkg/ingress/types.go +++ b/core/pkg/ingress/types.go @@ -359,5 +359,11 @@ type L4Backend struct { Namespace string `json:"namespace"` Protocol apiv1.Protocol `json:"protocol"` // +optional - UseProxyProtocol bool `json:"useProxyProtocol"` + ProxyProtocol ProxyProtocol `json:"proxyProtocol"` +} + +// ProxyProtocol describes the proxy protocol configuration +type ProxyProtocol struct { + Decode bool `json:"decode"` + Encode bool `json:"encode"` }