Merge branch 'v1.5' into master
This commit is contained in:
commit
c84fb9895e
35 changed files with 462 additions and 124 deletions
|
@ -577,3 +577,109 @@ func (s *Etcd3Suite) TestSNIDynamicTlsConfig(c *check.C) {
|
|||
cn = resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "snitest.org")
|
||||
}
|
||||
|
||||
func (s *Etcd3Suite) TestDeleteSNIDynamicTlsConfig(c *check.C) {
|
||||
// start Træfik
|
||||
cmd, display := s.traefikCmd(
|
||||
withConfigFile("fixtures/etcd/simple_https.toml"),
|
||||
"--etcd",
|
||||
"--etcd.endpoint="+ipEtcd+":4001",
|
||||
"--etcd.useAPIV3=true")
|
||||
defer display(c)
|
||||
|
||||
// prepare to config
|
||||
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)
|
||||
|
||||
backend1 := map[string]string{
|
||||
"/traefik/backends/backend1/circuitbreaker/expression": "NetworkErrorRatio() > 0.5",
|
||||
"/traefik/backends/backend1/servers/server1/url": "http://" + ipWhoami01 + ":80",
|
||||
"/traefik/backends/backend1/servers/server1/weight": "1",
|
||||
"/traefik/backends/backend1/servers/server2/url": "http://" + ipWhoami02 + ":80",
|
||||
"/traefik/backends/backend1/servers/server2/weight": "1",
|
||||
}
|
||||
|
||||
frontend1 := map[string]string{
|
||||
"/traefik/frontends/frontend1/backend": "backend1",
|
||||
"/traefik/frontends/frontend1/entrypoints": "https",
|
||||
"/traefik/frontends/frontend1/priority": "1",
|
||||
"/traefik/frontends/frontend1/routes/test_1/rule": "Host:snitest.com",
|
||||
}
|
||||
|
||||
tlsconfigure1 := map[string]string{
|
||||
"/traefik/tlsconfiguration/snitestcom/entrypoints": "https",
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/keyfile": string(snitestComKey),
|
||||
"/traefik/tlsconfiguration/snitestcom/certificate/certfile": string(snitestComCert),
|
||||
}
|
||||
|
||||
// config backends,frontends and first tls keypair
|
||||
for key, value := range backend1 {
|
||||
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 tlsconfigure1 {
|
||||
err := s.kv.Put(key, []byte(value), nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
tr1 := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.com",
|
||||
},
|
||||
}
|
||||
|
||||
// wait for etcd
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
_, err := s.kv.Get("/traefik/tlsconfiguration/snitestcom/certificate/keyfile", nil)
|
||||
return err
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
err = cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
// wait for Træfik
|
||||
err = try.GetRequest(traefikWebEtcdURL+"api/providers", 60*time.Second, try.BodyContains(string("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h")))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
client := &http.Client{Transport: tr1}
|
||||
req.Host = tr1.TLSClientConfig.ServerName
|
||||
req.Header.Set("Host", tr1.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
var resp *http.Response
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
cn := resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "snitest.com")
|
||||
|
||||
// now we delete the tls cert/key pairs,so the endpoint show use default cert/key pair
|
||||
for key := range tlsconfigure1 {
|
||||
err := s.kv.Delete(key)
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
|
||||
// waiting for Træfik to pull configuration
|
||||
err = try.GetRequest(traefikWebEtcdURL+"api/providers", 30*time.Second, try.BodyNotContains("MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7h"))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||
c.Assert(err, checker.IsNil)
|
||||
client = &http.Client{Transport: tr1}
|
||||
req.Host = tr1.TLSClientConfig.ServerName
|
||||
req.Header.Set("Host", tr1.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
resp, err = client.Do(req)
|
||||
c.Assert(err, checker.IsNil)
|
||||
cn = resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
c.Assert(cn, checker.Equals, "TRAEFIK DEFAULT CERT")
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ defaultEntryPoints = ["https"]
|
|||
[entryPoints.https]
|
||||
address = ":4443"
|
||||
[entryPoints.https.tls]
|
||||
[entryPoints.https02]
|
||||
address = ":8443"
|
||||
[entryPoints.https02.tls]
|
||||
|
||||
[web]
|
||||
address = ":8080"
|
||||
|
|
|
@ -353,7 +353,7 @@ func startTestServer(port string, statusCode int) (ts *httptest.Server) {
|
|||
return ts
|
||||
}
|
||||
|
||||
// TestWithSNIConfigRoute involves a client sending HTTPS requests with
|
||||
// TestWithSNIDynamicConfigRouteWithNoChange involves a client sending HTTPS requests with
|
||||
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
|
||||
// that traefik routes the requests to the expected backends thanks to given certificate if possible
|
||||
// otherwise thanks to the default one.
|
||||
|
@ -424,7 +424,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithNoChange(c *check.C) {
|
|||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNoContent)
|
||||
}
|
||||
|
||||
// TestWithSNIConfigRoute involves a client sending HTTPS requests with
|
||||
// TestWithSNIDynamicConfigRouteWithChange involves a client sending HTTPS requests with
|
||||
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
|
||||
// that traefik updates its configuration when the HTTPS configuration is modified and
|
||||
// it routes the requests to the expected backends thanks to given certificate if possible
|
||||
|
@ -479,7 +479,7 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithChange(c *check.C) {
|
|||
req.Header.Set("Accept", "*/*")
|
||||
|
||||
// Change certificates configuration file content
|
||||
modifyCertificateConfFileContent(c, tr1.TLSClientConfig.ServerName, dynamicConfFileName)
|
||||
modifyCertificateConfFileContent(c, tr1.TLSClientConfig.ServerName, dynamicConfFileName, "https")
|
||||
var resp *http.Response
|
||||
err = try.Do(30*time.Second, func() error {
|
||||
resp, err = client.Do(req)
|
||||
|
@ -525,29 +525,121 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithChange(c *check.C) {
|
|||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
||||
func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName string) {
|
||||
tlsConf := types.Configuration{
|
||||
TLSConfiguration: []*traefikTls.Configuration{
|
||||
{
|
||||
Certificate: &traefikTls.Certificate{
|
||||
CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
},
|
||||
},
|
||||
// TestWithSNIDynamicConfigRouteWithChangeForEmptyTlsConfiguration involves a client sending HTTPS requests with
|
||||
// SNI hostnames of "snitest.org" and "snitest.com". The test verifies
|
||||
// that traefik updates its configuration when the HTTPS configuration is modified, even if it totally deleted, and
|
||||
// it routes the requests to the expected backends thanks to given certificate if possible
|
||||
// otherwise thanks to the default one.
|
||||
func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithTlsConfigurationDeletion(c *check.C) {
|
||||
dynamicConfFileName := s.adaptFile(c, "fixtures/https/dynamic_https.toml", struct{}{})
|
||||
defer os.Remove(dynamicConfFileName)
|
||||
confFileName := s.adaptFile(c, "fixtures/https/dynamic_https_sni.toml", struct {
|
||||
DynamicConfFileName string
|
||||
}{
|
||||
DynamicConfFileName: dynamicConfFileName,
|
||||
})
|
||||
defer os.Remove(confFileName)
|
||||
cmd, display := s.traefikCmd(withConfigFile(confFileName))
|
||||
defer display(c)
|
||||
err := cmd.Start()
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
tr2 := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
ServerName: "snitest.org",
|
||||
},
|
||||
}
|
||||
var confBuffer bytes.Buffer
|
||||
e := toml.NewEncoder(&confBuffer)
|
||||
err := e.Encode(tlsConf)
|
||||
|
||||
// wait for Traefik
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/providers", 1*time.Second, try.BodyContains("Host:"+tr2.TLSClientConfig.ServerName))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||
|
||||
defer backend2.Close()
|
||||
|
||||
err = try.GetRequest(backend2.URL, 500*time.Millisecond, try.StatusCodeIs(http.StatusResetContent))
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||
client := &http.Client{Transport: tr2}
|
||||
req.Host = tr2.TLSClientConfig.ServerName
|
||||
req.Header.Set("Host", tr2.TLSClientConfig.ServerName)
|
||||
req.Header.Set("Accept", "*/*")
|
||||
|
||||
var resp *http.Response
|
||||
err = try.Do(30*time.Second, func() error {
|
||||
resp, err = client.Do(req)
|
||||
|
||||
// /!\ If connection is not closed, SSLHandshake will only be done during the first trial /!\
|
||||
req.Close = true
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cn := resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
if cn != tr2.TLSClientConfig.ServerName {
|
||||
return fmt.Errorf("domain %s found in place of %s", cn, tr2.TLSClientConfig.ServerName)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusResetContent)
|
||||
// Change certificates configuration file content
|
||||
modifyCertificateConfFileContent(c, "", dynamicConfFileName, "https02")
|
||||
|
||||
err = try.Do(60*time.Second, func() error {
|
||||
resp, err = client.Do(req)
|
||||
|
||||
// /!\ If connection is not closed, SSLHandshake will only be done during the first trial /!\
|
||||
req.Close = true
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cn := resp.TLS.PeerCertificates[0].Subject.CommonName
|
||||
if cn == tr2.TLSClientConfig.ServerName {
|
||||
return fmt.Errorf("domain %s found in place of default one", tr2.TLSClientConfig.ServerName)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
||||
func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName, entryPoint string) {
|
||||
f, err := os.OpenFile("./"+confFileName, os.O_WRONLY, os.ModeExclusive)
|
||||
c.Assert(err, checker.IsNil)
|
||||
defer func() {
|
||||
f.Close()
|
||||
}()
|
||||
f.Truncate(0)
|
||||
_, err = f.Write(confBuffer.Bytes())
|
||||
c.Assert(err, checker.IsNil)
|
||||
// If certificate file is not provided, just truncate the configuration file
|
||||
if len(certFileName) > 0 {
|
||||
tlsConf := types.Configuration{
|
||||
TLSConfiguration: []*traefikTls.Configuration{
|
||||
{
|
||||
Certificate: &traefikTls.Certificate{
|
||||
CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
},
|
||||
EntryPoints: []string{entryPoint},
|
||||
},
|
||||
},
|
||||
}
|
||||
var confBuffer bytes.Buffer
|
||||
e := toml.NewEncoder(&confBuffer)
|
||||
err := e.Encode(tlsConf)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
_, err = f.Write(confBuffer.Bytes())
|
||||
c.Assert(err, checker.IsNil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,25 @@ func BodyContains(values ...string) ResponseCondition {
|
|||
}
|
||||
}
|
||||
|
||||
// BodyNotContains returns a retry condition function.
|
||||
// The condition returns an error if the request body contain one of the given
|
||||
// strings.
|
||||
func BodyNotContains(values ...string) ResponseCondition {
|
||||
return func(res *http.Response) error {
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %s", err)
|
||||
}
|
||||
|
||||
for _, value := range values {
|
||||
if strings.Contains(string(body), value) {
|
||||
return fmt.Errorf("find '%s' in body '%s'", value, string(body))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// BodyContainsOr returns a retry condition function.
|
||||
// The condition returns an error if the request body does not contain one of the given
|
||||
// strings.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue