Add TLS support for etcd and consul

This commit is contained in:
Martin 2016-07-07 17:25:42 +02:00
parent e26e0955b3
commit b83fb525a8
8 changed files with 197 additions and 27 deletions

14
glide.lock generated
View file

@ -1,5 +1,5 @@
hash: cf8f42aae193bd26b7670157094e6b11590443bc500f0a78243ee21bd3ed314e hash: 70ad4e576bc1fa845512cce6b4ade5c422ba4fb5bb0472b37e1d3a93f13809cd
updated: 2016-06-23T17:46:42.381770076+02:00 updated: 2016-07-07T17:33:16.358775373+02:00
imports: imports:
- name: github.com/boltdb/bolt - name: github.com/boltdb/bolt
version: 3f7947a25d970e1e5f512276c14d5dcf731ccd5e version: 3f7947a25d970e1e5f512276c14d5dcf731ccd5e
@ -36,7 +36,7 @@ imports:
subpackages: subpackages:
- spew - spew
- name: github.com/docker/distribution - name: github.com/docker/distribution
version: edd7cb5249d0a45262b20bb58b838ecf4fb368bd version: 4e17ab5d319ac5b70b2769442947567a83386fbc
subpackages: subpackages:
- reference - reference
- digest - digest
@ -100,7 +100,7 @@ imports:
- name: github.com/gorilla/context - name: github.com/gorilla/context
version: aed02d124ae4a0e94fea4541c8effd05bf0c8296 version: aed02d124ae4a0e94fea4541c8effd05bf0c8296
- name: github.com/hashicorp/consul - name: github.com/hashicorp/consul
version: 6e061b2d580d80347b7c5c4dfc8730de7403a145 version: 64e3033d3c7f80af3f925f4665a9bc1af75d6153
subpackages: subpackages:
- api - api
- name: github.com/hashicorp/go-cleanhttp - name: github.com/hashicorp/go-cleanhttp
@ -134,7 +134,7 @@ imports:
- name: github.com/Microsoft/go-winio - name: github.com/Microsoft/go-winio
version: ce2922f643c8fd76b46cadc7f404a06282678b34 version: ce2922f643c8fd76b46cadc7f404a06282678b34
- name: github.com/miekg/dns - name: github.com/miekg/dns
version: 48ab6605c66ac797e07f615101c3e9e10e932b66 version: 5d001d020961ae1c184f9f8152fdc73810481677
- name: github.com/mitchellh/mapstructure - name: github.com/mitchellh/mapstructure
version: d2dd0262208475919e1a362f675cfc0e7c10e905 version: d2dd0262208475919e1a362f675cfc0e7c10e905
- name: github.com/moul/http2curl - name: github.com/moul/http2curl
@ -142,7 +142,7 @@ imports:
- name: github.com/ogier/pflag - name: github.com/ogier/pflag
version: 45c278ab3607870051a2ea9040bb85fcb8557481 version: 45c278ab3607870051a2ea9040bb85fcb8557481
- name: github.com/opencontainers/runc - name: github.com/opencontainers/runc
version: 5dc3f3576efb5262bf582217e93f86c93944374d version: 9d7831e41d3ef428b67685eeb27f2b4a22a92391
subpackages: subpackages:
- libcontainer/user - libcontainer/user
- name: github.com/parnurzeal/gorequest - name: github.com/parnurzeal/gorequest
@ -219,7 +219,7 @@ imports:
subpackages: subpackages:
- acme - acme
- name: golang.org/x/crypto - name: golang.org/x/crypto
version: f3241ce8505855877cc8a9717bd61a0f7c4ea83c version: d81fdb778bf2c40a91b24519d60cdc5767318829
subpackages: subpackages:
- ocsp - ocsp
- name: golang.org/x/net - name: golang.org/x/net

View file

