Adds TLS SNI support for the frontends
This commit is contained in:
parent
1604786285
commit
d6e28a923c
11 changed files with 268 additions and 14 deletions
|
@ -16,7 +16,7 @@ type GlobalConfiguration struct {
|
||||||
GraceTimeOut int64
|
GraceTimeOut int64
|
||||||
AccessLogsFile string
|
AccessLogsFile string
|
||||||
TraefikLogsFile string
|
TraefikLogsFile string
|
||||||
CertFile, KeyFile string
|
Certificates []Certificate
|
||||||
LogLevel string
|
LogLevel string
|
||||||
ProvidersThrottleDuration time.Duration
|
ProvidersThrottleDuration time.Duration
|
||||||
Docker *provider.Docker
|
Docker *provider.Docker
|
||||||
|
@ -29,6 +29,12 @@ type GlobalConfiguration struct {
|
||||||
Boltdb *provider.BoltDb
|
Boltdb *provider.BoltDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Certificate holds a SSL cert/key pair
|
||||||
|
type Certificate struct {
|
||||||
|
CertFile string
|
||||||
|
KeyFile string
|
||||||
|
}
|
||||||
|
|
||||||
// NewGlobalConfiguration returns a GlobalConfiguration with default values.
|
// NewGlobalConfiguration returns a GlobalConfiguration with default values.
|
||||||
func NewGlobalConfiguration() *GlobalConfiguration {
|
func NewGlobalConfiguration() *GlobalConfiguration {
|
||||||
globalConfiguration := new(GlobalConfiguration)
|
globalConfiguration := new(GlobalConfiguration)
|
||||||
|
|
|
@ -102,10 +102,12 @@ For example:
|
||||||
#
|
#
|
||||||
# logLevel = "ERROR"
|
# logLevel = "ERROR"
|
||||||
|
|
||||||
# SSL certificate and key used
|
# SSL certificates and keys
|
||||||
|
# You may add several certificate/key pairs to terminate HTTPS for multiple domain names using TLS SNI
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
|
# [[certificates]]
|
||||||
# CertFile = "traefik.crt"
|
# CertFile = "traefik.crt"
|
||||||
# KeyFile = "traefik.key"
|
# KeyFile = "traefik.key"
|
||||||
|
|
||||||
|
|
32
integration/fixtures/https/https_sni.toml
Normal file
32
integration/fixtures/https/https_sni.toml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
port = ":443"
|
||||||
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[[certificates]]
|
||||||
|
CertFile = "fixtures/https/snitest.com.cert"
|
||||||
|
KeyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
|
[[certificates]]
|
||||||
|
CertFile = "fixtures/https/snitest.org.cert"
|
||||||
|
KeyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
[file]
|
||||||
|
|
||||||
|
[backends]
|
||||||
|
[backends.backend1]
|
||||||
|
[backends.backend1.servers.server1]
|
||||||
|
url = "http://127.0.0.1:9010"
|
||||||
|
[backends.backend2]
|
||||||
|
[backends.backend2.servers.server1]
|
||||||
|
url = "http://127.0.0.1:9020"
|
||||||
|
|
||||||
|
[frontends]
|
||||||
|
[frontends.frontend1]
|
||||||
|
backend = "backend1"
|
||||||
|
[frontends.frontend1.routes.test_1]
|
||||||
|
rule = "Host"
|
||||||
|
value = "snitest.com"
|
||||||
|
[frontends.frontend2]
|
||||||
|
backend = "backend2"
|
||||||
|
[frontends.frontend2.routes.test_2]
|
||||||
|
rule = "Host"
|
||||||
|
value = "snitest.org"
|
19
integration/fixtures/https/snitest.com.cert
Normal file
19
integration/fixtures/https/snitest.com.cert
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC/zCCAeegAwIBAgIJAL858pci5XyjMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
|
||||||
|
BAMMC3NuaXRlc3QuY29tMB4XDTE1MTEyMzIyMDU1NloXDTI1MTEyMDIyMDU1Nlow
|
||||||
|
FjEUMBIGA1UEAwwLc25pdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||||
|
ggEKAoIBAQDVF25wEroSIUO/dNgHxlyt8pZFVpJ8fNaJw7cnlZ1JP2hLuEbmjAFT
|
||||||
|
dHqS8wKDNYHktsBEOUfN/qbk0AiGb+SvhQw6kfM/QSj9fXVQ7KhYP9XYOekTOH7d
|
||||||
|
M0Z2L3RGgqs8z+83exOOnAFVvIJCMZJXEeijV6iJlmpCcJa0Kg/JHlxhoWTEeZuU
|
||||||
|
G+hITafk1yWOKorTCPlMhB30wuQoWfbHP+3G0bsERLXFiMANE8EtQu8+ZhfseBUh
|
||||||
|
5Tu5gIC4Fnria7mRixAZeEiAblFP9h0vrNRcP3nmuVz0tHPIeQsJQiEhxaZ09oUW
|
||||||
|
h9WqTsYCP1821+SVazM9oFRTpy6chZyTAgMBAAGjUDBOMB0GA1UdDgQWBBSz9mbX
|
||||||
|
ia1TM5FG4Zgagaet24S8HDAfBgNVHSMEGDAWgBSz9mbXia1TM5FG4Zgagaet24S8
|
||||||
|
HDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQB79W8XTxlozh9w/W7T
|
||||||
|
5vDev67G4T/wetABSb68CRrqojt78PMJuS89JarA8I3ts00O+0JYnsHxp+9qC7pf
|
||||||
|
jWHcDSiLwRUMu7MXW/KIen1EB8BQNA0xWbAiQaWYPHzsBlX48+9wBe0HTDx7Lcxb
|
||||||
|
OsmnXHBF5fd2EY+R8qJu+PyTDDL1WLItFJpzHiFiGiYF8Tyic3kkPjje6eIOxRmT
|
||||||
|
hq+qbwApzbzz6h/VD5xR3zBDFBo2Xs5tdP264KIw/YXDpaXVBiJ5DDjQ3dtJw1G5
|
||||||
|
yzgrHQZWJN8Gs8ZZgGdgRf7PHox8xEZtqPiMkChDz6T7Ha3U0xYN6TZGNZOR6DHs
|
||||||
|
K9/8
|
||||||
|
-----END CERTIFICATE-----
|
27
integration/fixtures/https/snitest.com.key
Normal file
27
integration/fixtures/https/snitest.com.key
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEA1RducBK6EiFDv3TYB8ZcrfKWRVaSfHzWicO3J5WdST9oS7hG
|
||||||
|
5owBU3R6kvMCgzWB5LbARDlHzf6m5NAIhm/kr4UMOpHzP0Eo/X11UOyoWD/V2Dnp
|
||||||
|
Ezh+3TNGdi90RoKrPM/vN3sTjpwBVbyCQjGSVxHoo1eoiZZqQnCWtCoPyR5cYaFk
|
||||||
|
xHmblBvoSE2n5NcljiqK0wj5TIQd9MLkKFn2xz/txtG7BES1xYjADRPBLULvPmYX
|
||||||
|
7HgVIeU7uYCAuBZ64mu5kYsQGXhIgG5RT/YdL6zUXD955rlc9LRzyHkLCUIhIcWm
|
||||||
|
dPaFFofVqk7GAj9fNtfklWszPaBUU6cunIWckwIDAQABAoIBABAdQYDAKcoNMe5c
|
||||||
|
i6mq2n9dBPghX9qCJkcswcEAk3BilySCvvnYRJFnEY3jSqFZfoUpPMjr+/4b78sF
|
||||||
|
4F8qPwT27sHPH7H833ir8B86hlCGI0nCt1l4wD9CDWYKmKRsZT6oCtMLP6NdMMyn
|
||||||
|
AMK4tPRYqlsP2fLtqQN1ODBPrfnraoNHtOVE784iBCD5dewICA5RIQG2i/d2+CGF
|
||||||
|
+bahFqUXVCqHoxBz4AVvrRFL99VcP7P2iZyk6hDQ7fci7Xay8Wb/HutRxuqvF0aU
|
||||||
|
bG6Enk6CCtNZHLwNPp4Hqft0Udvg2tG8okYwbEmoEO40nQsCSzRCpq5Uvzi+LX1k
|
||||||
|
LykQ6+ECgYEA7x8vQoyOK60Q3LPpJFGDec2+XJPoesTfJTT6idaP7ukUL8p3FsUo
|
||||||
|
9vtxRRfhSOdPoAINmrL0TyMekO2B6zXx0pmWVpMrFwZW6zMwZAnLp/w+3USpbGCy
|
||||||
|
K12IIwvRYzTzKwoMTVAKTXm36b6oqr2La4bTdJR7REY6G374FrJb/H0CgYEA5CHk
|
||||||
|
Ym0h7cf00fw9UEHRfzUZxmCfRWY6K8InOuHdLi+u4TiyXzs8x5s0e/DN/raNmTGx
|
||||||
|
QO81UzuS3nKwc4n5QyXjVnhzR5DbbSACDwHtdnxZByL0D1KvPjtRF8F+rWXViXv2
|
||||||
|
TM7UiOmn6R375FPSAPxeyMx8Womc3EnAAfLWGk8CgYEAv8I2WBv3dzcWqqbsdF+a
|
||||||
|
G/fOjNdgO/PdLy1JLXiPfHwV4C1xSyVZMJd7wnjgBWLaC+sZldGk8kGrpXWSFlnw
|
||||||
|
T38zfMIQcCp5Uax/RfpFA7XZhAAoDe2NdBFRtyknBXPU/dLVArsJSBAwWJa5FBNk
|
||||||
|
1xoMQRVBtQLMXnh341utQNECgYEA4o1R2/ka16NaWmpPjXM/lD9skFgF84p4vFn8
|
||||||
|
UXpaB3LtDdcbNH2Ed4mHToouWAR8jCUQLTcg0r53tRdaafMcKfXnVUka2nhdoHpH
|
||||||
|
8RVt99u3IeIxU0I+q+OGPbw3jAV0UStcxpwj7q9zw4q2SuJ+y+HUUz7XQ6Yjs5Q9
|
||||||
|
7PF2c/sCgYEAhdVn5gZ5FvYKrBi46t3pxPsWK476HmQEVHVi5+od7wg+araDelAe
|
||||||
|
8QE8hc8qdZGbjdB/AHSPCeUxfO2vnpsCoSRs29o6pDvQuqvHYs+M53l5LEYeOjof
|
||||||
|
t6J/DK5Pim2CAFjYFcZk8/Gyl5HjTw3PpdWxoPD5v2Xw3bbY57IIbm4=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
19
integration/fixtures/https/snitest.org.cert
Normal file
19
integration/fixtures/https/snitest.org.cert
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC/zCCAeegAwIBAgIJALAYHG/vGqWEMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV
|
||||||
|
BAMMC3NuaXRlc3Qub3JnMB4XDTE1MTEyMzIyMDU0NFoXDTI1MTEyMDIyMDU0NFow
|
||||||
|
FjEUMBIGA1UEAwwLc25pdGVzdC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||||
|
ggEKAoIBAQC8b2Qv68Xnv4wgJ6HNupxABSUA5KXmv9g7pwwsFMSOK15o2qGFzx/x
|
||||||
|
9loIi5pMIYIy4SVwJNrYUi772nCYMqSIVXlwct/CE70j2Jb2geIHu3jHbFWXruWb
|
||||||
|
W1tGGUYzvnsOUziPE3rLWa/NObNYLLlUKJaxfHrxnpuKpQUsXzoLl25cJEVr4jg2
|
||||||
|
ZITpdraxaBLisdlWY7EwwHBLu2nxH5Rn+nIjenFfdUwKF9s5dGy63tfBc8LX9yJk
|
||||||
|
+kOwy1al/Wxa0DUb6rSt0QDCcD+rXnjk2zWPtsHz1btwtqM+FLtN5z0Lmnx7DF3C
|
||||||
|
tCf1TMzduzZ6aeHk77zc664ZQun5cH33AgMBAAGjUDBOMB0GA1UdDgQWBBRn/nNz
|
||||||
|
PUsmDKmKv3GGo3km5KKvUDAfBgNVHSMEGDAWgBRn/nNzPUsmDKmKv3GGo3km5KKv
|
||||||
|
UDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBkuutIcbBdESgvNLLr
|
||||||
|
k/8HUDuFm72lYHZFE+c76CxqYN52w02NCTiq1InoDUvqZXb/StATBwRRduTUPCj9
|
||||||
|
KUkC7pOjAFxjzjExsHrtZSq01WinrxNI+qSKvI8jFngMHnwN1omTt7/D7nxeW5Of
|
||||||
|
FJTkElnxtELAGHoIwZ+bKprnexefpn9UW84VJvJ2crSR63vBvdTrgsrEGW6kQj1I
|
||||||
|
62laDpax4+x8t2h+sfG6uNIA1cFrG8Sk+O2Bi3ogB7Y/4e8r6WA23IRP+aSv0J2b
|
||||||
|
k5fvuuXbIc979pQOoO03zG0S7Wpmpsw+9dQB9TOxGITOLfCZwEuIhnv+M9lLqCks
|
||||||
|
7H2A
|
||||||
|
-----END CERTIFICATE-----
|
27
integration/fixtures/https/snitest.org.key
Normal file
27
integration/fixtures/https/snitest.org.key
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEAvG9kL+vF57+MICehzbqcQAUlAOSl5r/YO6cMLBTEjiteaNqh
|
||||||
|
hc8f8fZaCIuaTCGCMuElcCTa2FIu+9pwmDKkiFV5cHLfwhO9I9iW9oHiB7t4x2xV
|
||||||
|
l67lm1tbRhlGM757DlM4jxN6y1mvzTmzWCy5VCiWsXx68Z6biqUFLF86C5duXCRF
|
||||||
|
a+I4NmSE6Xa2sWgS4rHZVmOxMMBwS7tp8R+UZ/pyI3pxX3VMChfbOXRsut7XwXPC
|
||||||
|
1/ciZPpDsMtWpf1sWtA1G+q0rdEAwnA/q1545Ns1j7bB89W7cLajPhS7Tec9C5p8
|
||||||
|
ewxdwrQn9UzM3bs2emnh5O+83OuuGULp+XB99wIDAQABAoIBAGOn9bByXQQnhZAr
|
||||||
|
5aLMIn6pOdyzEBptM4q42fMmOJ2HyjJiDjKaTCbHRu5mBoBk6FrIP+iDVUo6jKad
|
||||||
|
7BZSEjoYGlWiKzyU+97NWWmdX1D/kOzHGq1RzhTPyAHWtA4Bm0sEMFFa2AJbuGIt
|
||||||
|
NfBYFtuva6MKVmsamuBETewdoLEnxzzDFcuOaxXRfTC/ikWcYyB4KEWA5fjroUQC
|
||||||
|
Llo9/UTGTkh1Hynv9AXY6Qia/RbrIQjKveKCRj6PjxyE/qN9qfmngczz2pK0hRhL
|
||||||
|
Z+K06y8G+Yj1I1zm5jNg1kakVQKoBsnaYkmIUBUSmWv6ERotedOWtOAMlOKa+0l2
|
||||||
|
DS7Ou2ECgYEA91doi+3XrMVsgyTEm/ArzEyRUfM5dCSvBCRFhO7QQp2OYAbjJk5S
|
||||||
|
pmdpqmwTsXNNMU+XNkWCLug5pk0PTJwP0mVLE2fLYqCCXoyaMltQ0Yk2gaun/RwE
|
||||||
|
w5EfyMwOQakLFY/ODvduQfyNpaoWgFz4/WPNTVNCGs04LepSGKaFNy0CgYEAwwgV
|
||||||
|
jKeFA+QZGooTInyk07ZlAbenEPu/c2y3UUFxclP0CjP2/VBOpz9B62vhzCKbjD1c
|
||||||
|
/L3x1CKC4n4lbeyHi4vrF69LX9SHr1Jm0SUtyKeV3g0EAzIWI0HFhVUkMvtbibQ4
|
||||||
|
HXrLVCJO77xetQ7RQszss1z9g3WotAAiBMiQgDMCgYBTLjoilOIrYFmV4Q+dwa95
|
||||||
|
DWbxwHJZ9NxG8EvQ4N95B7OR578Matqwy6ZlgeM9kiErrDCWN9oIHGEG5HN4uCM6
|
||||||
|
BoaxB/8GNCSj13Uj6kHLtfF2ulvMa1fOzUd7J+TDgC4SGkKaFewmlOCuDf1zPdEe
|
||||||
|
pimtD4rzqIB0MJFbaOT0IQKBgDBPjlb7IB3ooLdMQJUoXwP6iGa2gXHZioEjCv3b
|
||||||
|
wihZ13e3i5UQEYuoRcH1RUd1wyYoBSKuQnsT2WwVZ1wlXSYaELAbQgaI9NtfBA0G
|
||||||
|
sqKjsKICg13vSECPiEgQ4Rin3vLra4MR6c/7d6Y2+RbMhtWPQYrkm/+2Y4XDCqo4
|
||||||
|
rGK1AoGAOFZ3RVhuwXzFdKNe32LM1wm1eZ7waxjI4bQS2xUN/3C/uWS7A3LaSlc3
|
||||||
|
eRG3DaVpez4DQVupZDHMgxJUYqqKynUj6GD1YiaxGROj3TYCu6e7OxyhalhCllSu
|
||||||
|
w/X5M802XqzLjeec5zHoZDfknnAkgR9MsxZYmZPFaDyL6GOKUB8=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
110
integration/https_test.go
Normal file
110
integration/https_test.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os/exec"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
checker "github.com/vdemeester/shakers"
|
||||||
|
check "gopkg.in/check.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPSSuite
|
||||||
|
type HTTPSSuite struct{ BaseSuite }
|
||||||
|
|
||||||
|
// TestWithSNIConfigHandshake involves a client sending a SNI hostname of
|
||||||
|
// "snitest.com", which happens to match the CN of 'snitest.com.crt'. The test
|
||||||
|
// verifies that traefik presents the correct certificate.
|
||||||
|
func (s *HTTPSSuite) TestWithSNIConfigHandshake(c *check.C) {
|
||||||
|
cmd := exec.Command(traefikBinary, "fixtures/https/https_sni.toml")
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: "snitest.com",
|
||||||
|
}
|
||||||
|
conn, err := tls.Dial("tcp", "127.0.0.1:443", 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"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWithSNIConfigRoute 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.
|
||||||
|
func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
|
||||||
|
cmd := exec.Command(traefikBinary, "fixtures/https/https_sni.toml")
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
backend1 := startTestServer("9010", 204)
|
||||||
|
backend2 := startTestServer("9020", 205)
|
||||||
|
defer backend1.Close()
|
||||||
|
defer backend2.Close()
|
||||||
|
|
||||||
|
time.Sleep(2000 * time.Millisecond)
|
||||||
|
|
||||||
|
tr1 := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: "snitest.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tr2 := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: "snitest.org",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &http.Client{Transport: tr1}
|
||||||
|
req, _ := http.NewRequest("GET", "https://127.0.0.1/", nil)
|
||||||
|
req.Host = "snitest.com"
|
||||||
|
req.Header.Set("Host", "snitest.com")
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
// Expected a 204 (from backend1)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 204)
|
||||||
|
|
||||||
|
client = &http.Client{Transport: tr2}
|
||||||
|
req, _ = http.NewRequest("GET", "https://127.0.0.1/", nil)
|
||||||
|
req.Host = "snitest.org"
|
||||||
|
req.Header.Set("Host", "snitest.org")
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
// Expected a 205 (from backend2)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 205)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTestServer(port string, statusCode int) (ts *httptest.Server) {
|
||||||
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(statusCode)
|
||||||
|
})
|
||||||
|
listener, err := net.Listen("tcp", "127.0.0.1:"+port)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts = &httptest.Server{
|
||||||
|
Listener: listener,
|
||||||
|
Config: &http.Server{Handler: handler},
|
||||||
|
}
|
||||||
|
ts.Start()
|
||||||
|
return
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ func Test(t *testing.T) {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
check.Suite(&SimpleSuite{})
|
check.Suite(&SimpleSuite{})
|
||||||
|
check.Suite(&HTTPSSuite{})
|
||||||
check.Suite(&FileSuite{})
|
check.Suite(&FileSuite{})
|
||||||
check.Suite(&DockerSuite{})
|
check.Suite(&DockerSuite{})
|
||||||
check.Suite(&ConsulSuite{})
|
check.Suite(&ConsulSuite{})
|
||||||
|
|
31
traefik.go
31
traefik.go
|
@ -209,35 +209,43 @@ func main() {
|
||||||
log.Fatal("Error preparing server: ", er)
|
log.Fatal("Error preparing server: ", er)
|
||||||
}
|
}
|
||||||
go startServer(srv, globalConfiguration)
|
go startServer(srv, globalConfiguration)
|
||||||
|
//TODO change that!
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
serverLock.Unlock()
|
serverLock.Unlock()
|
||||||
|
|
||||||
<-stopChan
|
<-stopChan
|
||||||
log.Info("Shutting down")
|
log.Info("Shutting down")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTLSConfig(certFile string, keyFile string) (*tls.Config, error) {
|
// creates a TLS config that allows terminating HTTPS for multiple domains using SNI
|
||||||
|
func createTLSConfig(certs []Certificate) (*tls.Config, error) {
|
||||||
|
if len(certs) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
config := &tls.Config{}
|
config := &tls.Config{}
|
||||||
if config.NextProtos == nil {
|
if config.NextProtos == nil {
|
||||||
config.NextProtos = []string{"http/1.1"}
|
config.NextProtos = []string{"http/1.1"}
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
config.Certificates = make([]tls.Certificate, 1)
|
config.Certificates = make([]tls.Certificate, len(certs))
|
||||||
if len(certFile) > 0 && len(keyFile) > 0 {
|
for i, v := range certs {
|
||||||
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
|
config.Certificates[i], err = tls.LoadX509KeyPair(v.CertFile, v.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
// BuildNameToCertificate parses the CommonName and SubjectAlternateName fields
|
||||||
|
// in each certificate and populates the config.NameToCertificate map.
|
||||||
|
config.BuildNameToCertificate()
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startServer(srv *manners.GracefulServer, globalConfiguration *GlobalConfiguration) {
|
func startServer(srv *manners.GracefulServer, globalConfiguration *GlobalConfiguration) {
|
||||||
log.Info("Starting server")
|
log.Info("Starting server")
|
||||||
if len(globalConfiguration.CertFile) > 0 && len(globalConfiguration.KeyFile) > 0 {
|
if srv.TLSConfig != nil {
|
||||||
err := srv.ListenAndServeTLS(globalConfiguration.CertFile, globalConfiguration.KeyFile)
|
err := srv.ListenAndServeTLSWithConfig(srv.TLSConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error creating server: ", err)
|
log.Fatal("Error creating server: ", err)
|
||||||
}
|
}
|
||||||
|
@ -258,7 +266,7 @@ func prepareServer(router *mux.Router, globalConfiguration *GlobalConfiguration,
|
||||||
negroni.Use(middleware)
|
negroni.Use(middleware)
|
||||||
}
|
}
|
||||||
negroni.UseHandler(router)
|
negroni.UseHandler(router)
|
||||||
tlsConfig, err := createTLSConfig(globalConfiguration.CertFile, globalConfiguration.KeyFile)
|
tlsConfig, err := createTLSConfig(globalConfiguration.Certificates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error creating TLS config %s", err)
|
log.Fatalf("Error creating TLS config %s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -273,8 +281,9 @@ func prepareServer(router *mux.Router, globalConfiguration *GlobalConfiguration,
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
server, err := oldServer.HijackListener(&http.Server{
|
server, err := oldServer.HijackListener(&http.Server{
|
||||||
Addr: globalConfiguration.Port,
|
Addr: globalConfiguration.Port,
|
||||||
Handler: negroni,
|
Handler: negroni,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
}, tlsConfig)
|
}, tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error hijacking server %s", err)
|
log.Fatalf("Error hijacking server %s", err)
|
||||||
|
|
|
@ -37,10 +37,12 @@
|
||||||
#
|
#
|
||||||
# logLevel = "ERROR"
|
# logLevel = "ERROR"
|
||||||
|
|
||||||
# SSL certificate and key used
|
# SSL certificates and keys
|
||||||
|
# You may add several certificate/key pairs to terminate HTTPS for multiple domain names using TLS SNI
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
|
# [[certificates]]
|
||||||
# CertFile = "traefik.crt"
|
# CertFile = "traefik.crt"
|
||||||
# KeyFile = "traefik.key"
|
# KeyFile = "traefik.key"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue