Protéger vos dockers

Protéger le socket docker avec un proxy en lui accordant uniquement les droits désirés.

Protéger vos dockers

Bonjour,

Le socket docker c'est celui que vous utilisez par exemple avec Portainer qui vous donne les droits complets sur l'administration de vos dockers. Sauf que si votre docker se trouve compromis pour une raison x ou y, la personne va avoir accès rapidement à tout votre stack grâce au socket. Le socket c'est quand vous écrivez dans votre docker cette ligne:

/var/run/docker.sock:/var/run/docker.sock

L'idée c'est d'utiliser cette image docker pour créer un intermédiaire (proxy) avec qui nous allons pouvoir gérer les droits.

Les prérequis:
- Docker
- Docker compose

La première chose à faire va être de créer le réseau sur le lequel nous voulons que ce docker fonctionne (et on suppose que vous avez déjà un réseau local que je vais appeler ici backend).

docker network create proxy

On va ensuite créer le docker compose qui va bien:

########################### NETWORKS ###############################################
networks:
  backend:
    external: true
    driver: bridge
  proxy:
    external: true
    driver: bridge    
########################### SERVICES ###############################################
services:
########################### DOCKER SOCKET PROXY ##########################################################
  dockersocket:
    # Security-enhanced proxy for the Docker Socket
    # https://github.com/Tecnativa/docker-socket-proxy
    # https://hub.docker.com/r/tecnativa/docker-socket-proxy
    container_name: dockersocket
    image: tecnativa/docker-socket-proxy:latest
    restart: unless-stopped
    privileged: true
    networks:
      - proxy  
    ports:
     - "$DOCKER_SOCKET:2375"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock     
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro      
    environment:  
      - LOG_LEVEL=info # debug,info,notice,warning,err,crit,alert,emerg
      ## Variables match the URL prefix (i.e. AUTH blocks access to /auth/* parts of the API, etc.).
      # 0 to revoke access.
      # 1 to grant access.
      ## Granted by Default
      - EVENTS=1
      - PING=1
      - VERSION=1
      ## Revoked by Default
      # Security critical
      - AUTH=0
      - SECRETS=0
      - POST=1 # Watchtower
      - DELETE=1 # Watchtower
      # Not always needed
      - BUILD=0
      - COMMIT=0
      - CONFIGS=0
      - CONTAINERS=1 # Traefik, portainer, etc.
      - DISTRIBUTION=0
      - EXEC=0
      - IMAGES=1 # Portainer
      - INFO=1 # Portainer
      - NETWORKS=1 # Portainer
      - NODES=0
      - PLUGINS=0
      - SERVICES=1 # Portainer
      - SESSION=0
      - SWARM=0
      - SYSTEM=0
      - TASKS=1 # Portainer
      - VOLUMES=1 # Portainer   

Il faut bien évidemment déclarer le port de votre container (DOCKER_SOCKET) dans votre fichier .env ou alors le mettre directement dans votre compose.

Pour le compose, c'est assez straight forward. Au niveau des variables d'environnement, vous pouvez ajuster les droits que vous donnez à votre proxy (0 = interdire, 1 = autoriser).

Maintenant quand vous avez un container qui utiliser le docker socket, vous allez remplacer les lignes :

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  

par les lignes suivante (et rajouter le network proxy):

    environment:
      - DOCKER_HOST=tcp://dockersocket:2375      

Nous allons voir par exemple comment l'appliquer pour le container Portainer.

############################### PORTAINER #######################################################     
  portainer:
    # Interface graphique docker manageement
    # https://hub.docker.com/r/portainer/portainer-ce
    container_name: portainer
    image: portainer/portainer-ce:latest
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true      
    networks:
      - backend
      - proxy
    ports:
      - "$PORTAINER_PORT:9000"
      - "$PORTAINERSERVER_PORT:8000"   
    environment:
      - DOCKER_HOST=tcp://dockersocket:2375      
    volumes:
      - $USERDIR/Portainer:/data     
      #- /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro

A noter que vous devez bien sur rajouter le network proxy dans le compose de portainer pour qu'il puisse se connecter sur le socket proxy en plus de son réseau local habituel (ici backend).

Et c'est tout ! Ca permet de réduire la surface d'attaque et c'est toujours ça de pris. A noter que le container n'utilise absolument aucune ressource, chez moi il utilise 0% de CPU et 1Mo de RAM. Il n'y a donc aucune raison de ne pas l'utiliser.

@+