Proof-of-Concept for proxy TLS support

The code is quite messy, but particularly the argument parsing and
volume-mounting. Also, it doesn't support args with spaces, or
non-absolute file-paths.
This commit is contained in:
Paul Bellamy committed 2015-06-01 16:50:52 +01:00
1 parent 4774043295
commit 74afbc5505
9 files changed
+265 -20

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
package proxy
import (
"crypto/tls"
"net"
)
func (proxy *Proxy) listener(addr string) (net.Listener, error) {
listener, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
if proxy.tlsConfig.enabled() {
listener = tls.NewListener(listener, proxy.tlsConfig.Config)
}
return listener, nil
}
+31 -8
View File
@@ -2,6 +2,7 @@ package proxy
import (
"bytes"
"crypto/tls"
"fmt"
"net"
"net/http"
@@ -13,6 +14,12 @@ import (
. "github.com/weaveworks/weave/common"
)
const (
defaultCaFile = "ca.pem"
defaultKeyFile = "key.pem"
defaultCertFile = "cert.pem"
)
var (
containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
containerStartRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
@@ -24,13 +31,14 @@ type Proxy struct {
version string
client *docker.Client
dockerAddr string
listenAddr string
withDNS bool
dockerBridgeIP string
listenAddr string
tlsConfig *TLSConfig
withDNS bool
withIPAM bool
}
func NewProxy(version, dockerAddr, listenAddr string, withDNS, withIPAM bool) (*Proxy, error) {
func NewProxy(version, dockerAddr, listenAddr string, withDNS, withIPAM bool, tlsConfig *TLSConfig) (*Proxy, error) {
u, err := url.Parse(dockerAddr)
if err != nil {
return nil, err
@@ -44,6 +52,10 @@ func NewProxy(version, dockerAddr, listenAddr string, withDNS, withIPAM bool) (*
}
}
if err := tlsConfig.loadCerts(); err != nil {
Error.Fatalf("Could not configure tls for proxy: %s", err)
}
client, err := docker.NewClient(dockerAddr)
if err != nil {
return nil, err
@@ -65,8 +77,9 @@ func NewProxy(version, dockerAddr, listenAddr string, withDNS, withIPAM bool) (*
client: client,
dockerAddr: dockerAddr,
listenAddr: listenAddr,
withDNS: withDNS,
dockerBridgeIP: string(dockerBridgeIP),
tlsConfig: tlsConfig,
withDNS: withDNS,
withIPAM: withIPAM,
}, nil
}
@@ -112,8 +125,18 @@ func (proxy *Proxy) Status() string {
}
func (proxy *Proxy) ListenAndServe() error {
return (&http.Server{
Addr: proxy.listenAddr,
Handler: proxy,
}).ListenAndServe()
listener, err := net.Listen("tcp", proxy.listenAddr)
if err != nil {
return err
}
if proxy.tlsConfig.enabled() {
listener = tls.NewListener(listener, proxy.tlsConfig.Config)
Info.Println("TLS Enabled")
}
Info.Printf("Listening on %s", proxy.listenAddr)
Info.Printf("Proxying %s", proxy.dockerAddr)
return (&http.Server{Handler: proxy}).Serve(listener)
}
+78
View File
@@ -0,0 +1,78 @@
package proxy
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/docker/docker/pkg/homedir"
)
type TLSConfig struct {
Enabled, Verify bool
Cert, Key, CACert string
*tls.Config
}
func (c *TLSConfig) enabled() bool {
if c == nil {
return false
}
return c.Enabled || c.Verify
}
func (c *TLSConfig) loadCerts() error {
if !c.enabled() {
return nil
}
dockerCertPath := os.Getenv("DOCKER_CERT_PATH")
if dockerCertPath == "" {
dockerCertPath = filepath.Join(homedir.Get(), ".docker")
}
if c.CACert == "" {
c.CACert = filepath.Join(dockerCertPath, defaultCaFile)
}
if c.Cert == "" {
c.Cert = filepath.Join(dockerCertPath, defaultCertFile)
}
if c.Key == "" {
c.Key = filepath.Join(dockerCertPath, defaultKeyFile)
}
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"http/1.1"},
// Avoid fallback on insecure SSL protocols
MinVersion: tls.VersionTLS10,
}
if c.Verify {
certPool := x509.NewCertPool()
file, err := ioutil.ReadFile(c.CACert)
if err != nil {
return fmt.Errorf("Couldn't read CA cert %s: %s", c.CACert, err)
}
certPool.AppendCertsFromPEM(file)
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
tlsConfig.InsecureSkipVerify = false
tlsConfig.RootCAs = certPool
}
_, errCert := os.Stat(c.Cert)
_, errKey := os.Stat(c.Key)
if errCert == nil && errKey == nil {
cert, err := tls.LoadX509KeyPair(c.Cert, c.Key)
if err != nil {
return fmt.Errorf("Couldn't load X509 key pair: %q. Make sure the key is encrypted", err)
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
c.Config = tlsConfig
return nil
}