[proxy] Add tls support
Caveats: * TLS files must be present on the target server (and readable) * TLS file paths cannot contain spaces * TLS file paths must be absolute (i.e. cannot be relative) * Bash argument parsing is terrible
This commit is contained in:
1 parent
8514172e57
commit
c31358259f
9 files changed
+290
-21
No files matched your search
+31
-8
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
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{
|
||||
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 certificate: %v", err)
|
||||
}
|
||||
certPool.AppendCertsFromPEM(file)
|
||||
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
tlsConfig.ClientCAs = 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
|
||||
}
|
||||
Reference in new issue
Block a user