From 847fdb31681c0fd52013d42bc4c301dcfc759cbd Mon Sep 17 00:00:00 2001 From: Manuel de Brito Fontes Date: Tue, 16 Jan 2018 16:23:05 -0300 Subject: [PATCH] Move SSL passthrough code inside the controller package --- cmd/nginx/main.go | 7 +- internal/ingress/controller/nginx.go | 117 +++++++++++++++++++-------- 2 files changed, 89 insertions(+), 35 deletions(-) diff --git a/cmd/nginx/main.go b/cmd/nginx/main.go index a645c317a..d7edf8118 100644 --- a/cmd/nginx/main.go +++ b/cmd/nginx/main.go @@ -19,6 +19,7 @@ package main import ( "encoding/json" "fmt" + "math/rand" "net" "net/http" "net/http/pprof" @@ -47,6 +48,8 @@ import ( ) func main() { + rand.Seed(time.Now().UnixNano()) + fmt.Println(version.String()) showVersion, conf, err := parseFlags() @@ -118,7 +121,7 @@ func main() { // create the default SSL certificate (dummy) defCert, defKey := ssl.GetFakeSSLCert() - c, err := ssl.AddOrUpdateCertAndKey(fakeCertificate, defCert, defKey, []byte{}, fs) + c, err := ssl.AddOrUpdateCertAndKey(fakeCertificate, defCert, defKey, []byte{}) if err != nil { glog.Fatalf("Error generating self signed certificate: %v", err) } @@ -189,7 +192,7 @@ func setupSSLProxy(sslPort, proxyPort int, n *controller.NGINXController) { var conn net.Conn var err error - if n.IsProxyProtocolEnabled() { + if n.IsProxyProtocolEnabled { // we need to wrap the listener in order to decode // proxy protocol before handling the connection conn, err = proxyList.Accept() diff --git a/internal/ingress/controller/nginx.go b/internal/ingress/controller/nginx.go index 1d5e1ba83..3d859b7be 100644 --- a/internal/ingress/controller/nginx.go +++ b/internal/ingress/controller/nginx.go @@ -32,6 +32,7 @@ import ( "github.com/golang/glog" + proxyproto "github.com/armon/go-proxyproto" apiv1 "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" "k8s.io/client-go/kubernetes/scheme" @@ -227,6 +228,8 @@ type NGINXController struct { isShuttingDown bool + Proxy *TCPProxy + store store.Storer fileSystem filesystem.Filesystem @@ -252,6 +255,10 @@ func (n *NGINXController) Start() { Pgid: 0, } + if n.cfg.EnableSSLPassthrough { + n.setupSSLProxy() + } + glog.Info("starting NGINX process...") n.start(cmd) @@ -399,40 +406,38 @@ func (n *NGINXController) OnUpdate(ingressCfg ingress.Configuration) error { cfg := n.store.GetBackendConfiguration() cfg.Resolver = n.resolver - /* - servers := []*TCPServer{} - for _, pb := range ingressCfg.PassthroughBackends { - svc := pb.Service - if svc == nil { - glog.Warningf("missing service for PassthroughBackends %v", pb.Backend) - continue - } - port, err := strconv.Atoi(pb.Port.String()) - if err != nil { - for _, sp := range svc.Spec.Ports { - if sp.Name == pb.Port.String() { - port = int(sp.Port) - break - } - } - } else { - for _, sp := range svc.Spec.Ports { - if sp.Port == int32(port) { - port = int(sp.Port) - break - } - } - } - - //TODO: Allow PassthroughBackends to specify they support proxy-protocol - servers = append(servers, &TCPServer{ - Hostname: pb.Hostname, - IP: svc.Spec.ClusterIP, - Port: port, - ProxyProtocol: false, - }) + servers := []*TCPServer{} + for _, pb := range ingressCfg.PassthroughBackends { + svc := pb.Service + if svc == nil { + glog.Warningf("missing service for PassthroughBackends %v", pb.Backend) + continue } - */ + port, err := strconv.Atoi(pb.Port.String()) + if err != nil { + for _, sp := range svc.Spec.Ports { + if sp.Name == pb.Port.String() { + port = int(sp.Port) + break + } + } + } else { + for _, sp := range svc.Spec.Ports { + if sp.Port == int32(port) { + port = int(sp.Port) + break + } + } + } + + //TODO: Allow PassthroughBackends to specify they support proxy-protocol + servers = append(servers, &TCPServer{ + Hostname: pb.Hostname, + IP: svc.Spec.ClusterIP, + Port: port, + ProxyProtocol: false, + }) + } // we need to check if the status module configuration changed if cfg.EnableVtsStatus { @@ -640,3 +645,49 @@ func nextPowerOf2(v int) int { return v } + +func (n *NGINXController) setupSSLProxy() { + sslPort := n.cfg.ListenPorts.HTTPS + proxyPort := n.cfg.ListenPorts.SSLProxy + + glog.Info("starting TLS proxy for SSL passthrough") + n.Proxy = &TCPProxy{ + Default: &TCPServer{ + Hostname: "localhost", + IP: "127.0.0.1", + Port: proxyPort, + ProxyProtocol: true, + }, + } + + listener, err := net.Listen("tcp", fmt.Sprintf(":%v", sslPort)) + if err != nil { + glog.Fatalf("%v", err) + } + + proxyList := &proxyproto.Listener{Listener: listener} + + // start goroutine that accepts tcp connections in port 443 + go func() { + for { + var conn net.Conn + var err error + + if n.store.GetBackendConfiguration().UseProxyProtocol { + // we need to wrap the listener in order to decode + // proxy protocol before handling the connection + conn, err = proxyList.Accept() + } else { + conn, err = listener.Accept() + } + + if err != nil { + glog.Warningf("unexpected error accepting tcp connection: %v", err) + continue + } + + glog.V(3).Infof("remote address %s to local %s", conn.RemoteAddr(), conn.LocalAddr()) + go n.Proxy.Handle(conn) + } + }() +}