Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Docker integration: Exposing Docker socket to Traefik container is a serious security risk #4174
Do you want to request a feature or report a bug?
What did you do?
I followed the official instructions to get Traefik running with Docker (and Let's Encrypt).
What did you expect to see?
I would have expected that the part of Traefik which communicates with the Docker daemon and updates Traefik's configuration accordingly when containers are started/stopped would happen in a different container, separate from the Traefik container as the latter is typically exposed to the internet.
What did you see instead?
The official docs instructed me to expose the Docker socket to the Traefik container itself. This is widely recognized to be a serious security issue, see 1, 2, 3, 4 and 5, as it basically means that anyone who manages to compromise Traefik obtains root on the host machine. Note that this is even worse than running a regular (non-Docker-integrated) reverse proxy outside any container directly on the host machine as such a proxy usually doesn't run as root.
Unfortunately, I couldn't find any other way in the docs to get Traefik set up with Docker.
Move the part of Traefik that regularly pulls the container list from the Docker daemon and updates the Traefik configuration into a separate binary so that it can be run in a separate container, similar to what the nginx-proxy project suggests (see section "separate containers"). This seems to be the only solution that fully isolates the
PS: I am aware that some might consider my report a feature request, not a bug, as the current behavior & instructions seem to be the officially accepted way to integrate Traefik with Docker. However, I still think that any security issue – whether widely accepted or not – should 1) be considered a bug and 2) be at least mentioned in the official documentation.
Nov 8, 2018
I absolutely agree that this should be addressed more thoroughly. I just wanted to share here, for anyone who comes across it, what I'm currently using as something of a workaround. I'm running a minimally adapted version of https://github.com/Tecnativa/docker-socket-proxy as a standalone container on each swarm manager, connected to a docker network specific to the purpose, connecting the traefik service to that network as well, and pointing Traefik to the proxied port.
Why a standalone container? ...because I have namespace mapping enabled and selinux enforcing, and I needed
Why a slight modification instead of just using the approach as supplied by Tecnativa (or copying the config and using haproxy directly)? ...because I wanted to install socat in the image and modify the haproxy docker entrypoint to use socat to redirect the container's /dev/log socket to STDOUT. (Edit: I did not originally mention that this is because haproxy doesn't follow the general Docker practice of logging to STDOUT unless instructed otherwise.)
I'm sure this could be done with quite a few other approaches. In fact, at one point I was trying to figure out if I could accomplish this using nothing but
@codethief Thanks for reporting this.
@emilevauge can you shed any light on what the ".....far better solution for production deployments that should be out soon ;)" is specifically for the swarm setup? i.e. does it incorporate some sort of sidecar like this? or involved this workaround? if not what is the new solution going to be?
For anyone else coming across this, this appears to work
# Create network for local docker host api access docker network create -d overlay dockersocket4traefiknet # Create network for app docker network create -d overlay myappnetwork # Start NGINX dummy for test, this has no access to the `dockersocket4traefiknet` docker service create \ --network myappnetwork \ --label traefik.frontend.rule='Host:mynginx' \ --label traefik.enable=true \ --label traefik.port=80 \ --name nginx-test \ nginx # Start the docker-socket-proxy container for traefik bound to `dockersocket4traefiknet` # Grant read only GET request access to SERVICES/NETWORKS/TASKs apis # there are no published ports so only other services granted access on the # dockersocket4traefiknet network can hit this named service @ 2375 docker service create \ --mode global \ --constraint=node.role==manager \ --network dockersocket4traefiknet \ -e SERVICES=1 \ -e NETWORKS=1 \ -e TASKS=1 \ --name dockersocket4traefik \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ tecnativa/docker-socket-proxy # Start Traefik.. note it has access to 2 networks the `dockersocket4traefiknet` for swarm info # and the `myappnetwork` for containers to proxy to docker service create \ --name traefik-test \ --mode global \ --constraint=node.role==manager \ --network myappnetwork \ --network dockersocket4traefiknet \ --publish 9080:80 \ --publish 9999:8080 \ --publish 9443:443 \ traefik:1.6.6 \ --entryPoints='Name:http Address::80' \ --defaultentrypoints="http" \ --retry \ --debug=true \ --logLevel=DEBUG \ --docker \ --docker.endpoint="tcp://dockersocket4traefik:2375" \ --docker.swarmmode \ --docker.domain=traefik \ --docker.watch \ --docker.exposedbydefault=false \ --web \ --web.statistics # Dashboard shows service OK http://localhost:9999/dashboard/ # Logs legit docker service logs -tf traefik-test # Access service OK http://mynginx:9080/
My fork has swapped out Tecnativa's build hooks for Gitlab CI and I'm using a more recent haproxy image as the base, but the functional difference consists entirely of
referenced this issue
Nov 23, 2018
Hello everyone, you might be interested into this PR #4225 , which discuss security concerns with Docker and Swarm mode backends.
The content is based from a set of issues, including this one.
Thanks all for your feedbacks on this important topic, which we do value a lot!
@dduportal Thanks for adding those remarks to the docs! I think they are a very good start! Then again, I do think they are a bit vague. Consider e.g.:
IMO it should be stressed that if Traefik gets compromised, the attacker effectively gains root access. A user reading the docs shouldn't have to go to one of the linked articles to figure this out.
Regarding the "security compensation":
Two remarks here:
At CloudBees I've been investigating a comparable issue to grant build container access to the docker socket, which exposes the whole infrastructure.
A possible way to balance this risk is to use a docker API proxy to only allow legitimate API to be used by traefik (typically, allow
I've been a bit concerned about potentially tieing a world facing container into my docker socket too.
I have put together a glorified shell script that helps decouple the docker sock and my traefik router. I am using it successfully in my lab. It works by having a traefik container attached to docker, purely to generate config. The script then pulls the config down via /api, and publishes it to my 'real' Traefik instance (which is not bound to Docker), but has --rest enabled. The key here is that the config is pushed to the internet facing container, not pulled, avoiding having to have connectivity to other components.
The script is designed to be provider agnostic (PROVIDERS could be a list), not sure if docker is the only backend that has this issue?
Comments welcome. Tom.
I've got an example of this setup doing all the swarm things needed. A few thoughts:
I feel like this setup is simple enough, and lowers the risk enough that it's a pattern I'd like to try with all the other tools that need docker API access. In the real world, I've never seen a Swarm cluster without something mounting the socket for management and control over docker... so all the warnings about "don't mount the socket" tends to get thrown out the minute someone wants to run Traefik, Portainer, Swarmpit, etc. so I'm glad we're coming up with these alternative patterns to let people have options to control their environments and also keep them as secure as possible.
referenced this issue
Dec 12, 2018
could be usefull to document the docker API traefik relies on.