From d56d8b7da1a7683dae6e4603121c2d5a2fb08f54 Mon Sep 17 00:00:00 2001 From: David Pratt Date: Fri, 28 Apr 2017 17:21:47 -0500 Subject: [PATCH] Use proxy-protocol to pass through source IP to nginx --- controllers/nginx/pkg/cmd/controller/nginx.go | 3 +++ controllers/nginx/pkg/cmd/controller/tcp.go | 24 ++++++++++++++++++- .../rootfs/etc/nginx/template/nginx.tmpl | 6 ++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/controllers/nginx/pkg/cmd/controller/nginx.go b/controllers/nginx/pkg/cmd/controller/nginx.go index 7047cec4dd..5d9d9c5471 100644 --- a/controllers/nginx/pkg/cmd/controller/nginx.go +++ b/controllers/nginx/pkg/cmd/controller/nginx.go @@ -88,6 +88,7 @@ func newNGINXController() ingress.Controller { Hostname: "localhost", IP: "127.0.0.1", Port: 442, + ProxyProtocol: true, }, }, } @@ -531,10 +532,12 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) ([]byte, er } } + //TODO: Allow PassthroughBackends to specify they support proxy-protocol servers = append(servers, &server{ Hostname: pb.Hostname, IP: svc.Spec.ClusterIP, Port: port, + ProxyProtocol: false, }) } diff --git a/controllers/nginx/pkg/cmd/controller/tcp.go b/controllers/nginx/pkg/cmd/controller/tcp.go index 54bafc8be5..8a95fd0912 100644 --- a/controllers/nginx/pkg/cmd/controller/tcp.go +++ b/controllers/nginx/pkg/cmd/controller/tcp.go @@ -13,6 +13,7 @@ type server struct { Hostname string IP string Port int + ProxyProtocol bool } type proxy struct { @@ -61,10 +62,31 @@ func (p *proxy) Handle(conn net.Conn) { } defer clientConn.Close() - _, err = clientConn.Write(data[:length]) + if proxy.ProxyProtocol { + //Write out the proxy-protocol header + localAddr := conn.LocalAddr().(*net.TCPAddr) + remoteAddr := conn.RemoteAddr().(*net.TCPAddr) + protocol := "UNKNOWN" + if remoteAddr.IP.To4() != nil { + protocol = "TCP4" + } else if remoteAddr.IP.To16() != nil { + protocol = "TCP6" + } + proxyProtocolHeader := fmt.Sprintf("PROXY %s %s %s %d %d\r\n", protocol, remoteAddr.IP.String(), localAddr.IP.String(), remoteAddr.Port, localAddr.Port) + glog.V(4).Infof("Writing proxy protocol header - %s", proxyProtocolHeader) + _, err = fmt.Fprintf(clientConn, proxyProtocolHeader) + } if err != nil { + glog.Errorf("unexpected error writing proxy-protocol header: %s", err) clientConn.Close() + } else { + _, err = clientConn.Write(data[:length]) + if err != nil { + glog.Errorf("unexpected error writing first 4k of proxy data: %s", err) + clientConn.Close() + } } + pipe(clientConn, conn) } diff --git a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl index 7e49234b80..ba4d8f78e3 100644 --- a/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl +++ b/controllers/nginx/rootfs/etc/nginx/template/nginx.tmpl @@ -230,9 +230,9 @@ http { {{ if $IsIPV6Enabled }}listen [::]:80{{ if $cfg.UseProxyProtocol }} proxy_protocol{{ end }}{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{ end }};{{ end }} {{/* Listen on 442 because port 443 is used in the TLS sni server */}} - {{/* This listen on port 442 cannot contains proxy_protocol directive because port 443 is in charge of decoding the protocol */}} - {{ if not (empty $server.SSLCertificate) }}listen 442{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; - {{ if $IsIPV6Enabled }}{{ if not (empty $server.SSLCertificate) }}listen [::]:442{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};{{ end }} + {{/* This listener must always have proxy_protocol enabled, because the SNI listener forwards on source IP info in it. */}} + {{ if not (empty $server.SSLCertificate) }}listen 442 proxy_protocol{{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }}; + {{ if $IsIPV6Enabled }}{{ if not (empty $server.SSLCertificate) }}listen [::]:442 proxy_protocol{{ end }} {{ if eq $server.Hostname "_"}} default_server reuseport backlog={{ $backlogSize }}{{end}} ssl {{ if $cfg.UseHTTP2 }}http2{{ end }};{{ end }} {{/* comment PEM sha is required to detect changes in the generated configuration and force a reload */}} # PEM sha: {{ $server.SSLPemChecksum }} ssl_certificate {{ $server.SSLCertificate }};