Fix bugs introduced mainly to docker-machine driver when we added TLS proxy

This commit is contained in:
Jonathan Leibiusky @xetorthio
2017-05-13 11:12:37 -03:00
parent 46bbd3b074
commit aa02432c56
7 changed files with 82 additions and 97 deletions

View File

@@ -45,6 +45,10 @@ CMD cat /etc/hosts >/etc/hosts.bak && \
sed 's/^::1.*//' /etc/hosts.bak > /etc/hosts && \
sed -i "s/\DOCKER_STORAGE_DRIVER/$DOCKER_STORAGE_DRIVER/" /etc/docker/daemon.json && \
sed -i "s/\PWD_IP_ADDRESS/$PWD_IP_ADDRESS/" /etc/docker/daemon.json && \
sed -i "s/\DOCKER_TLSENABLE/$DOCKER_TLSENABLE/" /etc/docker/daemon.json && \
sed -i "s/\DOCKER_TLSCACERT/$DOCKER_TLSCACERT/" /etc/docker/daemon.json && \
sed -i "s/\DOCKER_TLSCERT/$DOCKER_TLSCERT/" /etc/docker/daemon.json && \
sed -i "s/\DOCKER_TLSKEY/$DOCKER_TLSKEY/" /etc/docker/daemon.json && \
umount /var/lib/docker && mount -t securityfs none /sys/kernel/security && \
dockerd &>/docker.log & \
while true ; do script -q -c "/bin/bash -l" /dev/null ; done

View File

@@ -6,5 +6,9 @@
"insecure-registries": ["127.0.0.1"],
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"],
"storage-driver": "DOCKER_STORAGE_DRIVER",
"dns": ["PWD_IP_ADDRESS", "8.8.8.8"]
"dns": ["PWD_IP_ADDRESS", "8.8.8.8"],
"tls": DOCKER_TLSENABLE,
"tlscacert": "DOCKER_TLSCACERT",
"tlscert": "DOCKER_TLSCERT",
"tlskey": "DOCKER_TLSKEY"
}

View File

@@ -1,43 +0,0 @@
package handlers
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/play-with-docker/play-with-docker/services"
)
func SetKeys(rw http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
sessionId := vars["sessionId"]
instanceName := vars["instanceName"]
type certs struct {
ServerCert []byte `json:"server_cert"`
ServerKey []byte `json:"server_key"`
}
var c certs
jsonErr := json.NewDecoder(req.Body).Decode(&c)
if jsonErr != nil {
log.Println(jsonErr)
rw.WriteHeader(http.StatusBadRequest)
return
}
s := services.GetSession(sessionId)
s.Lock()
defer s.Unlock()
i := services.GetInstance(s, instanceName)
_, err := i.SetCertificate(c.ServerCert, c.ServerKey)
if err != nil {
log.Println(err)
rw.WriteHeader(http.StatusBadRequest)
return
}
log.Printf("Set keys for instance %s\n", instanceName)
}

View File

