diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md
index 35d189d96..c526a2a51 100644
--- a/docs/configuration/backends/docker.md
+++ b/docs/configuration/backends/docker.md
@@ -57,7 +57,7 @@ watch = true
exposedByDefault = true
# Use the IP address from the binded port instead of the inner network one.
-#
+#
# In case no IP address is attached to the binded port (or in case
# there is no bind), the inner network one will be used as a fallback.
#
@@ -93,7 +93,6 @@ network = "web"
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
-
## Docker Swarm Mode
```toml
@@ -180,6 +179,57 @@ exposedByDefault = false
To enable constraints see [provider-specific constraints section](/configuration/commons/#provider-specific).
+## Security Considerations
+
+### Security Challenge with the Docker Socket
+
+Traefik requires access to the docker socket to get its dynamic configuration,
+by watching the Docker API through this socket.
+
+!!! important
+ Depending on your context and your usage, accessing the Docker API without any restriction might be a security concern.
+
+As explained on the Docker documentation: ([Docker Daemon Attack Surface page](https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface)):
+
+`[...] only **trusted** users should be allowed to control your Docker daemon [...]`
+
+If the Traefik processes (handling requests from the outside world) is attacked,
+then the attacker can access the Docker (or Swarm Mode) backend.
+
+Also, when using Swarm Mode, it is mandatory to schedule Traefik's containers on the Swarm manager nodes,
+to let Traefik accessing the Docker Socket of the Swarm manager node.
+
+More information about Docker's security:
+
+- [KubeCon EU 2018 Keynote, Running with Scissors, from Liz Rice](https://www.youtube.com/watch?v=ltrV-Qmh3oY)
+- [Don't expose the Docker socket (not even to a container)](https://www.lvh.io/posts/dont-expose-the-docker-socket-not-even-to-a-container.html)
+- [A thread on Stack Overflow about sharing the `/var/run/docker.sock` file](https://news.ycombinator.com/item?id=17983623)
+- [To Dind or not to DinD](https://blog.loof.fr/2018/01/to-dind-or-not-do-dind.html)
+
+### Security Compensation
+
+The main security compensation is to expose the Docker socket over TCP, instead of the default Unix socket file.
+It allows different implementation levels of the [AAA (Authentication, Authorization, Accounting) concepts](https://en.wikipedia.org/wiki/AAA_(computer_security)), depending on your security assessment:
+
+- Authentication with Client Certificates as described in [the "Protect the Docker daemon socket" page of Docker's documentation](https://docs.docker.com/engine/security/https/)
+
+- Authorization with the [Docker Authorization Plugin Mechanism](https://docs.docker.com/engine/extend/plugins_authorization/)
+
+- Accounting at networking level, by exposing the socket only inside a Docker private network, only available for Traefik.
+
+- Accounting at container level, by exposing the socket on a another container than Traefik's.
+ With Swarm mode, it allows scheduling of Traefik on worker nodes, with only the "socket exposer" container on the manager nodes.
+
+- Accounting at kernel level, by enforcing kernel calls with mechanisms like [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux),
+ to only allows an identified set of actions for Traefik's process (or the "socket exposer" process).
+
+Use the following ressources to get started:
+
+- [Traefik issue GH-4174 about security with Docker socket](https://github.com/containous/traefik/issues/4174)
+- [Inspecting Docker Activity with Socat](https://developers.redhat.com/blog/2015/02/25/inspecting-docker-activity-with-socat/)
+- [Letting Traefik run on Worker Nodes](https://blog.mikesir87.io/2018/07/letting-traefik-run-on-worker-nodes/)
+- [Docker Socket Proxy from Tecnativa](https://github.com/Tecnativa/docker-socket-proxy)
+
## Labels: overriding default behavior
### Using Docker with Swarm Mode
@@ -292,7 +342,7 @@ If a container is linked to several networks, be sure to set the proper network
For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name.
Or if your service references external network use it's name instead.
-[2] `traefik.frontend.auth.basic.users=EXPR `:
+[2] `traefik.frontend.auth.basic.users=EXPR`:
To create `user:password` pair, it's possible to use this command:
`echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g`.
The result will be `user:$$apr1$$9Cv/OMGj$$ZomWQzuQbL.3TRCS81A1g/`, note additional symbol `$` makes escaping.
@@ -306,7 +356,7 @@ It also means that Traefik will manipulate only one backend, not one backend per
| Label | Description |
|-------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `traefik.frontend.headers.customRequestHeaders=EXPR ` | Provides the container with custom request headers that will be appended to each request forwarded to the container.
Format: HEADER:value||HEADER2:value2
|
+| `traefik.frontend.headers.customRequestHeaders=EXPR` | Provides the container with custom request headers that will be appended to each request forwarded to the container.
Format: HEADER:value||HEADER2:value2
|
| `traefik.frontend.headers.customResponseHeaders=EXPR` | Appends the headers to each response returned by the container, before forwarding the response to the client.
Format: HEADER:value||HEADER2:value2
|
#### Security Headers
@@ -321,7 +371,7 @@ It also means that Traefik will manipulate only one backend, not one backend per
| `traefik.frontend.headers.customFrameOptionsValue=VALUE` | Overrides the `X-Frame-Options` header with the custom value. |
| `traefik.frontend.headers.forceSTSHeader=false` | Adds the STS header to non-SSL requests. |
| `traefik.frontend.headers.frameDeny=false` | Adds the `X-Frame-Options` header with the value of `DENY`. |
-| `traefik.frontend.headers.hostsProxyHeaders=EXPR ` | Provides a list of headers that the proxied hostname may be stored.
Format: `HEADER1,HEADER2` |
+| `traefik.frontend.headers.hostsProxyHeaders=EXPR` | Provides a list of headers that the proxied hostname may be stored.
Format: `HEADER1,HEADER2` |
| `traefik.frontend.headers.isDevelopment=false` | This will cause the `AllowedHosts`, `SSLRedirect`, and `STSSeconds`/`STSIncludeSubdomains` options to be ignored during development.
When deploying to production, be sure to set this to false. |
| `traefik.frontend.headers.publicKey=VALUE` | Adds HPKP header. |
| `traefik.frontend.headers.referrerPolicy=VALUE` | Adds referrer policy header. |
@@ -342,63 +392,63 @@ You can define as many segments as ports exposed in a container.
Segment labels override the default behavior.
-| Label | Description |
-|------------------------------------------------------------------------------------|------------------------------------------------------------------------|
-| `traefik..backend=BACKEND` | Same as `traefik.backend` |
-| `traefik..domain=DOMAIN` | Same as `traefik.domain` |
-| `traefik..port=PORT` | Same as `traefik.port` |
-| `traefik..protocol=http` | Same as `traefik.protocol` |
-| `traefik..weight=10` | Same as `traefik.weight` |
-| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
-| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
-| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
-| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
-| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
-| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
-| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
-| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
-| `traefik..frontend.auth.forward.authResponseHeaders=EXPR` | Same as `traefik.frontend.auth.forward.authResponseHeaders` |
-| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
-| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
-| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
-| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
-| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
-| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
-| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
-| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
-| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` |
-| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` |
-| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` |
-| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
-| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
-| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
-| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
-| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
-| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
-| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
-| `traefik..frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
-| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
-| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
-| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
-| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
-| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` |
-| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
-| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` |
-| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` |
-| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` |
-| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
-| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
-| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
-| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
-| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` |
-| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
-| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
+| Label | Description |
+|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
+| `traefik..backend=BACKEND` | Same as `traefik.backend` |
+| `traefik..domain=DOMAIN` | Same as `traefik.domain` |
+| `traefik..port=PORT` | Same as `traefik.port` |
+| `traefik..protocol=http` | Same as `traefik.protocol` |
+| `traefik..weight=10` | Same as `traefik.weight` |
+| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
+| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
+| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
+| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
+| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
+| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
+| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
+| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
+| `traefik..frontend.auth.forward.authResponseHeaders=EXPR` | Same as `traefik.frontend.auth.forward.authResponseHeaders` |
+| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
+| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
+| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
+| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
+| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
+| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
+| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
+| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
+| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` |
+| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` |
+| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` |
+| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
+| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
+| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
+| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
+| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
+| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
+| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
+| `traefik..frontend.passTLSClientCert.infos.subject.organization=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.organization` |
+| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
+| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber` |
+| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
+| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
+| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` |
+| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
+| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` |
+| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` |
+| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` |
+| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
+| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
+| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
+| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
+| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` |
+| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
+| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
#### Custom Headers
| Label | Description |
|----------------------------------------------------------------------|----------------------------------------------------------|
-| `traefik..frontend.headers.customRequestHeaders=EXPR ` | Same as `traefik.frontend.headers.customRequestHeaders` |
+| `traefik..frontend.headers.customRequestHeaders=EXPR` | Same as `traefik.frontend.headers.customRequestHeaders` |
| `traefik..frontend.headers.customResponseHeaders=EXPR` | Same as `traefik.frontend.headers.customResponseHeaders` |
#### Security Headers