kaysond / trafficjam

A Docker firewall for your reverse proxy network
132 stars 8 forks source link

Docker socket proxy support #15

Open Pingumania opened 2 years ago

Pingumania commented 2 years ago

Would it be possible to implement support for Docker Socket Proxy?

This probably isn't possible if the host networking mode is required.

kaysond commented 2 years ago

It should already be supported, actually. You just need to set the DOCKER_HOST env var, and the docker command in the container will automatically connect to whatever you set it to (i.e. the docker-socket-proxy tcp socket). It won't work in swarm, but it would be relatively easy to add.

I'm curious why you want to use dsp. Running trafficjam in a container is just a convenience. You could just as easily run the script as root on the host itself. Since the container isn't connected to the outside world, the risk of giving it access to the docker socket is essentially zero.

Pingumania commented 2 years ago

I'm curious why you want to use dsp. Running trafficjam in a container is just a convenience. You could just as easily run the script as root on the host itself. Since the container isn't connected to the outside world, the risk of giving it access to the docker socket is essentially zero.

Honestly just my OCD, all my services that require access to the docker socket use the dsp. I also don't see any security concerns.

I hadn't had the time to test DOCKER_HOST yet.

kaysond commented 2 years ago

Honestly just my OCD

I totally get it. I'm the same! I'm gonna close this but feel free to comment if you have trouble with the env var

Adito5393 commented 1 year ago

Hey @kaysond, thanks for sharing this cool, simple tool. I have managed to run it behind the Docker socket proxy with only 2 permissions (CONTAINERS & NETWORKS). Unfortunately, it can only run if the proxy is also in network_mode: host. (or so, I thought..)

Here is the docker-compose.yml you want to give a try:

version: "3.9"

networks:
  traefik_net:
    external: true
  backend_traefik:
    external: false

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    restart: always
    networks:
      - backend_traefik

  proxy-docker:
    image: tecnativa/docker-socket-proxy:0.1.1
    container_name: traefik_docker_socket_proxy
    restart: always
    networks:
      - backend_traefik
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - LOG_LEVEL=warning
      # Traefik ONLY!
      - CONTAINERS=1

  trafficjam-proxy-docker:
    image: tecnativa/docker-socket-proxy:0.1.1
    container_name: traefik_trafficjam_socket_proxy
    restart: always
    network_mode: host
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - LOG_LEVEL=warning
      - CONTAINERS=1
      - NETWORKS=1

  trafficjam:
    image: kaysond/trafficjam:v2.1.1
    container_name: traefik_trafficjam
    restart: always
    cap_add:
      - NET_ADMIN
    network_mode: host
    environment:
      - DOCKER_HOST=tcp://0.0.0.0:2375
      - TZ
      - NETWORK=traefik_net
      - WHITELIST_FILTER=ancestor=traefik:2.10
      - DEBUG=1

This setup, however, opens the docker tcp port on the host:

ss -tulpn | grep LISTEN
tcp   LISTEN 0      3000         0.0.0.0:2375      0.0.0.0:*    users:(("haproxy",pid=28169,fd=6))

Run the docker-socket-proxy on a dedicated network

Then, the issue is that I can't use the docker DNS for the tcp URL, e.g. DOCKER_HOST=tcp://traefik_trafficjam_socket_proxy:2375

traefik_trafficjam  | [2023-06-07 18:47:00] ERROR: Unexpected error while determining network driver: 
traefik_trafficjam  | error during connect: Get "http://trafficjam-proxy-docker:2375/v1.24/networks/traefik_net": dial tcp: lookup trafficjam-proxy-docker on 1.1.1.1:53: no such host

If I hard code the DOCKER_HOST to the trafficjam-proxy-docker located on it's dedicated subnetwork (DOCKER_HOST=tcp://172.22.0.2:2375), it works.

TLDR

How can I set automatically the env DOCKER_HOST to use the IP of a certain container? On the host, I can infer it via:

docker container inspect -f '{{ .NetworkSettings.Networks.traefik_backend_trafficjam.IPAddress }}' traefik_trafficjam_socket_proxy
172.22.0.2
kaysond commented 1 year ago

How can I set automatically the env DOCKER_HOST to use the IP of a certain container?

I don't think you can, unfortunately.

Then, the issue is that I can't use the docker DNS for the tcp URL, e.g. DOCKER_HOST=tcp://traefik_trafficjam_socket_proxy:2375

This doesn't work because when you use network_mode: host, it uses the host DNS server by default. You might be able to play with some of the container dns options and get it to use the docker dns server instead: https://docs.docker.com/network/#dns-services

