Certificate can contain path or file contents
Signed-off-by: Martin <martin.piegay@zenika.com>
This commit is contained in:
parent
056e0fe2d9
commit
7ada80b619
5 changed files with 172 additions and 14 deletions
|
@ -1,11 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/containous/traefik/acme"
|
||||
"github.com/containous/traefik/provider"
|
||||
"github.com/containous/traefik/types"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -179,6 +181,43 @@ type TLS struct {
|
|||
// Certificates defines traefik certificates type
|
||||
type Certificates []Certificate
|
||||
|
||||
//CreateTLSConfig creates a TLS config from Certificate structures
|
||||
func (certs *Certificates) CreateTLSConfig() (*tls.Config, error) {
|
||||
config := &tls.Config{}
|
||||
config.Certificates = []tls.Certificate{}
|
||||
certsSlice := []Certificate(*certs)
|
||||
for _, v := range certsSlice {
|
||||
isAPath := false
|
||||
_, errCert := os.Stat(v.CertFile)
|
||||
_, errKey := os.Stat(v.KeyFile)
|
||||
if errCert == nil {
|
||||
if errKey == nil {
|
||||
isAPath = true
|
||||
} else {
|
||||
return nil, fmt.Errorf("Bad TLS Certificate KeyFile format. Expected a path.")
|
||||
}
|
||||
} else if errKey == nil {
|
||||
return nil, fmt.Errorf("Bad TLS Certificate KeyFile format. Expected a path.")
|
||||
}
|
||||
|
||||
cert := tls.Certificate{}
|
||||
var err error
|
||||
if isAPath {
|
||||
cert, err = tls.LoadX509KeyPair(v.CertFile, v.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cert, err = tls.X509KeyPair([]byte(v.CertFile), []byte(v.KeyFile))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
config.Certificates = append(config.Certificates, cert)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// String is the method to format the flag's value, part of the flag.Value interface.
|
||||
// The String method's output will be used in diagnostics.
|
||||
func (certs *Certificates) String() string {
|
||||
|
@ -209,6 +248,7 @@ func (certs *Certificates) Type() string {
|
|||
}
|
||||
|
||||
// Certificate holds a SSL cert/key pair
|
||||
// May can contain either path or file contents
|
||||
type Certificate struct {
|
||||
CertFile string
|
||||
KeyFile string
|
||||
|
|
10
glide.lock
generated
10
glide.lock
generated
|
@ -1,5 +1,5 @@
|
|||
hash: 22c20a7d7419e9624267d7f0041cd8ad87afc876d2738fa559527c74f9917c3a
|
||||
updated: 2016-07-05T14:48:30.023831407+02:00
|
||||
hash: cf8f42aae193bd26b7670157094e6b11590443bc500f0a78243ee21bd3ed314e
|
||||
updated: 2016-06-23T17:46:42.381770076+02:00
|
||||
imports:
|
||||
- name: github.com/boltdb/bolt
|
||||
version: 3f7947a25d970e1e5f512276c14d5dcf731ccd5e
|
||||
|
@ -36,7 +36,7 @@ imports:
|
|||
subpackages:
|
||||
- spew
|
||||
- name: github.com/docker/distribution
|
||||
version: 4e17ab5d319ac5b70b2769442947567a83386fbc
|
||||
version: edd7cb5249d0a45262b20bb58b838ecf4fb368bd
|
||||
subpackages:
|
||||
- reference
|
||||
- digest
|
||||
|
@ -142,7 +142,7 @@ imports:
|
|||
- name: github.com/ogier/pflag
|
||||
version: 45c278ab3607870051a2ea9040bb85fcb8557481
|
||||
- name: github.com/opencontainers/runc
|
||||
version: 7221e387826c9918fa9fd6e7975baf4d30c8fa54
|
||||
version: 5dc3f3576efb5262bf582217e93f86c93944374d
|
||||
subpackages:
|
||||
- libcontainer/user
|
||||
- name: github.com/parnurzeal/gorequest
|
||||
|
@ -219,7 +219,7 @@ imports:
|
|||
subpackages:
|
||||
- acme
|
||||
- name: golang.org/x/crypto
|
||||
version: 0c565bf13221fb55497d7ae2bb95694db1fd1bff
|
||||
version: f3241ce8505855877cc8a9717bd61a0f7c4ea83c
|
||||
subpackages:
|
||||
- ocsp
|
||||
- name: golang.org/x/net
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
checker "github.com/vdemeester/shakers"
|
||||
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/containous/traefik/integration/utils"
|
||||
|
@ -308,3 +309,126 @@ func (s *EtcdSuite) TestGlobalConfiguration(c *check.C) {
|
|||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(response.StatusCode, checker.Equals, 200)
|
||||
}
|
||||
|
||||
//TODO : TestCertificatesContents
|
||||
func (s *EtcdSuite) TestCertificatesContentstWithSNIConfigHandshake(c *check.C) {
|
||||
etcdHost := s.composeProject.Container(c, "etcd").NetworkSettings.IPAddress
|
||||
// start traefik
|
||||
cmd := exec.Command(traefikBinary, "--configFile=fixtures/simple_web.toml", "--etcd", "--etcd.endpoint="+etcdHost+":4001")
|
||||
// cmd.Stdout = os.Stdout
|
||||
// cmd.Stderr = os.Stderr
|
||||
|
||||
whoami1 := s.composeProject.Container(c, "whoami1")
|
||||
whoami2 := s.composeProject.Container(c, "whoami2")
|
||||
whoami3 := s.composeProject.Container(c, "whoami3")
|
||||
whoami4 := s.composeProject.Container(c, "whoami4")
|
||||
|
||||
//Copy the contents of the certificate files into ETCD
|
||||
snitestComCert, err := ioutil.ReadFile("fixtures/https/snitest.com.cert")
|
||||
c.Assert(err, checker.IsNil)
|
||||
snitestComKey, err := ioutil.ReadFile("fixtures/https/snitest.com.key")
|
||||
c.Assert(err, checker.IsNil)
|
||||
snitestOrgCert, err := ioutil.ReadFile("fixtures/https/snitest.org.cert")
|
||||
c.Assert(err, checker.IsNil)
|
||||
snitestOrgKey, err := ioutil.ReadFile("fixtures/https/snitest.org.key")
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
globalConfig := map[string]string{
|
||||
"/traefik/entrypoints/https/address": ":4443",
|
||||
"/traefik/entrypoints/https/tls/certificates/0/certfile": string(snitestComCert),
|
||||
"/traefik/entrypoints/https/tls/certificates/0/keyfile": string(snitestComKey),
|
||||
"/traefik/entrypoints/https/tls/certificates/1/certfile": string(snitestOrgCert),
|
||||
"/traefik/entrypoints/https/tls/certificates/1/keyfile": string(snitestOrgKey),
|
||||
"/traefik/defaultentrypoints/0": "https",
|
||||
}
|
||||
|
||||
backend1 := map[string]string{
|
||||
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
|
||||
"/traefik/backends/backend1/servers/server1/url": "http://" + whoami1.NetworkSettings.IPAddress + ":80",
|
||||
"/traefik/backends/backend1/servers/server1/weight": "10",
|
||||
"/traefik/backends/backend1/servers/server2/url": "http://" + whoami2.NetworkSettings.IPAddress + ":80",
|
||||
"/traefik/backends/backend1/servers/server2/weight": "1",
|
||||
}
|
||||
backend2 := map[string]string{
|
||||
"/traefik/backends/backend2/loadbalancer/method": "drr",
|
||||
"/traefik/backends/backend2/servers/server1/url": "http://" + whoami3.NetworkSettings.IPAddress + ":80",
|
||||
"/traefik/backends/backend2/servers/server1/weight": "1",
|
||||
"/traefik/backends/backend2/servers/server2/url": "http://" + whoami4.NetworkSettings.IPAddress + ":80",
|
||||
"/traefik/backends/backend2/servers/server2/weight": "2",
|
||||
}
|
||||
frontend1 := map[string]string{
|
||||
"/traefik/frontends/frontend1/backend": "backend2",
|
||||
"/traefik/frontends/frontend1/entrypoints": "http",
|
||||
"/traefik/frontends/frontend1/priority": "1",
|
||||
"/traefik/frontends/frontend1/routes/test_1/rule": "Host:snitest.com",
|
||||
}
|
||||
frontend2 := map[string]string{
|
||||
"/traefik/frontends/frontend2/backend": "backend1",
|
||||
"/traefik/frontends/frontend2/entrypoints": "http",
|
||||
"/traefik/frontends/frontend2/priority": "10",
|
||||
"/traefik/frontends/frontend2/routes/test_2/rule": "Host:snitest.org",
|
||||
}
|
||||
for key, value := range globalConfig {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range backend1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range backend2 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range frontend1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
for key, value := range frontend2 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// wait for etcd
|
||||
err = utils.Try(60*time.Second, func() error {
|
||||
_, err := s.kv.Exists("/traefik/frontends/frontend2/routes/test_2/rule")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// wait for traefik
|
||||
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.Contains(string(body), "Host:snitest.org") {
|
||||
return errors.New("Incorrect traefik config")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
//check
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.com",
|
||||
}
|
||||
conn, err := tls.Dial("tcp", "127.0.0.1:4443", tlsConfig)
|
||||
c.Assert(err, checker.IsNil, check.Commentf("failed to connect to server"))
|
||||
|
||||
defer conn.Close()
|
||||
err = conn.Handshake()
|
||||
c.Assert(err, checker.IsNil, check.Commentf("TLS handshake error"))
|
||||
|
||||
cs := conn.ConnectionState()
|
||||
err = cs.PeerCertificates[0].VerifyHostname("snitest.com")
|
||||
c.Assert(err, checker.IsNil, check.Commentf("certificate did not match SNI servername"))
|
||||
}
|
||||
|
|
11
server.go
11
server.go
|
@ -290,14 +290,9 @@ func (server *Server) createTLSConfig(entryPointName string, tlsOption *TLS, rou
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
config := &tls.Config{}
|
||||
config.Certificates = []tls.Certificate{}
|
||||
for _, v := range tlsOption.Certificates {
|
||||
cert, err := tls.LoadX509KeyPair(v.CertFile, v.KeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Certificates = append(config.Certificates, cert)
|
||||
config, err := tlsOption.Certificates.CreateTLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(tlsOption.ClientCAFiles) > 0 {
|
||||
|
|
|
@ -176,7 +176,6 @@ Complete documentation is available at https://traefik.io`,
|
|||
|
||||
//TODO : log warning if many KvStore or set priority
|
||||
if kv != nil {
|
||||
fmtlog.Println("KV Store found")
|
||||
s.AddSource(kv)
|
||||
if _, err := s.LoadConfig(); err != nil {
|
||||
fmtlog.Println(fmt.Errorf("Error : %s", err))
|
||||
|
|
Loading…
Reference in a new issue