Define TLS options on the Router configuration
Co-authored-by: juliens <julien@containo.us>
This commit is contained in:
parent
d306c8fd50
commit
85ce16b34f
24 changed files with 958 additions and 148 deletions
|
@ -9,6 +9,7 @@
|
||||||
Rule = "foobar"
|
Rule = "foobar"
|
||||||
priority = 42
|
priority = 42
|
||||||
[HTTP.Routers.Router0.tls]
|
[HTTP.Routers.Router0.tls]
|
||||||
|
options = "TLS0"
|
||||||
|
|
||||||
[HTTP.Middlewares]
|
[HTTP.Middlewares]
|
||||||
|
|
||||||
|
@ -206,6 +207,7 @@
|
||||||
Rule = "foobar"
|
Rule = "foobar"
|
||||||
[TCP.Routers.TCPRouter0.tls]
|
[TCP.Routers.TCPRouter0.tls]
|
||||||
passthrough = true
|
passthrough = true
|
||||||
|
options = "TLS1"
|
||||||
|
|
||||||
[TCP.Services]
|
[TCP.Services]
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ labels:
|
||||||
- "traefik.HTTP.Routers.Router0.Rule=foobar"
|
- "traefik.HTTP.Routers.Router0.Rule=foobar"
|
||||||
- "traefik.HTTP.Routers.Router0.Service=foobar"
|
- "traefik.HTTP.Routers.Router0.Service=foobar"
|
||||||
- "traefik.HTTP.Routers.Router0.TLS=true"
|
- "traefik.HTTP.Routers.Router0.TLS=true"
|
||||||
|
- "traefik.HTTP.Routers.Router0.TLS.options=foo"
|
||||||
- "traefik.HTTP.Routers.Router1.EntryPoints=foobar, fiibar"
|
- "traefik.HTTP.Routers.Router1.EntryPoints=foobar, fiibar"
|
||||||
- "traefik.HTTP.Routers.Router1.Middlewares=foobar, fiibar"
|
- "traefik.HTTP.Routers.Router1.Middlewares=foobar, fiibar"
|
||||||
- "traefik.HTTP.Routers.Router1.Priority=42"
|
- "traefik.HTTP.Routers.Router1.Priority=42"
|
||||||
|
@ -143,9 +144,11 @@ labels:
|
||||||
- "traefik.TCP.Routers.Router0.EntryPoints=foobar, fiibar"
|
- "traefik.TCP.Routers.Router0.EntryPoints=foobar, fiibar"
|
||||||
- "traefik.TCP.Routers.Router0.Service=foobar"
|
- "traefik.TCP.Routers.Router0.Service=foobar"
|
||||||
- "traefik.TCP.Routers.Router0.TLS.Passthrough=false"
|
- "traefik.TCP.Routers.Router0.TLS.Passthrough=false"
|
||||||
|
- "traefik.TCP.Routers.Router0.TLS.options=bar"
|
||||||
- "traefik.TCP.Routers.Router1.Rule=foobar"
|
- "traefik.TCP.Routers.Router1.Rule=foobar"
|
||||||
- "traefik.TCP.Routers.Router1.EntryPoints=foobar, fiibar"
|
- "traefik.TCP.Routers.Router1.EntryPoints=foobar, fiibar"
|
||||||
- "traefik.TCP.Routers.Router1.Service=foobar"
|
- "traefik.TCP.Routers.Router1.Service=foobar"
|
||||||
- "traefik.TCP.Routers.Router1.TLS.Passthrough=false"
|
- "traefik.TCP.Routers.Router1.TLS.Passthrough=false"
|
||||||
|
- "traefik.TCP.Routers.Router1.TLS.options=foobar"
|
||||||
- "traefik.TCP.Services.Service0.LoadBalancer.server.Port=42"
|
- "traefik.TCP.Services.Service0.LoadBalancer.server.Port=42"
|
||||||
- "traefik.TCP.Services.Service1.LoadBalancer.server.Port=42"
|
- "traefik.TCP.Services.Service1.LoadBalancer.server.Port=42"
|
||||||
|
|
|
@ -156,7 +156,9 @@ Services are the target for the router.
|
||||||
|
|
||||||
### TLS
|
### TLS
|
||||||
|
|
||||||
When specifying a TLS section, you tell Traefik that the current router is dedicated to HTTPS requests only (and that the router should ignore HTTP (non tls) requests).
|
#### General
|
||||||
|
|
||||||
|
When a TLS section is specified, it instructs Traefik that the current router is dedicated to HTTPS requests only (and that the router should ignore HTTP (non TLS) requests).
|
||||||
Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services).
|
Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services).
|
||||||
|
|
||||||
??? example "Configuring the router to accept HTTPS requests only"
|
??? example "Configuring the router to accept HTTPS requests only"
|
||||||
|
@ -172,8 +174,7 @@ Traefik will terminate the SSL connections (meaning that it will send decrypted
|
||||||
!!! note "HTTPS & ACME"
|
!!! note "HTTPS & ACME"
|
||||||
|
|
||||||
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
||||||
In the near future, options will be available to enable fine-grain control of the TLS parameters.
|
|
||||||
|
|
||||||
!!! note "Passthrough"
|
!!! note "Passthrough"
|
||||||
|
|
||||||
On TCP routers, you can configure a passthrough option so that Traefik doesn't terminate the TLS connection.
|
On TCP routers, you can configure a passthrough option so that Traefik doesn't terminate the TLS connection.
|
||||||
|
@ -196,6 +197,31 @@ Traefik will terminate the SSL connections (meaning that it will send decrypted
|
||||||
service = "service-id"
|
service = "service-id"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `Options`
|
||||||
|
|
||||||
|
The `Options` field enables fine-grained control of the TLS parameters.
|
||||||
|
It refers to a [tlsOptions](../../https-tls/overview/#configuration-options) and will be applied only if a `Host` rule is defined.
|
||||||
|
|
||||||
|
??? example "Configuring the tls options"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.Router-1]
|
||||||
|
rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
|
||||||
|
service = "service-id"
|
||||||
|
[http.routers.Router-1.tls] # will terminate the TLS request
|
||||||
|
options = "foo"
|
||||||
|
|
||||||
|
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.foo]
|
||||||
|
minVersion = "VersionTLS12"
|
||||||
|
cipherSuites = [
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## Configuring TCP Routers
|
## Configuring TCP Routers
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
@ -269,8 +295,10 @@ Services are the target for the router.
|
||||||
|
|
||||||
### TLS
|
### TLS
|
||||||
|
|
||||||
When specifying a TLS section, you tell Traefik that the current router is dedicated to TLS requests only (and that the router should ignore non-tls requests).
|
#### General
|
||||||
By default, Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services), but you can tell Traefik that the request should pass through (keeping the encrypted data) and be forwarded to the service "as is".
|
|
||||||
|
When a TLS section is specified, it instructs Traefik that the current router is dedicated to TLS requests only (and that the router should ignore non-TLS requests).
|
||||||
|
By default, Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services), but Traefik can be configured in order to let the requests pass through (keeping the data encrypted), and be forwarded to the service "as is".
|
||||||
|
|
||||||
??? example "Configuring TLS Termination"
|
??? example "Configuring TLS Termination"
|
||||||
|
|
||||||
|
@ -296,4 +324,28 @@ By default, Traefik will terminate the SSL connections (meaning that it will sen
|
||||||
!!! note "TLS & ACME"
|
!!! note "TLS & ACME"
|
||||||
|
|
||||||
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
In the current version, with [ACME](../../https-tls/acme.md) enabled, automatic certificate generation will apply to every router declaring a TLS section.
|
||||||
In the near future, options will be available to enable fine-grain control of the TLS parameters.
|
|
||||||
|
#### `Options`
|
||||||
|
|
||||||
|
The `Options` field enables fine-grained control of the TLS parameters.
|
||||||
|
It refers to a [tlsOptions](../../https-tls/overview/#configuration-options) and will be applied only if a `HostSNI` rule is defined.
|
||||||
|
|
||||||
|
??? example "Configuring the tls options"
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.Router-1]
|
||||||
|
rule = "Host(`foo-domain`) && Path(`/foo-path/`)"
|
||||||
|
service = "service-id"
|
||||||
|
[tcp.routers.Router-1.tls] # will terminate the TLS request
|
||||||
|
options = "foo"
|
||||||
|
|
||||||
|
|
||||||
|
[tlsOptions]
|
||||||
|
[tlsOptions.foo]
|
||||||
|
minVersion = "VersionTLS12"
|
||||||
|
cipherSuites = [
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_RSA_WITH_AES_256_GCM_SHA384"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
62
integration/fixtures/https/https_tls_options.toml
Normal file
62
integration/fixtures/https/https_tls_options.toml
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.web-secure]
|
||||||
|
address = ":4443"
|
||||||
|
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
|
[http.routers]
|
||||||
|
[http.routers.router1]
|
||||||
|
Service = "service1"
|
||||||
|
Rule = "Host(`snitest.com`)"
|
||||||
|
[http.routers.router1.tls]
|
||||||
|
options = "foo"
|
||||||
|
|
||||||
|
[http.routers.router2]
|
||||||
|
Service = "service2"
|
||||||
|
Rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router2.tls]
|
||||||
|
options = "bar"
|
||||||
|
|
||||||
|
[http.routers.router3]
|
||||||
|
Service = "service2"
|
||||||
|
Rule = "Host(`snitest.org`)"
|
||||||
|
[http.routers.router3.tls]
|
||||||
|
options = "unknown"
|
||||||
|
|
||||||
|
[http.services]
|
||||||
|
[http.services.service1]
|
||||||
|
[http.services.service1.LoadBalancer]
|
||||||
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
|
URL = "http://127.0.0.1:9010"
|
||||||
|
|
||||||
|
[http.services.service2]
|
||||||
|
[http.services.service2.LoadBalancer]
|
||||||
|
[[http.services.service2.LoadBalancer.Servers]]
|
||||||
|
URL = "http://127.0.0.1:9020"
|
||||||
|
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.com.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.com.key"
|
||||||
|
|
||||||
|
[[tls]]
|
||||||
|
[tls.certificate]
|
||||||
|
certFile = "fixtures/https/snitest.org.cert"
|
||||||
|
keyFile = "fixtures/https/snitest.org.key"
|
||||||
|
|
||||||
|
[tlsoptions.foo]
|
||||||
|
minversion = "VersionTLS11"
|
||||||
|
|
||||||
|
[tlsoptions.bar]
|
||||||
|
minversion = "VersionTLS12"
|
|
@ -2,12 +2,19 @@
|
||||||
checkNewVersion = false
|
checkNewVersion = false
|
||||||
sendAnonymousUsage = false
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[api]
|
||||||
|
entrypoint="api"
|
||||||
|
|
||||||
[log]
|
[log]
|
||||||
level = "DEBUG"
|
level = "DEBUG"
|
||||||
|
|
||||||
[entryPoints]
|
[entryPoints]
|
||||||
[entryPoints.web]
|
[entryPoints.web]
|
||||||
address = ":80"
|
address = ":8081"
|
||||||
|
|
||||||
|
|
||||||
|
[entryPoints.api]
|
||||||
|
address = ":8080"
|
||||||
|
|
||||||
[providers]
|
[providers]
|
||||||
[providers.file]
|
[providers.file]
|
||||||
|
|
|
@ -38,4 +38,3 @@ level = "DEBUG"
|
||||||
[http.services.whoami.loadbalancer]
|
[http.services.whoami.loadbalancer]
|
||||||
[[http.services.whoami.loadbalancer.servers]]
|
[[http.services.whoami.loadbalancer.servers]]
|
||||||
url = "http://localhost:8085"
|
url = "http://localhost:8085"
|
||||||
weight=1
|
|
||||||
|
|
42
integration/fixtures/tcp/multi-tls-options.toml
Normal file
42
integration/fixtures/tcp/multi-tls-options.toml
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
[global]
|
||||||
|
checkNewVersion = false
|
||||||
|
sendAnonymousUsage = false
|
||||||
|
|
||||||
|
[log]
|
||||||
|
level = "DEBUG"
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.tcp]
|
||||||
|
address = ":8093"
|
||||||
|
|
||||||
|
[api]
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
|
[tcp]
|
||||||
|
[tcp.routers]
|
||||||
|
[tcp.routers.to-whoami-no-cert]
|
||||||
|
rule = "HostSNI(`whoami-c.test`)"
|
||||||
|
service = "whoami-no-cert"
|
||||||
|
entryPoints = [ "tcp" ]
|
||||||
|
[tcp.routers.to-whoami-no-cert.tls]
|
||||||
|
options = "foo"
|
||||||
|
|
||||||
|
[tcp.routers.to-whoami-sni-strict]
|
||||||
|
rule = "HostSNI(`whoami-d.test`)"
|
||||||
|
service = "whoami-no-cert"
|
||||||
|
entryPoints = [ "tcp" ]
|
||||||
|
[tcp.routers.to-whoami-sni-strict.tls]
|
||||||
|
options = "bar"
|
||||||
|
|
||||||
|
[tcp.services.whoami-no-cert]
|
||||||
|
[tcp.services.whoami-no-cert.loadbalancer]
|
||||||
|
method = "wrr"
|
||||||
|
[[tcp.services.whoami-no-cert.loadbalancer.servers]]
|
||||||
|
address = "localhost:8083"
|
||||||
|
|
||||||
|
[tlsoptions.foo]
|
||||||
|
minversion = "VersionTLS11"
|
||||||
|
|
||||||
|
[tlsoptions.bar]
|
||||||
|
minversion = "VersionTLS12"
|
|
@ -111,6 +111,90 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestWithTLSOptions verifies that traefik routes the requests with the associated tls options.
|
||||||
|
func (s *HTTPSSuite) TestWithTLSOptions(c *check.C) {
|
||||||
|
cmd, display := s.traefikCmd(withConfigFile("fixtures/https/https_tls_options.toml"))
|
||||||
|
defer display(c)
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
// wait for Traefik
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`snitest.org`)"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
backend1 := startTestServer("9010", http.StatusNoContent)
|
||||||
|
backend2 := startTestServer("9020", http.StatusResetContent)
|
||||||
|
defer backend1.Close()
|
||||||
|
defer backend2.Close()
|
||||||
|
|
||||||
|
err = try.GetRequest(backend1.URL, 1*time.Second, try.StatusCodeIs(http.StatusNoContent))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
err = try.GetRequest(backend2.URL, 1*time.Second, try.StatusCodeIs(http.StatusResetContent))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
tr1 := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
MaxVersion: tls.VersionTLS11,
|
||||||
|
ServerName: "snitest.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tr2 := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
MaxVersion: tls.VersionTLS12,
|
||||||
|
ServerName: "snitest.org",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tr3 := &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
MaxVersion: tls.VersionTLS11,
|
||||||
|
ServerName: "snitest.org",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// With valid TLS options and request
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = tr1.TLSClientConfig.ServerName
|
||||||
|
req.Header.Set("Host", tr1.TLSClientConfig.ServerName)
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
|
||||||
|
err = try.RequestWithTransport(req, 30*time.Second, tr1, try.HasCn(tr1.TLSClientConfig.ServerName), try.StatusCodeIs(http.StatusNoContent))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// With a valid TLS version
|
||||||
|
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = tr2.TLSClientConfig.ServerName
|
||||||
|
req.Header.Set("Host", tr2.TLSClientConfig.ServerName)
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
|
||||||
|
err = try.RequestWithTransport(req, 3*time.Second, tr2, try.HasCn(tr2.TLSClientConfig.ServerName), try.StatusCodeIs(http.StatusResetContent))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// With a bad TLS version
|
||||||
|
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = tr3.TLSClientConfig.ServerName
|
||||||
|
req.Header.Set("Host", tr3.TLSClientConfig.ServerName)
|
||||||
|
req.Header.Set("Accept", "*/*")
|
||||||
|
client := http.Client{
|
||||||
|
Transport: tr3,
|
||||||
|
}
|
||||||
|
_, err = client.Do(req)
|
||||||
|
c.Assert(err, checker.NotNil)
|
||||||
|
c.Assert(err.Error(), checker.Contains, "protocol version not supported")
|
||||||
|
|
||||||
|
// with unknown tls option
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("unknown TLS options: unknown"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
// TestWithSNIStrictNotMatchedRequest involves a client sending a SNI hostname of
|
// TestWithSNIStrictNotMatchedRequest involves a client sending a SNI hostname of
|
||||||
// "snitest.org", which does not match the CN of 'snitest.com.crt'. The test
|
// "snitest.org", which does not match the CN of 'snitest.com.crt'. The test
|
||||||
// verifies that traefik closes the connection.
|
// verifies that traefik closes the connection.
|
||||||
|
|
|
@ -28,34 +28,38 @@ func (s *RateLimitSuite) TestSimpleConfiguration(c *check.C) {
|
||||||
}{s.ServerIP})
|
}{s.ServerIP})
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
|
|
||||||
cmd, _ := s.cmdTraefik(withConfigFile(file))
|
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer display(c)
|
||||||
err := cmd.Start()
|
err := cmd.Start()
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
defer cmd.Process.Kill()
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("ratelimit"))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
// sleep for 4 seconds to be certain the configured time period has elapsed
|
// sleep for 4 seconds to be certain the configured time period has elapsed
|
||||||
// then test another request and verify a 200 status code
|
// then test another request and verify a 200 status code
|
||||||
time.Sleep(4 * time.Second)
|
time.Sleep(4 * time.Second)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
// continue requests at 3 second intervals to test the other rate limit time period
|
// continue requests at 3 second intervals to test the other rate limit time period
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
err = try.GetRequest("http://127.0.0.1:80/", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
err = try.GetRequest("http://127.0.0.1:8081/", 500*time.Millisecond, try.StatusCodeIs(http.StatusTooManyRequests))
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,36 @@ func (s *TCPSuite) TestMixed(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TCPSuite) TestTLSOptions(c *check.C) {
|
||||||
|
file := s.adaptFile(c, "fixtures/tcp/multi-tls-options.toml", struct{}{})
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer display(c)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`whoami-c.test`)"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// Check that we can use a client tls version <= 1.1 with hostSNI 'whoami-c.test'
|
||||||
|
out, err := guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-c.test", true, tls.VersionTLS11)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(out, checker.Contains, "whoami-no-cert")
|
||||||
|
|
||||||
|
// Check that we can use a client tls version <= 1.2 with hostSNI 'whoami-d.test'
|
||||||
|
out, err = guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-d.test", true, tls.VersionTLS12)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(out, checker.Contains, "whoami-no-cert")
|
||||||
|
|
||||||
|
// Check that we cannot use a client tls version <= 1.1 with hostSNI 'whoami-d.test'
|
||||||
|
_, err = guessWhoTLSMaxVersion("127.0.0.1:8093", "whoami-d.test", true, tls.VersionTLS11)
|
||||||
|
c.Assert(err, checker.NotNil)
|
||||||
|
c.Assert(err.Error(), checker.Contains, "protocol version not supported")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TCPSuite) TestNonTLSFallback(c *check.C) {
|
func (s *TCPSuite) TestNonTLSFallback(c *check.C) {
|
||||||
file := s.adaptFile(c, "fixtures/tcp/non-tls-fallback.toml", struct{}{})
|
file := s.adaptFile(c, "fixtures/tcp/non-tls-fallback.toml", struct{}{})
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
|
@ -191,11 +221,21 @@ func welcome(addr string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func guessWho(addr, serverName string, tlsCall bool) (string, error) {
|
func guessWho(addr, serverName string, tlsCall bool) (string, error) {
|
||||||
|
return guessWhoTLSMaxVersion(addr, serverName, tlsCall, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func guessWhoTLSMaxVersion(addr, serverName string, tlsCall bool, tlsMaxVersion uint16) (string, error) {
|
||||||
var conn net.Conn
|
var conn net.Conn
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if tlsCall {
|
if tlsCall {
|
||||||
conn, err = tls.Dial("tcp", addr, &tls.Config{ServerName: serverName, InsecureSkipVerify: true})
|
|
||||||
|
conn, err = tls.Dial("tcp", addr, &tls.Config{
|
||||||
|
ServerName: serverName,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
MinVersion: 0,
|
||||||
|
MaxVersion: tlsMaxVersion,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
tcpAddr, err2 := net.ResolveTCPAddr("tcp", addr)
|
tcpAddr, err2 := net.ResolveTCPAddr("tcp", addr)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
|
|
|
@ -58,7 +58,7 @@ func Test_doOnJSON(t *testing.T) {
|
||||||
"DNSProvider": "",
|
"DNSProvider": "",
|
||||||
"DelayDontCheckDNS": 0,
|
"DelayDontCheckDNS": 0,
|
||||||
"ACMELogging": false,
|
"ACMELogging": false,
|
||||||
"TLSOptions": null
|
"Options": null
|
||||||
},
|
},
|
||||||
"DefaultEntryPoints": [
|
"DefaultEntryPoints": [
|
||||||
"https",
|
"https",
|
||||||
|
@ -141,7 +141,7 @@ func Test_doOnJSON(t *testing.T) {
|
||||||
"DNSProvider": "",
|
"DNSProvider": "",
|
||||||
"DelayDontCheckDNS": 0,
|
"DelayDontCheckDNS": 0,
|
||||||
"ACMELogging": false,
|
"ACMELogging": false,
|
||||||
"TLSOptions": null
|
"Options": null
|
||||||
},
|
},
|
||||||
"DefaultEntryPoints": [
|
"DefaultEntryPoints": [
|
||||||
"https",
|
"https",
|
||||||
|
|
|
@ -22,7 +22,9 @@ type Router struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouterTLSConfig holds the TLS configuration for a router
|
// RouterTLSConfig holds the TLS configuration for a router
|
||||||
type RouterTLSConfig struct{}
|
type RouterTLSConfig struct {
|
||||||
|
Options string `json:"options,omitempty" toml:"options,omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
// TCPRouter holds the router configuration.
|
// TCPRouter holds the router configuration.
|
||||||
type TCPRouter struct {
|
type TCPRouter struct {
|
||||||
|
@ -34,7 +36,8 @@ type TCPRouter struct {
|
||||||
|
|
||||||
// RouterTCPTLSConfig holds the TLS configuration for a router
|
// RouterTCPTLSConfig holds the TLS configuration for a router
|
||||||
type RouterTCPTLSConfig struct {
|
type RouterTCPTLSConfig struct {
|
||||||
Passthrough bool `json:"passthrough" toml:"passthrough,omitzero"`
|
Passthrough bool `json:"passthrough" toml:"passthrough,omitzero"`
|
||||||
|
Options string `json:"options,omitempty" toml:"options,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadBalancerService holds the LoadBalancerService configuration.
|
// LoadBalancerService holds the LoadBalancerService configuration.
|
||||||
|
|
|
@ -162,9 +162,11 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.tcp.routers.Router0.entrypoints": "foobar, fiibar",
|
"traefik.tcp.routers.Router0.entrypoints": "foobar, fiibar",
|
||||||
"traefik.tcp.routers.Router0.service": "foobar",
|
"traefik.tcp.routers.Router0.service": "foobar",
|
||||||
"traefik.tcp.routers.Router0.tls.passthrough": "false",
|
"traefik.tcp.routers.Router0.tls.passthrough": "false",
|
||||||
|
"traefik.tcp.routers.Router0.tls.options": "foo",
|
||||||
"traefik.tcp.routers.Router1.rule": "foobar",
|
"traefik.tcp.routers.Router1.rule": "foobar",
|
||||||
"traefik.tcp.routers.Router1.entrypoints": "foobar, fiibar",
|
"traefik.tcp.routers.Router1.entrypoints": "foobar, fiibar",
|
||||||
"traefik.tcp.routers.Router1.service": "foobar",
|
"traefik.tcp.routers.Router1.service": "foobar",
|
||||||
|
"traefik.tcp.routers.Router1.tls.options": "foo",
|
||||||
"traefik.tcp.routers.Router1.tls.passthrough": "false",
|
"traefik.tcp.routers.Router1.tls.passthrough": "false",
|
||||||
"traefik.tcp.services.Service0.loadbalancer.server.Port": "42",
|
"traefik.tcp.services.Service0.loadbalancer.server.Port": "42",
|
||||||
"traefik.tcp.services.Service1.loadbalancer.server.Port": "42",
|
"traefik.tcp.services.Service1.loadbalancer.server.Port": "42",
|
||||||
|
@ -185,6 +187,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
TLS: &config.RouterTCPTLSConfig{
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
Passthrough: false,
|
Passthrough: false,
|
||||||
|
Options: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Router1": {
|
"Router1": {
|
||||||
|
@ -196,6 +199,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
TLS: &config.RouterTCPTLSConfig{
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
Passthrough: false,
|
Passthrough: false,
|
||||||
|
Options: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -580,6 +584,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
TLS: &config.RouterTCPTLSConfig{
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
Passthrough: false,
|
Passthrough: false,
|
||||||
|
Options: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Router1": {
|
"Router1": {
|
||||||
|
@ -591,6 +596,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
TLS: &config.RouterTCPTLSConfig{
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
Passthrough: false,
|
Passthrough: false,
|
||||||
|
Options: "foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1110,10 +1116,12 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.TCP.Routers.Router0.EntryPoints": "foobar, fiibar",
|
"traefik.TCP.Routers.Router0.EntryPoints": "foobar, fiibar",
|
||||||
"traefik.TCP.Routers.Router0.Service": "foobar",
|
"traefik.TCP.Routers.Router0.Service": "foobar",
|
||||||
"traefik.TCP.Routers.Router0.TLS.Passthrough": "false",
|
"traefik.TCP.Routers.Router0.TLS.Passthrough": "false",
|
||||||
|
"traefik.TCP.Routers.Router0.TLS.Options": "foo",
|
||||||
"traefik.TCP.Routers.Router1.Rule": "foobar",
|
"traefik.TCP.Routers.Router1.Rule": "foobar",
|
||||||
"traefik.TCP.Routers.Router1.EntryPoints": "foobar, fiibar",
|
"traefik.TCP.Routers.Router1.EntryPoints": "foobar, fiibar",
|
||||||
"traefik.TCP.Routers.Router1.Service": "foobar",
|
"traefik.TCP.Routers.Router1.Service": "foobar",
|
||||||
"traefik.TCP.Routers.Router1.TLS.Passthrough": "false",
|
"traefik.TCP.Routers.Router1.TLS.Passthrough": "false",
|
||||||
|
"traefik.TCP.Routers.Router1.TLS.Options": "foo",
|
||||||
"traefik.TCP.Services.Service0.LoadBalancer.server.Port": "42",
|
"traefik.TCP.Services.Service0.LoadBalancer.server.Port": "42",
|
||||||
"traefik.TCP.Services.Service1.LoadBalancer.server.Port": "42",
|
"traefik.TCP.Services.Service1.LoadBalancer.server.Port": "42",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -128,6 +129,74 @@ func (r *RuntimeConfiguration) PopulateUsedBy() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func contains(entryPoints []string, entryPointName string) bool {
|
||||||
|
for _, name := range entryPoints {
|
||||||
|
if name == entryPointName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoutersByEntrypoints returns all the http routers by entrypoints name and routers name
|
||||||
|
func (r *RuntimeConfiguration) GetRoutersByEntrypoints(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*RouterInfo {
|
||||||
|
entryPointsRouters := make(map[string]map[string]*RouterInfo)
|
||||||
|
|
||||||
|
for rtName, rt := range r.Routers {
|
||||||
|
if (tls && rt.TLS == nil) || (!tls && rt.TLS != nil) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
eps := rt.EntryPoints
|
||||||
|
if len(eps) == 0 {
|
||||||
|
eps = entryPoints
|
||||||
|
}
|
||||||
|
for _, entryPointName := range eps {
|
||||||
|
if !contains(entryPoints, entryPointName) {
|
||||||
|
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
||||||
|
Errorf("entryPoint %q doesn't exist", entryPointName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
||||||
|
entryPointsRouters[entryPointName] = make(map[string]*RouterInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
entryPointsRouters[entryPointName][rtName] = rt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryPointsRouters
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTCPRoutersByEntrypoints returns all the tcp routers by entrypoints name and routers name
|
||||||
|
func (r *RuntimeConfiguration) GetTCPRoutersByEntrypoints(ctx context.Context, entryPoints []string) map[string]map[string]*TCPRouterInfo {
|
||||||
|
entryPointsRouters := make(map[string]map[string]*TCPRouterInfo)
|
||||||
|
|
||||||
|
for rtName, rt := range r.TCPRouters {
|
||||||
|
eps := rt.EntryPoints
|
||||||
|
if len(eps) == 0 {
|
||||||
|
eps = entryPoints
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entryPointName := range eps {
|
||||||
|
if !contains(entryPoints, entryPointName) {
|
||||||
|
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
||||||
|
Errorf("entryPoint %q doesn't exist", entryPointName)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
||||||
|
entryPointsRouters[entryPointName] = make(map[string]*TCPRouterInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
entryPointsRouters[entryPointName][rtName] = rt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryPointsRouters
|
||||||
|
}
|
||||||
|
|
||||||
// RouterInfo holds information about a currently running HTTP router
|
// RouterInfo holds information about a currently running HTTP router
|
||||||
type RouterInfo struct {
|
type RouterInfo struct {
|
||||||
*Router // dynamic configuration
|
*Router // dynamic configuration
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package config_test
|
package config_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/pkg/config"
|
"github.com/containous/traefik/pkg/config"
|
||||||
|
@ -688,3 +689,399 @@ func TestPopulateUsedby(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetTCPRoutersByEntrypoints(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
conf config.Configuration
|
||||||
|
entryPoints []string
|
||||||
|
expected map[string]map[string]*config.TCPRouterInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Empty Configuration without entrypoint",
|
||||||
|
conf: config.Configuration{},
|
||||||
|
entryPoints: []string{""},
|
||||||
|
expected: map[string]map[string]*config.TCPRouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Empty Configuration with unknown entrypoints",
|
||||||
|
conf: config.Configuration{},
|
||||||
|
entryPoints: []string{"foo"},
|
||||||
|
expected: map[string]map[string]*config.TCPRouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with an unknown entrypoint",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"foo"},
|
||||||
|
expected: map[string]map[string]*config.TCPRouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with a known entrypoint",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"web"},
|
||||||
|
expected: map[string]map[string]*config.TCPRouterInfo{
|
||||||
|
"web": {
|
||||||
|
"foo": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with multiple known entrypoints",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"web", "webs"},
|
||||||
|
expected: map[string]map[string]*config.TCPRouterInfo{
|
||||||
|
"web": {
|
||||||
|
"foo": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"webs": {
|
||||||
|
"bar": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
TCPRouter: &config.TCPRouter{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runtimeConfig := config.NewRuntimeConfig(test.conf)
|
||||||
|
actual := runtimeConfig.GetTCPRoutersByEntrypoints(context.Background(), test.entryPoints)
|
||||||
|
assert.Equal(t, test.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRoutersByEntrypoints(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
conf config.Configuration
|
||||||
|
entryPoints []string
|
||||||
|
expected map[string]map[string]*config.RouterInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Empty Configuration without entrypoint",
|
||||||
|
conf: config.Configuration{},
|
||||||
|
entryPoints: []string{""},
|
||||||
|
expected: map[string]map[string]*config.RouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Empty Configuration with unknown entrypoints",
|
||||||
|
conf: config.Configuration{},
|
||||||
|
entryPoints: []string{"foo"},
|
||||||
|
expected: map[string]map[string]*config.RouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with an unknown entrypoint",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"foo"},
|
||||||
|
expected: map[string]map[string]*config.RouterInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with a known entrypoint",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"web"},
|
||||||
|
expected: map[string]map[string]*config.RouterInfo{
|
||||||
|
"web": {
|
||||||
|
"foo": {
|
||||||
|
Router: &config.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
Router: &config.Router{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Valid configuration with multiple known entrypoints",
|
||||||
|
conf: config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: map[string]*config.TCPRouter{
|
||||||
|
"foo": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "HostSNI(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entryPoints: []string{"web", "webs"},
|
||||||
|
expected: map[string]map[string]*config.RouterInfo{
|
||||||
|
"web": {
|
||||||
|
"foo": {
|
||||||
|
Router: &config.Router{
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "myprovider.foo-service",
|
||||||
|
Rule: "Host(`bar.foo`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
Router: &config.Router{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"webs": {
|
||||||
|
"bar": {
|
||||||
|
Router: &config.Router{
|
||||||
|
|
||||||
|
EntryPoints: []string{"webs"},
|
||||||
|
Service: "myprovider.bar-service",
|
||||||
|
Rule: "Host(`foo.bar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"foobar": {
|
||||||
|
Router: &config.Router{
|
||||||
|
EntryPoints: []string{"web", "webs"},
|
||||||
|
Service: "myprovider.foobar-service",
|
||||||
|
Rule: "Host(`bar.foobar`)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
test := test
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runtimeConfig := config.NewRuntimeConfig(test.conf)
|
||||||
|
actual := runtimeConfig.GetRoutersByEntrypoints(context.Background(), test.entryPoints, false)
|
||||||
|
assert.Equal(t, test.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2164,7 +2164,7 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Name: "Test",
|
Name: "Test",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)",
|
"traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)",
|
||||||
"traefik.tcp.routers.foo.tls": "true",
|
"traefik.tcp.routers.foo.tls.options": "foo",
|
||||||
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
|
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
|
||||||
},
|
},
|
||||||
NetworkSettings: networkSettings{
|
NetworkSettings: networkSettings{
|
||||||
|
@ -2186,7 +2186,9 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"foo": {
|
"foo": {
|
||||||
Service: "foo",
|
Service: "foo",
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
TLS: &config.RouterTCPTLSConfig{},
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
|
Options: "foo",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Services: map[string]*config.TCPService{
|
Services: map[string]*config.TCPService{
|
||||||
|
|
|
@ -580,7 +580,6 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
Name: "Test",
|
Name: "Test",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)",
|
"traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)",
|
||||||
"traefik.tcp.routers.foo.tls": "true",
|
|
||||||
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
|
"traefik.tcp.services.foo.loadbalancer.server.port": "8080",
|
||||||
},
|
},
|
||||||
Port: "80/tcp",
|
Port: "80/tcp",
|
||||||
|
@ -595,7 +594,6 @@ func Test_buildConfiguration(t *testing.T) {
|
||||||
"foo": {
|
"foo": {
|
||||||
Service: "foo",
|
Service: "foo",
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
TLS: &config.RouterTCPTLSConfig{},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Services: map[string]*config.TCPService{
|
Services: map[string]*config.TCPService{
|
||||||
|
|
|
@ -2,7 +2,6 @@ package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/containous/alice"
|
"github.com/containous/alice"
|
||||||
|
@ -23,33 +22,42 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewManager Creates a new Manager
|
// NewManager Creates a new Manager
|
||||||
func NewManager(routers map[string]*config.RouterInfo,
|
func NewManager(conf *config.RuntimeConfiguration,
|
||||||
serviceManager *service.Manager, middlewaresBuilder *middleware.Builder, modifierBuilder *responsemodifiers.Builder,
|
serviceManager *service.Manager,
|
||||||
|
middlewaresBuilder *middleware.Builder,
|
||||||
|
modifierBuilder *responsemodifiers.Builder,
|
||||||
) *Manager {
|
) *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
routerHandlers: make(map[string]http.Handler),
|
routerHandlers: make(map[string]http.Handler),
|
||||||
configs: routers,
|
|
||||||
serviceManager: serviceManager,
|
serviceManager: serviceManager,
|
||||||
middlewaresBuilder: middlewaresBuilder,
|
middlewaresBuilder: middlewaresBuilder,
|
||||||
modifierBuilder: modifierBuilder,
|
modifierBuilder: modifierBuilder,
|
||||||
|
conf: conf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager A route/router manager
|
// Manager A route/router manager
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
routerHandlers map[string]http.Handler
|
routerHandlers map[string]http.Handler
|
||||||
configs map[string]*config.RouterInfo
|
|
||||||
serviceManager *service.Manager
|
serviceManager *service.Manager
|
||||||
middlewaresBuilder *middleware.Builder
|
middlewaresBuilder *middleware.Builder
|
||||||
modifierBuilder *responsemodifiers.Builder
|
modifierBuilder *responsemodifiers.Builder
|
||||||
|
conf *config.RuntimeConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getHTTPRouters(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*config.RouterInfo {
|
||||||
|
if m.conf != nil {
|
||||||
|
return m.conf.GetRoutersByEntrypoints(ctx, entryPoints, tls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return make(map[string]map[string]*config.RouterInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildHandlers Builds handler for all entry points
|
// BuildHandlers Builds handler for all entry points
|
||||||
func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string, tls bool) map[string]http.Handler {
|
func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string, tls bool) map[string]http.Handler {
|
||||||
entryPointsRouters := m.filteredRouters(rootCtx, entryPoints, tls)
|
|
||||||
|
|
||||||
entryPointHandlers := make(map[string]http.Handler)
|
entryPointHandlers := make(map[string]http.Handler)
|
||||||
for entryPointName, routers := range entryPointsRouters {
|
|
||||||
|
for entryPointName, routers := range m.getHTTPRouters(rootCtx, entryPoints, tls) {
|
||||||
entryPointName := entryPointName
|
entryPointName := entryPointName
|
||||||
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
|
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
|
||||||
|
|
||||||
|
@ -75,45 +83,6 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string, t
|
||||||
return entryPointHandlers
|
return entryPointHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(entryPoints []string, entryPointName string) bool {
|
|
||||||
for _, name := range entryPoints {
|
|
||||||
if name == entryPointName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) filteredRouters(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*config.RouterInfo {
|
|
||||||
entryPointsRouters := make(map[string]map[string]*config.RouterInfo)
|
|
||||||
|
|
||||||
for rtName, rt := range m.configs {
|
|
||||||
if (tls && rt.TLS == nil) || (!tls && rt.TLS != nil) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
eps := rt.EntryPoints
|
|
||||||
if len(eps) == 0 {
|
|
||||||
eps = entryPoints
|
|
||||||
}
|
|
||||||
for _, entryPointName := range eps {
|
|
||||||
if !contains(entryPoints, entryPointName) {
|
|
||||||
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
|
||||||
Errorf("entryPoint %q doesn't exist", entryPointName)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
|
||||||
entryPointsRouters[entryPointName] = make(map[string]*config.RouterInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
entryPointsRouters[entryPointName][rtName] = rt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entryPointsRouters
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.RouterInfo) (http.Handler, error) {
|
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.RouterInfo) (http.Handler, error) {
|
||||||
router, err := rules.NewRouter()
|
router, err := rules.NewRouter()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -124,7 +93,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
||||||
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
|
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
|
||||||
logger := log.FromContext(ctxRouter)
|
logger := log.FromContext(ctxRouter)
|
||||||
|
|
||||||
handler, err := m.buildRouterHandler(ctxRouter, routerName)
|
handler, err := m.buildRouterHandler(ctxRouter, routerName, routerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
routerConfig.Err = err.Error()
|
routerConfig.Err = err.Error()
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
|
@ -149,17 +118,12 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
||||||
return chain.Then(router)
|
return chain.Then(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) buildRouterHandler(ctx context.Context, routerName string) (http.Handler, error) {
|
func (m *Manager) buildRouterHandler(ctx context.Context, routerName string, routerConfig *config.RouterInfo) (http.Handler, error) {
|
||||||
if handler, ok := m.routerHandlers[routerName]; ok {
|
if handler, ok := m.routerHandlers[routerName]; ok {
|
||||||
return handler, nil
|
return handler, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
configRouter, ok := m.configs[routerName]
|
handler, err := m.buildHTTPHandler(ctx, routerConfig, routerName)
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no configuration for %s", routerName)
|
|
||||||
}
|
|
||||||
|
|
||||||
handler, err := m.buildHTTPHandler(ctx, configRouter, routerName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,7 +308,7 @@ func TestRouterManager_Get(t *testing.T) {
|
||||||
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
||||||
routerManager := NewManager(rtConf.Routers, serviceManager, middlewaresBuilder, responseModifierFactory)
|
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
|
||||||
|
|
||||||
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
|
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ func TestAccessLog(t *testing.T) {
|
||||||
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
||||||
routerManager := NewManager(rtConf.Routers, serviceManager, middlewaresBuilder, responseModifierFactory)
|
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
|
||||||
|
|
||||||
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
|
handlers := routerManager.BuildHandlers(context.Background(), test.entryPoints, false)
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport)
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*config.MiddlewareInfo{})
|
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*config.MiddlewareInfo{})
|
||||||
routerManager := NewManager(rtConf.Routers, serviceManager, middlewaresBuilder, responseModifierFactory)
|
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
|
||||||
|
|
||||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
_ = routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
||||||
|
|
||||||
|
@ -769,7 +769,7 @@ func BenchmarkRouterServe(b *testing.B) {
|
||||||
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res})
|
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res})
|
||||||
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
|
||||||
routerManager := NewManager(rtConf.Routers, serviceManager, middlewaresBuilder, responseModifierFactory)
|
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
|
||||||
|
|
||||||
handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
handlers := routerManager.BuildHandlers(context.Background(), entryPoints, false)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -12,6 +11,7 @@ import (
|
||||||
"github.com/containous/traefik/pkg/server/internal"
|
"github.com/containous/traefik/pkg/server/internal"
|
||||||
tcpservice "github.com/containous/traefik/pkg/server/service/tcp"
|
tcpservice "github.com/containous/traefik/pkg/server/service/tcp"
|
||||||
"github.com/containous/traefik/pkg/tcp"
|
"github.com/containous/traefik/pkg/tcp"
|
||||||
|
"github.com/containous/traefik/pkg/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewManager Creates a new Manager
|
// NewManager Creates a new Manager
|
||||||
|
@ -19,29 +19,46 @@ func NewManager(conf *config.RuntimeConfiguration,
|
||||||
serviceManager *tcpservice.Manager,
|
serviceManager *tcpservice.Manager,
|
||||||
httpHandlers map[string]http.Handler,
|
httpHandlers map[string]http.Handler,
|
||||||
httpsHandlers map[string]http.Handler,
|
httpsHandlers map[string]http.Handler,
|
||||||
tlsConfig *tls.Config,
|
tlsManager *tls.Manager,
|
||||||
) *Manager {
|
) *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
configs: conf.TCPRouters,
|
|
||||||
serviceManager: serviceManager,
|
serviceManager: serviceManager,
|
||||||
httpHandlers: httpHandlers,
|
httpHandlers: httpHandlers,
|
||||||
httpsHandlers: httpsHandlers,
|
httpsHandlers: httpsHandlers,
|
||||||
tlsConfig: tlsConfig,
|
tlsManager: tlsManager,
|
||||||
|
conf: conf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager is a route/router manager
|
// Manager is a route/router manager
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
configs map[string]*config.TCPRouterInfo
|
|
||||||
serviceManager *tcpservice.Manager
|
serviceManager *tcpservice.Manager
|
||||||
httpHandlers map[string]http.Handler
|
httpHandlers map[string]http.Handler
|
||||||
httpsHandlers map[string]http.Handler
|
httpsHandlers map[string]http.Handler
|
||||||
tlsConfig *tls.Config
|
tlsManager *tls.Manager
|
||||||
|
conf *config.RuntimeConfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getTCPRouters(ctx context.Context, entryPoints []string) map[string]map[string]*config.TCPRouterInfo {
|
||||||
|
if m.conf != nil {
|
||||||
|
return m.conf.GetTCPRoutersByEntrypoints(ctx, entryPoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
return make(map[string]map[string]*config.TCPRouterInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) getHTTPRouters(ctx context.Context, entryPoints []string, tls bool) map[string]map[string]*config.RouterInfo {
|
||||||
|
if m.conf != nil {
|
||||||
|
return m.conf.GetRoutersByEntrypoints(ctx, entryPoints, tls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return make(map[string]map[string]*config.RouterInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildHandlers builds the handlers for the given entrypoints
|
// BuildHandlers builds the handlers for the given entrypoints
|
||||||
func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) map[string]*tcp.Router {
|
func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) map[string]*tcp.Router {
|
||||||
entryPointsRouters := m.filteredRouters(rootCtx, entryPoints)
|
entryPointsRouters := m.getTCPRouters(rootCtx, entryPoints)
|
||||||
|
entryPointsRoutersHTTP := m.getHTTPRouters(rootCtx, entryPoints, true)
|
||||||
|
|
||||||
entryPointHandlers := make(map[string]*tcp.Router)
|
entryPointHandlers := make(map[string]*tcp.Router)
|
||||||
for _, entryPointName := range entryPoints {
|
for _, entryPointName := range entryPoints {
|
||||||
|
@ -51,7 +68,7 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
|
||||||
|
|
||||||
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
|
ctx := log.With(rootCtx, log.Str(log.EntryPointName, entryPointName))
|
||||||
|
|
||||||
handler, err := m.buildEntryPointHandler(ctx, routers, m.httpHandlers[entryPointName], m.httpsHandlers[entryPointName])
|
handler, err := m.buildEntryPointHandler(ctx, routers, entryPointsRoutersHTTP[entryPointName], m.httpHandlers[entryPointName], m.httpsHandlers[entryPointName])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err)
|
log.FromContext(ctx).Error(err)
|
||||||
continue
|
continue
|
||||||
|
@ -61,10 +78,50 @@ func (m *Manager) BuildHandlers(rootCtx context.Context, entryPoints []string) m
|
||||||
return entryPointHandlers
|
return entryPointHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.TCPRouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
|
func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string]*config.TCPRouterInfo, configsHTTP map[string]*config.RouterInfo, handlerHTTP http.Handler, handlerHTTPS http.Handler) (*tcp.Router, error) {
|
||||||
router := &tcp.Router{}
|
router := &tcp.Router{}
|
||||||
router.HTTPHandler(handlerHTTP)
|
router.HTTPHandler(handlerHTTP)
|
||||||
router.HTTPSHandler(handlerHTTPS, m.tlsConfig)
|
|
||||||
|
defaultTLSConf, err := m.tlsManager.Get("default", "default")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
router.HTTPSHandler(handlerHTTPS, defaultTLSConf)
|
||||||
|
|
||||||
|
for routerHTTPName, routerHTTPConfig := range configsHTTP {
|
||||||
|
if len(routerHTTPConfig.TLS.Options) == 0 || routerHTTPConfig.TLS.Options == "default" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerHTTPName), log.Str(log.RouterName, routerHTTPName))
|
||||||
|
logger := log.FromContext(ctxRouter)
|
||||||
|
|
||||||
|
domains, err := rules.ParseDomains(routerHTTPConfig.Rule)
|
||||||
|
if err != nil {
|
||||||
|
routerErr := fmt.Errorf("invalid rule %s, error: %v", routerHTTPConfig.Rule, err)
|
||||||
|
routerHTTPConfig.Err = routerErr.Error()
|
||||||
|
logger.Debug(routerErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(domains) == 0 {
|
||||||
|
logger.Warnf("The 'default' TLS options will be applied instead of %q as no domain has been found in the rule", routerHTTPConfig.TLS.Options)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range domains {
|
||||||
|
if routerHTTPConfig.TLS != nil {
|
||||||
|
tlsConf, err := m.tlsManager.Get("default", routerHTTPConfig.TLS.Options)
|
||||||
|
if err != nil {
|
||||||
|
routerHTTPConfig.Err = err.Error()
|
||||||
|
logger.Debug(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
router.AddRouteHTTPTLS(domain, tlsConf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for routerName, routerConfig := range configs {
|
for routerName, routerConfig := range configs {
|
||||||
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
|
ctxRouter := log.With(internal.AddProviderInContext(ctx, routerName), log.Str(log.RouterName, routerName))
|
||||||
|
@ -92,7 +149,19 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
||||||
if routerConfig.TLS.Passthrough {
|
if routerConfig.TLS.Passthrough {
|
||||||
router.AddRoute(domain, handler)
|
router.AddRoute(domain, handler)
|
||||||
} else {
|
} else {
|
||||||
router.AddRouteTLS(domain, handler, m.tlsConfig)
|
configName := "default"
|
||||||
|
if len(routerConfig.TLS.Options) > 0 {
|
||||||
|
configName = routerConfig.TLS.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConf, err := m.tlsManager.Get("default", configName)
|
||||||
|
if err != nil {
|
||||||
|
routerConfig.Err = err.Error()
|
||||||
|
logger.Debug(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
router.AddRouteTLS(domain, handler, tlsConf)
|
||||||
}
|
}
|
||||||
case domain == "*":
|
case domain == "*":
|
||||||
router.AddCatchAllNoTLS(handler)
|
router.AddCatchAllNoTLS(handler)
|
||||||
|
@ -104,39 +173,3 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
|
||||||
|
|
||||||
return router, nil
|
return router, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func contains(entryPoints []string, entryPointName string) bool {
|
|
||||||
for _, name := range entryPoints {
|
|
||||||
if name == entryPointName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Manager) filteredRouters(ctx context.Context, entryPoints []string) map[string]map[string]*config.TCPRouterInfo {
|
|
||||||
entryPointsRouters := make(map[string]map[string]*config.TCPRouterInfo)
|
|
||||||
|
|
||||||
for rtName, rt := range m.configs {
|
|
||||||
eps := rt.EntryPoints
|
|
||||||
if len(eps) == 0 {
|
|
||||||
eps = entryPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, entryPointName := range eps {
|
|
||||||
if !contains(entryPoints, entryPointName) {
|
|
||||||
log.FromContext(log.With(ctx, log.Str(log.EntryPointName, entryPointName))).
|
|
||||||
Errorf("entryPoint %q doesn't exist", entryPointName)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := entryPointsRouters[entryPointName]; !ok {
|
|
||||||
entryPointsRouters[entryPointName] = make(map[string]*config.TCPRouterInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
entryPointsRouters[entryPointName][rtName] = rt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entryPointsRouters
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"github.com/containous/traefik/pkg/config"
|
"github.com/containous/traefik/pkg/config"
|
||||||
"github.com/containous/traefik/pkg/server/service/tcp"
|
"github.com/containous/traefik/pkg/server/service/tcp"
|
||||||
|
"github.com/containous/traefik/pkg/tls"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +43,10 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "foo-service",
|
Service: "foo-service",
|
||||||
Rule: "HostSNI(`bar.foo`)",
|
Rule: "HostSNI(`bar.foo`)",
|
||||||
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
|
Passthrough: false,
|
||||||
|
Options: "foo",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
|
@ -50,6 +55,10 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
EntryPoints: []string{"web"},
|
EntryPoints: []string{"web"},
|
||||||
Service: "foo-service",
|
Service: "foo-service",
|
||||||
Rule: "HostSNI(`foo.bar`)",
|
Rule: "HostSNI(`foo.bar`)",
|
||||||
|
TLS: &config.RouterTCPTLSConfig{
|
||||||
|
Passthrough: false,
|
||||||
|
Options: "bar",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -191,8 +200,21 @@ func TestRuntimeConfiguration(t *testing.T) {
|
||||||
TCPRouters: test.routerConfig,
|
TCPRouters: test.routerConfig,
|
||||||
}
|
}
|
||||||
serviceManager := tcp.NewManager(conf)
|
serviceManager := tcp.NewManager(conf)
|
||||||
|
tlsManager := tls.NewManager()
|
||||||
|
tlsManager.UpdateConfigs(
|
||||||
|
map[string]tls.Store{},
|
||||||
|
map[string]tls.TLS{
|
||||||
|
"foo": {
|
||||||
|
MinVersion: "VersionTLS12",
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
MinVersion: "VersionTLS11",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]*tls.Configuration{})
|
||||||
|
|
||||||
routerManager := NewManager(conf, serviceManager,
|
routerManager := NewManager(conf, serviceManager,
|
||||||
nil, nil, nil)
|
nil, nil, tlsManager)
|
||||||
|
|
||||||
_ = routerManager.BuildHandlers(context.Background(), entryPoints)
|
_ = routerManager.BuildHandlers(context.Background(), entryPoints)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -71,20 +70,21 @@ func (s *Server) loadConfigurationTCP(configurations config.Configurations) map[
|
||||||
|
|
||||||
rtConf := config.NewRuntimeConfig(conf)
|
rtConf := config.NewRuntimeConfig(conf)
|
||||||
handlersNonTLS, handlersTLS := s.createHTTPHandlers(ctx, rtConf, entryPoints)
|
handlersNonTLS, handlersTLS := s.createHTTPHandlers(ctx, rtConf, entryPoints)
|
||||||
routersTCP := s.createTCPRouters(ctx, rtConf, entryPoints, handlersNonTLS, handlersTLS, s.tlsManager.Get("default", "default"))
|
routersTCP := s.createTCPRouters(ctx, rtConf, entryPoints, handlersNonTLS, handlersTLS)
|
||||||
rtConf.PopulateUsedBy()
|
rtConf.PopulateUsedBy()
|
||||||
|
|
||||||
return routersTCP
|
return routersTCP
|
||||||
}
|
}
|
||||||
|
|
||||||
// the given configuration must not be nil. its fields will get mutated.
|
// the given configuration must not be nil. its fields will get mutated.
|
||||||
func (s *Server) createTCPRouters(ctx context.Context, configuration *config.RuntimeConfiguration, entryPoints []string, handlers map[string]http.Handler, handlersTLS map[string]http.Handler, tlsConfig *tls.Config) map[string]*tcpCore.Router {
|
func (s *Server) createTCPRouters(ctx context.Context, configuration *config.RuntimeConfiguration, entryPoints []string, handlers map[string]http.Handler, handlersTLS map[string]http.Handler) map[string]*tcpCore.Router {
|
||||||
if configuration == nil {
|
if configuration == nil {
|
||||||
return make(map[string]*tcpCore.Router)
|
return make(map[string]*tcpCore.Router)
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceManager := tcp.NewManager(configuration)
|
serviceManager := tcp.NewManager(configuration)
|
||||||
routerManager := routertcp.NewManager(configuration, serviceManager, handlers, handlersTLS, tlsConfig)
|
|
||||||
|
routerManager := routertcp.NewManager(configuration, serviceManager, handlers, handlersTLS, s.tlsManager)
|
||||||
|
|
||||||
return routerManager.BuildHandlers(ctx, entryPoints)
|
return routerManager.BuildHandlers(ctx, entryPoints)
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ func (s *Server) createHTTPHandlers(ctx context.Context, configuration *config.R
|
||||||
serviceManager := service.NewManager(configuration.Services, s.defaultRoundTripper)
|
serviceManager := service.NewManager(configuration.Services, s.defaultRoundTripper)
|
||||||
middlewaresBuilder := middleware.NewBuilder(configuration.Middlewares, serviceManager)
|
middlewaresBuilder := middleware.NewBuilder(configuration.Middlewares, serviceManager)
|
||||||
responseModifierFactory := responsemodifiers.NewBuilder(configuration.Middlewares)
|
responseModifierFactory := responsemodifiers.NewBuilder(configuration.Middlewares)
|
||||||
routerManager := router.NewManager(configuration.Routers, serviceManager, middlewaresBuilder, responseModifierFactory)
|
routerManager := router.NewManager(configuration, serviceManager, middlewaresBuilder, responseModifierFactory)
|
||||||
|
|
||||||
handlersNonTLS := routerManager.BuildHandlers(ctx, entryPoints, false)
|
handlersNonTLS := routerManager.BuildHandlers(ctx, entryPoints, false)
|
||||||
handlersTLS := routerManager.BuildHandlers(ctx, entryPoints, true)
|
handlersTLS := routerManager.BuildHandlers(ctx, entryPoints, true)
|
||||||
|
|
|
@ -14,13 +14,14 @@ import (
|
||||||
|
|
||||||
// Router is a TCP router
|
// Router is a TCP router
|
||||||
type Router struct {
|
type Router struct {
|
||||||
routingTable map[string]Handler
|
routingTable map[string]Handler
|
||||||
httpForwarder Handler
|
httpForwarder Handler
|
||||||
httpsForwarder Handler
|
httpsForwarder Handler
|
||||||
httpHandler http.Handler
|
httpHandler http.Handler
|
||||||
httpsHandler http.Handler
|
httpsHandler http.Handler
|
||||||
httpsTLSConfig *tls.Config
|
httpsTLSConfig *tls.Config // default TLS config
|
||||||
catchAllNoTLS Handler
|
catchAllNoTLS Handler
|
||||||
|
hostHTTPTLSConfig map[string]*tls.Config // TLS configs keyed by SNI
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeTCP forwards the connection to the right TCP/HTTP handler
|
// ServeTCP forwards the connection to the right TCP/HTTP handler
|
||||||
|
@ -84,6 +85,15 @@ func (r *Router) AddRouteTLS(sniHost string, target Handler, config *tls.Config)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddRouteHTTPTLS defines a handler for a given sniHost and sets the matching tlsConfig
|
||||||
|
func (r *Router) AddRouteHTTPTLS(sniHost string, config *tls.Config) {
|
||||||
|
if r.hostHTTPTLSConfig == nil {
|
||||||
|
r.hostHTTPTLSConfig = map[string]*tls.Config{}
|
||||||
|
}
|
||||||
|
log.Debugf("adding route %s with minversion %d", sniHost, config.MinVersion)
|
||||||
|
r.hostHTTPTLSConfig[sniHost] = config
|
||||||
|
}
|
||||||
|
|
||||||
// AddCatchAllNoTLS defines the fallback tcp handler
|
// AddCatchAllNoTLS defines the fallback tcp handler
|
||||||
func (r *Router) AddCatchAllNoTLS(handler Handler) {
|
func (r *Router) AddCatchAllNoTLS(handler Handler) {
|
||||||
r.catchAllNoTLS = handler
|
r.catchAllNoTLS = handler
|
||||||
|
@ -116,6 +126,10 @@ func (r *Router) HTTPForwarder(handler Handler) {
|
||||||
|
|
||||||
// HTTPSForwarder sets the tcp handler that will forward the TLS connections to an http handler
|
// HTTPSForwarder sets the tcp handler that will forward the TLS connections to an http handler
|
||||||
func (r *Router) HTTPSForwarder(handler Handler) {
|
func (r *Router) HTTPSForwarder(handler Handler) {
|
||||||
|
for sniHost, tlsConf := range r.hostHTTPTLSConfig {
|
||||||
|
r.AddRouteTLS(sniHost, handler, tlsConf)
|
||||||
|
}
|
||||||
|
|
||||||
r.httpsForwarder = &TLSHandler{
|
r.httpsForwarder = &TLSHandler{
|
||||||
Next: handler,
|
Next: handler,
|
||||||
Config: r.httpsTLSConfig,
|
Config: r.httpsTLSConfig,
|
||||||
|
|
|
@ -67,14 +67,19 @@ func (m *Manager) UpdateConfigs(stores map[string]Store, configs map[string]TLS,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get gets the tls configuration to use for a given store / configuration
|
// Get gets the TLS configuration to use for a given store / configuration
|
||||||
func (m *Manager) Get(storeName string, configName string) *tls.Config {
|
func (m *Manager) Get(storeName string, configName string) (*tls.Config, error) {
|
||||||
m.lock.RLock()
|
m.lock.RLock()
|
||||||
defer m.lock.RUnlock()
|
defer m.lock.RUnlock()
|
||||||
|
|
||||||
|
config, ok := m.configs[configName]
|
||||||
|
if !ok && configName != "default" {
|
||||||
|
return nil, fmt.Errorf("unknown TLS options: %s", configName)
|
||||||
|
}
|
||||||
|
|
||||||
store := m.getStore(storeName)
|
store := m.getStore(storeName)
|
||||||
|
|
||||||
tlsConfig, err := buildTLSConfig(m.configs[configName])
|
tlsConfig, err := buildTLSConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
tlsConfig = &tls.Config{}
|
tlsConfig = &tls.Config{}
|
||||||
|
@ -106,7 +111,7 @@ func (m *Manager) Get(storeName string, configName string) *tls.Config {
|
||||||
log.WithoutContext().Debugf("Serving default certificate for request: %q", domainToCheck)
|
log.WithoutContext().Debugf("Serving default certificate for request: %q", domainToCheck)
|
||||||
return store.DefaultCertificate, nil
|
return store.DefaultCertificate, nil
|
||||||
}
|
}
|
||||||
return tlsConfig
|
return tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) getStore(storeName string) *CertificateStore {
|
func (m *Manager) getStore(storeName string) *CertificateStore {
|
||||||
|
|
Loading…
Reference in a new issue