@ -12,6 +12,7 @@ import (
"errors" "errors"
"github.com/containous/traefik/integration/utils" "github.com/containous/traefik/integration/utils"
"github.com/containous/traefik/provider"
checker "github.com/vdemeester/shakers" checker "github.com/vdemeester/shakers"
"io/ioutil" "io/ioutil"
"os" "os"
@ -24,7 +25,7 @@ type ConsulSuite struct {
kv store.Store kv store.Store
} }
func (s *ConsulSuite) SetUpTest(c *check.C) { func (s *ConsulSuite) setupConsul(c *check.C) {
s.createComposeProject(c, "consul") s.createComposeProject(c, "consul")
s.composeProject.Start(c) s.composeProject.Start(c)
@ -52,6 +53,45 @@ func (s *ConsulSuite) SetUpTest(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
func (s *ConsulSuite) setupConsulTLS(c *check.C) {
s.createComposeProject(c, "consul_tls")
s.composeProject.Start(c)
consul.Register()
clientTLS := &provider.ClientTLS{
CA: "resources/tls/ca.cert",
Cert: "resources/tls/consul.cert",
Key: "resources/tls/consul.key",
InsecureSkipVerify: true,
}
TLSConfig, err := clientTLS.CreateTLSConfig()
c.Assert(err, checker.IsNil)
kv, err := libkv.NewStore(
store.CONSUL,
[]string{s.composeProject.Container(c, "consul").NetworkSettings.IPAddress + ":8585"},
&store.Config{
ConnectionTimeout: 10 * time.Second,
TLS: TLSConfig,
},
)
if err != nil {
c.Fatal("Cannot create store consul")
}
s.kv = kv
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := kv.Exists("test")
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
}
func (s *ConsulSuite) TearDownTest(c *check.C) { func (s *ConsulSuite) TearDownTest(c *check.C) {
// shutdown and delete compose project // shutdown and delete compose project
if s.composeProject != nil { if s.composeProject != nil {
@ -62,6 +102,7 @@ func (s *ConsulSuite) TearDownTest(c *check.C) {
func (s *ConsulSuite) TearDownSuite(c *check.C) {} func (s *ConsulSuite) TearDownSuite(c *check.C) {}
func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) { func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
s.setupConsul(c)
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost}) file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost})
defer os.Remove(file) defer os.Remove(file)
@ -79,6 +120,7 @@ func (s *ConsulSuite) TestSimpleConfiguration(c *check.C) {
} }
func (s *ConsulSuite) TestNominalConfiguration(c *check.C) { func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
s.setupConsul(c)
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost}) file := s.adaptFile(c, "fixtures/consul/simple.toml", struct{ ConsulHost string }{consulHost})
defer os.Remove(file) defer os.Remove(file)
@ -201,6 +243,7 @@ func (s *ConsulSuite) TestNominalConfiguration(c *check.C) {
} }
func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) { func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) {
s.setupConsul(c)
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
err := s.kv.Put("traefik/entrypoints/http/address", []byte(":8001"), nil) err := s.kv.Put("traefik/entrypoints/http/address", []byte(":8001"), nil)
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
@ -305,3 +348,46 @@ func (s *ConsulSuite) TestGlobalConfiguration(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, 200) c.Assert(response.StatusCode, checker.Equals, 200)
} }
func (s *ConsulSuite) TestGlobalConfigurationWithClientTLS(c *check.C) {
s.setupConsulTLS(c)
consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress
err := s.kv.Put("traefik/web/address", []byte(":8081"), nil)
c.Assert(err, checker.IsNil)
// wait for consul
err = utils.Try(60*time.Second, func() error {
_, err := s.kv.Exists("traefik/web/address")
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
// start traefik
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml",
"--consul", "--consul.endpoint="+consulHost+":8585",
"--consul.tls.ca=resources/tls/ca.cert",
"--consul.tls.cert=resources/tls/consul.cert",
"--consul.tls.key=resources/tls/consul.key",
"--consul.tls.insecureskipverify")
// cmd.Stdout = os.Stdout
// cmd.Stderr = os.Stderr
err = cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8081/api/providers", 60*time.Second, func(res *http.Response) error {
_, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
return nil
})
c.Assert(err, checker.IsNil)
}

View file

@ -0,0 +1,14 @@
consul:
image: progrium/consul
command: -server -bootstrap -log-level debug -ui-dir /ui -config-dir /configs
ports:
- "8500:8500"
- "8585:8585"
expose:
- "8300"
- "8301"
- "8301/udp"
- "8302"
- "8302/udp"
volumes:
- ../tls:/configs

