Abstract
There are some containers that require you to give them access to Docker socket, so they can work as intended. An example could be a watchtower where the user exposes docker socket as volume in order to periodically apply updates to other containers running on your host.
This of course introduces a security problem. Especially if you expose such container to the Internet. An attacker might breach into your container and then try jail breaking from Docker to takeover your whole system. One security problem leads to another.
Remember! Docker is running as root
on your machine.
Solution
There are many, and in the future I may or may not extend this article to accommodate. Right now, I want to focus on docker proxy. What is it?
Docker proxy
It is a container which has access to your Docker socket and is proxying request from other containers that utilize Docker API, however it is not exposed to the Internet by default, and you should not do so just because you can. Under the hood it runs HAProxy with some rules.
Then, instead of giving full or read only access to your docker socket, you can just give to the proxy and the proxy should allow only the minimum amount of privileges to run your desired container.
The following example shows how you should not do it:
services:
traefik:
image: traefik
ports:
- 443
- 80
volumes:
# Not the most secure way to give container access to your
# Docker socket.
- /var/run/docker.sock:/var/run/docker.sock
Now, how we can leverage Docker proxy to fix above problem.
How? Very easily, let’s take a look at this docker-compose.yml
example:
services:
traefik:
image: traefik
ports:
- 443
- 80
command:
- "--providers.docker=true"
# Dockerproxy listens on 2375, so we need to tell traefik about
# this
- "--providers.docker.endpoint=tcp://dockerproxy:2375"
dockerproxy:
image: tecnativa/docker-socket-proxy
restart: always
environment:
# Here you specify list of exposed Docker APIs
CONTAINERS: 1
volumes:
# Docker socket is exposed as a read-only to docker proxy but it
# is not exposed to the Internet
- /var/run/docker.sock:/var/run/docker.sock:ro
In the above example, traefik
no longer has access to Docker socket,
which is great. Now dockerproxy
has, which is not good either, right?
Well, it is not ideal, but dockerproxy
container is not exposed to the
Internet, therefore attack surface is much, much lower.
We also gave read-only access to dockerproxy
, because it is
sufficient. However, there are some containers, which require more
permissions. In that case, you can create multiple dockerproxy
containers for each one of them.
Click here for full list of permissions