This setup, however, opens the docker tcp port on the host:

I don't really see this as a big problem, though you should probably configure it to bind to localhost (127.0.0.1) only, instead of 0.0.0.0. The proxy is set to read only anyways, so even if an attacker could access the port, they couldn't do anything permanent with it. They could get some information about your docker networks and containers, but realistically, if someone can access it, you're probably in bad shape anyways.

This does bring up a good point, though, that it's not trivial to get dsp working when you have to be on the host network namespace. I'll have to give it some more thought. There might be some tricks you can play with iptables and veth interfaces (which could be automated via the container).

kaysond commented 1 year ago

In the meantime, though, you could set the dsp container to have a static ip: https://www.howtogeek.com/devops/how-to-assign-a-static-ip-to-a-docker-container/

Adito5393 commented 1 year ago

Thanks @kaysond for the idea! I will share here the complete working docker-compose.yml for others not to waste time figuring it out:

version: "3.9"

networks:
  traefik_net:
    external: true
  backend_traefik:
    external: false
  backend_trafficjam:
    external: false
    ipam:
      driver: default
      config:
        - subnet: 172.16.238.0/30

services:
  traefik:
    container_name: traefik
    image: traefik:2.10
    restart: always
    # ... rest of your config
    networks:
      - backend_traefik

  # Docker Socket Proxy - Security Enchanced Proxy for Docker Socket
  proxy-docker:
    image: custom-image/docker-socket-proxy:0.1.1
    container_name: traefik_docker_socket_proxy
    restart: always
    networks:
      - backend_traefik
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      # debug,info,notice,warning,err,crit,alert,emerg
      - LOG_LEVEL=warning
      # Traefik ONLY!
      - CONTAINERS=1

  trafficjam-proxy-docker:
    image: custom-image/docker-socket-proxy:0.1.1
    container_name: traefik_trafficjam_socket_proxy
    # restart: always
    privileged: true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      # debug,info,notice,warning,err,crit,alert,emerg
      - LOG_LEVEL=warning
      - CONTAINERS=1
      - NETWORKS=1
    networks:
      backend_trafficjam:
        ipv4_address: 172.16.238.2
    depends_on:
      - traefik

  trafficjam:
    image: kaysond/trafficjam:v2.1.1
    container_name: traefik_trafficjam
    # restart: always
    cap_add:
      - NET_ADMIN
    network_mode: host
    environment:
      - DOCKER_HOST=tcp://172.16.238.2:2375
      - TZ
      - NETWORK=traefik_net
      - WHITELIST_FILTER=ancestor=traefik:2.10
      - DEBUG=1
    depends_on:
      - trafficjam-proxy-docker

Pay special attention to the depends_on: part of the config. FYI: the custom-image/docker-socket-proxy was created to fix the "Provider connection error unexpected EOF" as discussed in issue 21:

ARG TAG=0.1.1
FROM ghcr.io/tecnativa/docker-socket-proxy:$TAG

RUN apk add --no-cache curl

HEALTHCHECK --interval=9m --timeout=5s --retries=3 \
  CMD curl -f http://localhost:2375/_ping || exit 1

Feel free to link to this comment inside the README.md file (so people don't expect you to provide support for this type of configuration)

PS: I also get this warning (see issue 79 and 74) and everything seems to work as expected: traefik_docker_socket_proxy | [WARNING] 166/085731 (1) : Can't open server state file '/var/lib/haproxy/server-state': No such file or directory

Adito5393 commented 4 months ago

For future users, I've switched to CetusGuard for better API rules support and these are the rules that work for me:

  trafficjam-proxy-docker:
    image: docker.io/hectorm/cetusguard:v1.0.11
    container_name: traefik_trafficjam_socket_proxy
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      CETUSGUARD_BACKEND_ADDR: "unix:///var/run/docker.sock"
      CETUSGUARD_FRONTEND_ADDR: "tcp://:2375"
      CETUSGUARD_RULES: |
        ! List containers
        GET %API_PREFIX_CONTAINERS%/json
        ! Inspect a container
        GET %API_PREFIX_CONTAINERS%/%CONTAINER_ID%/json
        ! Inspect a network
        GET %API_PREFIX_NETWORKS%/%NETWORK_NAME%
      # Warning = 4 and Debug = 7
      CETUSGUARD_LOG_LEVEL: "4"
    networks:
      backend_trafficjam:
        ipv4_address: 172.16.238.2
    depends_on:
      - traefik

The rest of the yml is the same.