View file

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrTCCApWgAwIBAgIJAO8QudN/gvGqMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV
BAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxDTALBgNVBAcMBEx5b24xDzANBgNVBAoM
BlplbmlrYTENMAsGA1UEAwwEdGVzdDEeMBwGCSqGSIb3DQEJARYPdGVzdEB6ZW5p
a2EuY29tMB4XDTE2MDcwNjA5MTA1MloXDTI2MDcwNDA5MTA1MlowbTELMAkGA1UE
BhMCRlIxDzANBgNVBAgMBkZyYW5jZTENMAsGA1UEBwwETHlvbjEPMA0GA1UECgwG
WmVuaWthMQ0wCwYDVQQDDAR0ZXN0MR4wHAYJKoZIhvcNAQkBFg90ZXN0QHplbmlr
YS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKwrXlde3J8hFY
hEvH1GH5SfA64/yb7pjXOwI3kvdS2dkbLglOL/jsolARAfFWxhhnnyJUy/BBzZtS
rZN/IukuLCypzjnF6I9koVwILU2EkhPcBUzPZWD6gDU42XZH/lgglZyTyLA/pi24
eAag5xVuTBMmBGbRsJJEq8MYgzSOAQLu2K8vFPARZdnvOMXVpfrC5+RxDj1AzyxU
5s7olWWG13cWkkh2PUNdb1gCXsz34ALG3EmD2S92tovkKHUZS5zHnOvFl8bF7bKC
MoXBi4bL2cUQXq815uFl0gfRrBgN4U+uT2UjzhIV9ax/xnkGueXi9wGPYP3Yanu8
dguEtevRAgMBAAGjUDBOMB0GA1UdDgQWBBSxdmZrC6APPhMg73JGRa1sKPB2CDAf
BgNVHSMEGDAWgBSxdmZrC6APPhMg73JGRa1sKPB2CDAMBgNVHRMEBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQBEZNfJxlKr/hv/cyfbJX6yUKDRG/sIFVD4G9uNEKak
N9Dm5/FZ3pzosq/mBuMjXyY/5kYfiBPpyJfUK7CpWfa/U1RP76dDPm+3aaTNK0XS
rWWxP/n5plfb6bt53cfKrnk9ud9ZqY6jX0vQzbVp6F4+jN3ZZfl4SEwlbK0jnrYV
pbjPKbDS5o0RNgLuk/KN9x/KLb9FdgTYxVrB4orDUzpxx54sjfHRGodUAO9VIlbZ
WteavUhCqbVWvYBB64vxKY695PeX79nmwCMVmsy8luquJYgIn27Czexuei3+2mxX
f1rPZL+iCzi8cuShXqhrxH2dNyxsmYFjiPwFHSVgYtL2
-----END CERTIFICATE-----

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIBEDANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJGUjEP
MA0GA1UECAwGRnJhbmNlMQ0wCwYDVQQHDARMeW9uMQ8wDQYDVQQKDAZaZW5pa2Ex
DTALBgNVBAMMBHRlc3QxHjAcBgkqhkiG9w0BCQEWD3Rlc3RAemVuaWthLmNvbTAe
Fw0xNjA3MDYxMzMzMTJaFw0yNjA3MDQxMzMzMTJaMBQxEjAQBgNVBAMMCWxvY2Fs
aG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyOvmLF7FLDur27bX7OYo
lh3RF/9Bo0Eq1+uFbqs7/KNVp66njn4QYT+OLcRTovoCIbTqaFT7jeqIKxpJ+DWL
n61BENZvsfSPkxTyF/zekarMHhvrMSpPqEP+NFnfmEVQ4kUELAyREmq6qkZloavV
8X8obRjGbNGuWpNLAlO0g68CAwEAAaOBizCBiDAJBgNVHRMEAjAAMB0GA1UdDgQW
BBQPlr+xQCpVYfksoxb+tsnNkL63EjAfBgNVHSMEGDAWgBSxdmZrC6APPhMg73JG
Ra1sKPB2CDALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
BwMCMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEFBQADggEBAEUgwhGh48yJ
JDlR7lT+uWQkPGXuXuATYKOt2fnqYFQ3z3jzP2Og8mR/iZJm85GvsN7CyfVi8hZL
sNJOJ1KPRrGVrOFGD4fd8e1sYYw1wowyEiBQii9f/BGy8khw7rl5RrZotuffTulx
PWXF9EyO+vLhpkPzCXG7CkJdakWfJX/83C7xfC+wOpyeGG89IW2l4W6yofLV88hL
LqBLfuL3J9ZknplSmHDB4W4TFr9aHd2zXdgAUgGd+b0+JfxZtxClivn8RoIkR6Dr
JKhxFO9i714+0MKQMEWAvAFcTw8I9ddkQ4cWs9YoYKYdF/cxowAxGYuykI+H92PO
ABAA2aH8ilE=
-----END CERTIFICATE-----

View file

