Allow deleting dynamically all TLS certificates from an entryPoint

This commit is contained in:
NicoMen 2017-12-21 14:16:03 +01:00 committed by Traefiker
parent 89a79d0f1b
commit 1e44e339ad
3 changed files with 101 additions and 6 deletions

View file

@ -6,6 +6,9 @@ defaultEntryPoints = ["https"]
[entryPoints.https] [entryPoints.https]
address = ":4443" address = ":4443"
[entryPoints.https.tls] [entryPoints.https.tls]
[entryPoints.https02]
address = ":8443"
[entryPoints.https02.tls]
[web] [web]
address = ":8080" address = ":8080"

View file

@ -353,7 +353,7 @@ func startTestServer(port string, statusCode int) (ts *httptest.Server) {
return ts 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 // 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 // that traefik routes the requests to the expected backends thanks to given certificate if possible
// otherwise thanks to the default one. // 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) 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 // SNI hostnames of "snitest.org" and "snitest.com". The test verifies
// that traefik updates its configuration when the HTTPS configuration is modified and // 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 // 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", "*/*") req.Header.Set("Accept", "*/*")
// Change certificates configuration file content // Change certificates configuration file content
modifyCertificateConfFileContent(c, tr1.TLSClientConfig.ServerName, dynamicConfFileName) modifyCertificateConfFileContent(c, tr1.TLSClientConfig.ServerName, dynamicConfFileName, "https")
var resp *http.Response var resp *http.Response
err = try.Do(30*time.Second, func() error { err = try.Do(30*time.Second, func() error {
resp, err = client.Do(req) resp, err = client.Do(req)
@ -525,8 +525,96 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithChange(c *check.C) {
c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound) c.Assert(resp.StatusCode, checker.Equals, http.StatusNotFound)
} }
// 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",
},
}
// 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, "snitest.com", 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. // modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName string) { func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName, entryPoint string) {
tlsConf := types.Configuration{ tlsConf := types.Configuration{
TLSConfiguration: []*traefikTls.Configuration{ TLSConfiguration: []*traefikTls.Configuration{
{ {
@ -534,7 +622,7 @@ func modifyCertificateConfFileContent(c *check.C, certFileName, confFileName str
CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"), CertFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"), KeyFile: traefikTls.FileOrContent("fixtures/https/" + certFileName + ".key"),
}, },
EntryPoints: []string{"https"}, EntryPoints: []string{entryPoint},
}, },
}, },
} }

View file

@ -439,7 +439,11 @@ func (s *Server) loadConfiguration(configMsg types.ConfigMessage) {
if err == nil { if err == nil {
for newServerEntryPointName, newServerEntryPoint := range newServerEntryPoints { for newServerEntryPointName, newServerEntryPoint := range newServerEntryPoints {
s.serverEntryPoints[newServerEntryPointName].httpRouter.UpdateHandler(newServerEntryPoint.httpRouter.GetHandler()) s.serverEntryPoints[newServerEntryPointName].httpRouter.UpdateHandler(newServerEntryPoint.httpRouter.GetHandler())
if &newServerEntryPoint.certs != nil { if s.globalConfiguration.EntryPoints[newServerEntryPointName].TLS == nil {
if newServerEntryPoint.certs.Get() != nil {
log.Debugf("Certificates not added to non-TLS entryPoint %s.", newServerEntryPointName)
}
} else {
s.serverEntryPoints[newServerEntryPointName].certs.Set(newServerEntryPoint.certs.Get()) s.serverEntryPoints[newServerEntryPointName].certs.Set(newServerEntryPoint.certs.Get())
} }
log.Infof("Server configuration reloaded on %s", s.serverEntryPoints[newServerEntryPointName].httpServer.Addr) log.Infof("Server configuration reloaded on %s", s.serverEntryPoints[newServerEntryPointName].httpServer.Addr)