@@ -9,10 +9,12 @@ import (
"strings"
vhost "github.com/inconshreveable/go-vhost"
"github.com/play-with-docker/play-with-docker/services"
)
func StartTLSProxy(port string) {
var validProxyHost = regexp.MustCompile(`^.*pwd([0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3})(?:-?([0-9]{1,5}))?\..*$`)
var validAliasProxyHost = regexp.MustCompile(`^.*pwd([0-9|a-z|A-Z]*)-([0-9|a-z|A-Z]{8})(?:-?([0-9]{1,5}))?\..*$`)
tlsListener, tlsErr := net.Listen("tcp", fmt.Sprintf(":%s", port))
log.Println("Listening on port " + port)
@@ -37,26 +39,42 @@ func StartTLSProxy(port string) {
}
defer vhostConn.Close()
host := vhostConn.ClientHelloMsg.ServerName
match := validProxyHost.FindStringSubmatch(host)
if len(match) < 2 {
// Not a valid proxy host, just close connection.
return
}
var targetIP string
targetPort := "443"
if len(match) == 3 {
targetPort = match[2]
}
ip := strings.Replace(match[1], "-", ".", -1)
if net.ParseIP(ip) == nil {
// Not a valid IP, so treat this is a hostname.
host := vhostConn.ClientHelloMsg.ServerName
match := validProxyHost.FindStringSubmatch(host)
if len(match) < 2 {
// Not a valid proxy host, try alias hosts
match := validAliasProxyHost.FindStringSubmatch(host)
if len(match) < 4 {
// Not valid, just close the connection
return
} else {
alias := match[1]
sessionPrefix := match[2]
instance := services.FindInstanceByAlias(sessionPrefix, alias)
if instance != nil {
targetIP = instance.IP
} else {
return
}
if len(match) == 4 {
targetPort = match[3]
}
}
} else {
targetIP = ip
// Valid proxy host
ip := strings.Replace(match[1], "-", ".", -1)
if net.ParseIP(ip) == nil {
// Not a valid IP, so treat this is a hostname.
return
} else {
targetIP = ip
}
if len(match) == 3 {
targetPort = match[2]
}
}
dest := fmt.Sprintf("%s:%s", targetIP, targetPort)

View File

@@ -244,14 +244,14 @@ func CreateInstance(session *Session, conf InstanceConfig) (*Instance, error) {
// Write certs to container cert dir
if len(conf.ServerCert) > 0 {
env = append(env, "DOCKER_TLSCERT=/var/run/pwd/certs/cert.pem")
env = append(env, `DOCKER_TLSCERT=\/var\/run\/pwd\/certs\/cert.pem`)
}
if len(conf.ServerKey) > 0 {
env = append(env, "DOCKER_TLSKEY=/var/run/pwd/certs/key.pem")
env = append(env, `DOCKER_TLSKEY=\/var\/run\/pwd\/certs\/key.pem`)
}
if len(conf.CACert) > 0 {
// if ca cert is specified, verify that clients that connects present a certificate signed by the CA
env = append(env, "DOCKER_TLSCACERT=/var/run/pwd/certs/ca.pem")
env = append(env, `DOCKER_TLSCACERT=\/var\/run\/pwd\/certs\/ca.pem`)
}
if len(conf.ServerCert) > 0 || len(conf.ServerKey) > 0 || len(conf.CACert) > 0 {
// if any of the certs is specified, enable TLS
@@ -323,7 +323,11 @@ func CreateInstance(session *Session, conf InstanceConfig) (*Instance, error) {
return nil, err
}
return &Instance{Name: containerName, Hostname: cinfo.Config.Hostname, IP: cinfo.NetworkSettings.Networks[session.Id].IPAddress}, nil
return &Instance{
Name: containerName,
Hostname: cinfo.Config.Hostname,
IP: cinfo.NetworkSettings.Networks[session.Id].IPAddress,
}, nil
}
func copyIfSet(content []byte, fileName, path, containerName string) error {

View File

@@ -2,7 +2,6 @@ package services
import (
"context"
"crypto/tls"
"fmt"
"io"
"log"
@@ -38,11 +37,13 @@ type Instance struct {
Mem string `json:"mem"`
Cpu string `json:"cpu"`
Alias string `json:"alias"`
tempPorts []uint16 `json:"-"`
ServerCert []byte `json:"server_cert"`
ServerKey []byte `json:"server_key"`
CACert []byte `json:"ca_cert"`
Cert []byte `json:"cert"`
Key []byte `json:"key"`
Ports UInt16Slice
tempPorts []uint16 `json:"-"`
ServerCert []byte `json:"server_cert"`
ServerKey []byte `json:"server_key"`
cert *tls.Certificate `json:"-"`
}
type InstanceConfig struct {
@@ -51,6 +52,8 @@ type InstanceConfig struct {
ServerCert []byte
ServerKey []byte
CACert []byte
Cert []byte
Key []byte
}
func (i *Instance) setUsedPort(port uint16) {
@@ -65,25 +68,6 @@ func (i *Instance) setUsedPort(port uint16) {
i.tempPorts = append(i.tempPorts, port)
}
func (i *Instance) SetCertificate(cert, key []byte) (*tls.Certificate, error) {
i.ServerCert = cert
i.ServerKey = key
c, e := tls.X509KeyPair(i.ServerCert, i.ServerKey)
if e != nil {
return nil, e
}
i.cert = &c
// We store sessions as soon as we set instance keys
if err := saveSessionsToDisk(); err != nil {
return nil, err
}
return i.cert, nil
}
func (i *Instance) GetCertificate() *tls.Certificate {
return i.cert
}
func (i *Instance) IsConnected() bool {
return i.conn != nil
@@ -119,7 +103,11 @@ func NewInstance(session *Session, conf InstanceConfig) (*Instance, error) {
}
instance.Alias = conf.Alias
instance.Cert = conf.Cert
instance.Key = conf.Key
instance.ServerCert = conf.ServerCert
instance.ServerKey = conf.ServerKey
instance.CACert = conf.CACert
instance.session = session
if session.Instances == nil {

View File

@@ -1,6 +1,7 @@
package services
import (
"crypto/tls"
"encoding/gob"
"fmt"
"log"
@@ -15,6 +16,7 @@ import (
"github.com/docker/docker/api"
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
"github.com/googollee/go-socket.io"
"github.com/play-with-docker/play-with-docker/config"
"github.com/prometheus/client_golang/prometheus"
@@ -99,11 +101,27 @@ func (s *Session) SchedulePeriodicTasks() {
if i.dockerClient == nil {
// Need to create client to the DinD docker daemon
// We check if the client needs to use TLS
var tlsConfig *tls.Config
if len(i.Cert) > 0 && len(i.Key) > 0 {
tlsConfig = tlsconfig.ClientDefault()
tlsConfig.InsecureSkipVerify = true
tlsCert, err := tls.X509KeyPair(i.Cert, i.Key)
if err != nil {
log.Println("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
continue
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
}
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 1 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext}
if tlsConfig != nil {
transport.TLSClientConfig = tlsConfig
}
cli := &http.Client{
Transport: transport,
}
@@ -313,14 +331,6 @@ func LoadSessionsFromDisk() error {
for _, i := range s.Instances {
// wire the session back to the instance
i.session = s
if i.ServerCert != nil && i.ServerKey != nil {
_, err := i.SetCertificate(i.ServerCert, i.ServerKey)
if err != nil {
log.Println(err)
return err
}
}
}
// Connect PWD daemon to the new network