@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMjr5ixexSw7q9u2
1+zmKJYd0Rf/QaNBKtfrhW6rO/yjVaeup45+EGE/ji3EU6L6AiG06mhU+43qiCsa
Sfg1i5+tQRDWb7H0j5MU8hf83pGqzB4b6zEqT6hD/jRZ35hFUOJFBCwMkRJquqpG
ZaGr1fF/KG0YxmzRrlqTSwJTtIOvAgMBAAECgYB2kymK4/8vRKP/DeBOkeI//abJ
p73/79SuCvP7RRko1ugVBrEiGenmypBJGEVXuH4LkG6KViUDMvdboK8oycj0zL6y
4naKuWct6EOcxSLhdFyCFLPY+0ggl3F9oG92D02H/3oU7ORBNFBaigSYRSP8EieT
5LxCkM2L1cElMJ/6cQJBAP901eNQZSvikAPma+9oPySD01e9yr0AE06wBxGNMkHH
OS07WknvIdJAMDKng5Umbp4EG/3UbV5ED/y3NoO22YkCQQDJWVrP5nEx53EXCENb
LWDA7SBxjBX60pqvuguDZSjsONQJUlMlqebZSzf/ezLGRUhkzRek8uOwz8MGKnTV
sf13AkAGvE3ncHc6cP7bG3g9F8KSc+deqOJvmVDpAjste0uX8GjRiH8Y8/UwVgDv
VPtjM2A3SmRyjOdVVPYW8728O1YBAkEAl4aPOPYLKasrCFJHnk5ACfBqAgmSYPgt
QSGZmICAk4UQzRMPT8DU4aIhujpUs7FgEbvml1PS1jUEZ5d75XXVcQJAZI50y14r
LJ4H+Q2NvvmeyuI8csX+63IGGd/Zt9/EYj4TQnKISnTV3cr/vkmsdoCevC4dT8rS
0d1rqCvfNzBUPA==
-----END PRIVATE KEY-----

View file

@ -0,0 +1,9 @@
{
"ports": {
"https": 8585
},
"ca_file": "/configs/ca.cert",
"cert_file": "/configs/consul.cert",
"key_file": "/configs/consul.key",
"verify_outgoing": true
}

View file

@ -22,6 +22,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"text/template" "text/template"
"time"
) )
var versionTemplate = `Version: {{.Version}} var versionTemplate = `Version: {{.Version}}
@ -118,22 +119,40 @@ Complete documentation is available at https://traefik.io`,
var kv *staert.KvSource var kv *staert.KvSource
var err error var err error
storeConfig := &store.Config{
ConnectionTimeout: 30 * time.Second,
Bucket: "traefik",
}
if traefikConfiguration.Consul != nil { if traefikConfiguration.Consul != nil {
//init KvSource //init KvSource
if traefikConfiguration.Consul.TLS != nil {
storeConfig.TLS, err = traefikConfiguration.Consul.TLS.CreateTLSConfig()
if err != nil {
fmtlog.Println(err)
os.Exit(-1)
}
}
consul.Register() consul.Register()
kv, err = staert.NewKvSource( kv, err = staert.NewKvSource(
store.CONSUL, store.CONSUL,
strings.Split(traefikConfiguration.Consul.Endpoint, ","), strings.Split(traefikConfiguration.Consul.Endpoint, ","),
nil, storeConfig,
strings.TrimPrefix(traefikConfiguration.Consul.Prefix, "/"), // TrimPrefix should be done in https://github.com/docker/libkv/blob/master/store/consul/consul.go#L113 : IDK why it doen't work strings.TrimPrefix(traefikConfiguration.Consul.Prefix, "/"),
) )
} else if traefikConfiguration.Etcd != nil { } else if traefikConfiguration.Etcd != nil {
//init KvSource //init KvSource
if traefikConfiguration.Etcd.TLS != nil {
storeConfig.TLS, err = traefikConfiguration.Etcd.TLS.CreateTLSConfig()
if err != nil {
fmtlog.Println(err)
os.Exit(-1)
}
}
etcd.Register() etcd.Register()
kv, err = staert.NewKvSource( kv, err = staert.NewKvSource(
store.ETCD, store.ETCD,
strings.Split(traefikConfiguration.Etcd.Endpoint, ","), strings.Split(traefikConfiguration.Etcd.Endpoint, ","),
nil, storeConfig,
traefikConfiguration.Etcd.Prefix, traefikConfiguration.Etcd.Prefix,
) )
} else if traefikConfiguration.Zookeeper != nil { } else if traefikConfiguration.Zookeeper != nil {
@ -160,25 +179,10 @@ Complete documentation is available at https://traefik.io`,
os.Exit(-1) os.Exit(-1)
} }
// TO DELETE : Used once to fill the kv store
// if kv != nil {
// fmtlog.Println("Try to store global configuration in consul store")
// if err := kv.StoreConfig(traefikConfiguration); err != nil {
// fmtlog.Println(fmt.Errorf("Error : %s", err))
// os.Exit(-1)
// } else {
// fmtlog.Println("It seems okay :)")
// jsonConf, _ := json.Marshal(traefikConfiguration)
// fmtlog.Printf("Global configuration loaded %s", string(jsonConf))
// os.Exit(0)
// }
// }
//TODO : log warning if many KvStore or set priority
if kv != nil { if kv != nil {
s.AddSource(kv) s.AddSource(kv)
if _, err := s.LoadConfig(); err != nil { if _, err := s.LoadConfig(); err != nil {
fmtlog.Println(fmt.Errorf("Error : %s", err)) fmtlog.Println(err)
} }
} }