Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define TLS options on the Router configuration #4931

Merged
merged 10 commits into from
Jun 17, 2019
2 changes: 2 additions & 0 deletions docs/content/reference/dynamic-configuration/file.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Rule = "foobar"
priority = 42
[HTTP.Routers.Router0.tls]
options = "TLS0"

[HTTP.Middlewares]

Expand Down Expand Up @@ -206,6 +207,7 @@
Rule = "foobar"
[TCP.Routers.TCPRouter0.tls]
passthrough = true
options = "TLS1"

[TCP.Services]

Expand Down
3 changes: 3 additions & 0 deletions docs/content/reference/dynamic-configuration/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ labels:
- "traefik.HTTP.Routers.Router0.Rule=foobar"
- "traefik.HTTP.Routers.Router0.Service=foobar"
- "traefik.HTTP.Routers.Router0.TLS=true"
- "traefik.HTTP.Routers.Router0.TLS.options=foo"
- "traefik.HTTP.Routers.Router1.EntryPoints=foobar, fiibar"
- "traefik.HTTP.Routers.Router1.Middlewares=foobar, fiibar"
- "traefik.HTTP.Routers.Router1.Priority=42"
Expand Down Expand Up @@ -143,9 +144,11 @@ labels:
- "traefik.TCP.Routers.Router0.EntryPoints=foobar, fiibar"
- "traefik.TCP.Routers.Router0.Service=foobar"
- "traefik.TCP.Routers.Router0.TLS.Passthrough=false"
- "traefik.TCP.Routers.Router0.TLS.options=bar"
- "traefik.TCP.Routers.Router1.Rule=foobar"
- "traefik.TCP.Routers.Router1.EntryPoints=foobar, fiibar"
- "traefik.TCP.Routers.Router1.Service=foobar"
- "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.Service1.LoadBalancer.server.Port=42"
64 changes: 58 additions & 6 deletions docs/content/routing/routers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ Services are the target for the router.

### 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).

??? example "Configuring the router to accept HTTPS requests only"
Expand All @@ -172,8 +174,7 @@ Traefik will terminate the SSL connections (meaning that it will send decrypted
!!! 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 near future, options will be available to enable fine-grain control of the TLS parameters.


!!! note "Passthrough"

On TCP routers, you can configure a passthrough option so that Traefik doesn't terminate the TLS connection.
Expand All @@ -196,6 +197,31 @@ Traefik will terminate the SSL connections (meaning that it will send decrypted
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

### General
Expand Down Expand Up @@ -269,8 +295,10 @@ Services are the target for the router.

### 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).
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".
#### General

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"

Expand All @@ -296,4 +324,28 @@ By default, Traefik will terminate the SSL connections (meaning that it will sen
!!! 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 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 changes: 62 additions & 0 deletions integration/fixtures/https/https_tls_options.toml
Original file line number Diff line number Diff line change
@@ -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"
9 changes: 8 additions & 1 deletion integration/fixtures/ratelimit/simple.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
checkNewVersion = false
sendAnonymousUsage = false

[api]
entrypoint="api"

[log]
level = "DEBUG"

[entryPoints]
[entryPoints.web]
address = ":80"
address = ":8081"


[entryPoints.api]
address = ":8080"

[providers]
[providers.file]
Expand Down
1 change: 0 additions & 1 deletion integration/fixtures/tcp/catch-all-no-tls-with-https.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@ level = "DEBUG"
[http.services.whoami.loadbalancer]
[[http.services.whoami.loadbalancer.servers]]
url = "http://localhost:8085"
weight=1
42 changes: 42 additions & 0 deletions integration/fixtures/tcp/multi-tls-options.toml
Original file line number Diff line number Diff line change
@@ -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"
84 changes: 84 additions & 0 deletions integration/https_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,90 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute(c *check.C) {
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
// "snitest.org", which does not match the CN of 'snitest.com.crt'. The test
// verifies that traefik closes the connection.
Expand Down