Skip to main content
  1. Concetti/

/var/run/docker.sock - il socket di Docker

·5 mins
Alessio Barnini
Author
Alessio Barnini
Table of Contents

Cosa fa
#

File speciale sul filesystem che funge da canale di comunicazione diretto tra il Docker CLI e il demone dockerd. E' un Unix domain socket — non usa la rete, comunica direttamente nel kernel. Chiunque abbia accesso in scrittura a questo file ha controllo completo su Docker e, di conseguenza, sull'host intero.

TL;DR
#

docker CLI  ──► /var/run/docker.sock ──► dockerd
                       ^
                       Unix domain socket
                       non e' rete — e' filesystem
                       solo sulla stessa macchina
                       passa nel kernel

Se monti questo socket dentro un container:
  container ──► /var/run/docker.sock ──► dockerd
  il container ha controllo totale su Docker
  privilege escalation garantita

Socket di rete vs Unix domain socket
#

SOCKET DI RETE (TCP/IP)
────────────────────────────────────────────────
  processo A
  stack di rete (TCP/IP)
(può attraversare la rete)
  stack di rete
  processo B

  identificato da: IP:porta
  puo' essere su macchine diverse
  traffico puo' uscire dalla macchina

UNIX DOMAIN SOCKET
────────────────────────────────────────────────
  processo A
  kernel (IPC — Inter Process Communication)
  processo B

  identificato da: path su filesystem (/var/run/docker.sock)
  solo sulla stessa macchina
  non esce mai dalla macchina
  molto piu' veloce — nessun overhead di rete

Come funziona normalmente
#

Tu (terminale)
    │  digiti: docker ps
Docker CLI (/usr/bin/docker)
    │  scrive sul socket: "GET /containers/json"
(protocollo HTTP su socket Unix)
/var/run/docker.sock
dockerd (il demone)
    │  risponde con la lista dei container
Docker CLI
output nel terminale
sequenceDiagram
    participant U as Tu (docker CLI)
    participant S as /var/run/docker.sock
    participant D as dockerd

    U->>S: docker ps (HTTP su Unix socket)
    S->>D: richiesta
    D->>S: lista container JSON
    S->>U: output formattato

Il problema — montare il socket in un container
#

# docker-compose.yml — PERICOLOSO
services:
  app:
    image: myapp
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      #   ^                    ^
      #   socket sull'host     montato dentro il container

Cosa succede:

HOST
├── dockerd (controlla tutto Docker)
│       ^
│       │ comunica tramite
│       │
├── /var/run/docker.sock  ← montato dentro il container
│       ^
│       │ il container ci scrive sopra
│       │
└── CONTAINER
        └── processo dentro il container
            puo' fare qualsiasi operazione Docker
            come se fosse il CLI sull'host

L'attacco — privilege escalation completa
#

# Scenario: attaccante ha compromesso un container
# Il container ha docker.sock montato

# Dentro il container, l'attaccante esegue:
docker run -it \
  -v /:/host \          # monta la ROOT dell'host dentro il nuovo container
  alpine \              # immagine minimale
  chroot /host          # cambia la root del processo a /host
                        # ora "vede" il filesystem reale dell'host

# Risultato: shell con accesso root all'host intero
# Il container era "isolato" — ma docker.sock ha rotto l'isolamento
PRIMA (isolamento normale):
┌─────────────────────────────┐
│  HOST                       │
│  ├── filesystem host        │
│  │                          │
│  └── CONTAINER              │
│       └── filesystem iso-   │
│           lato dal host     │
└─────────────────────────────┘

DOPO (docker.sock montato + attacco):
┌─────────────────────────────┐
│  HOST                       │
│  ├── filesystem host  ◄─────┼── container vede tutto
│  │                          │   e puo' modificare tutto
│  └── CONTAINER              │
│       └── accesso tramite   │
│           docker.sock       │
└─────────────────────────────┘

chroot — cosa fa
#

chroot (change root) cambia la directory root per un processo:

chroot /host bash
# d'ora in poi per questo processo:
# / e' /host
# /etc e' /host/etc
# /bin e' /host/bin
# il processo non vede niente fuori da /host

# Usato legittimamente per:
# - recovery di sistema (come nel rescue Hetzner)
# - ambienti di build isolati
# - container primitivi (prima di Docker)

Non confondere con chown (change owner — cambia il proprietario di un file).


Quando e' accettabile montare docker.sock
#

In alcuni casi legittimi il socket deve essere montato:

# Caso legittimo — tool di monitoring che deve leggere i container
services:
  portainer:
    image: portainer/portainer-ce
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  # necessario per funzionare

  traefik:
    image: traefik
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro  # :ro = read-only
      #                                          ^
      #                                          mitigazione parziale

:ro (read-only) riduce il rischio — il container puo' leggere lo stato dei container ma non crearne di nuovi. Non elimina il rischio completamente.


Come rilevare container con docker.sock montato
#

# Controlla tutti i container in esecuzione
docker inspect $(docker ps -q) | grep -i "docker.sock"

# Alternativa piu' leggibile
docker ps -q | xargs docker inspect --format \
  '{{.Name}}: {{range .Mounts}}{{if eq .Source "/var/run/docker.sock"}}SOCKET MONTATO{{end}}{{end}}'

# In un sistema sospetto — primo controllo
find /proc/*/fd -lname /var/run/docker.sock 2>/dev/null

Scenario Reale — Blue Team
#

Un analista SOC riceve un alert: processo insolito su un server di produzione con molti container. Controlla:

# 1. Quali container hanno docker.sock montato?
docker inspect $(docker ps -q) | grep docker.sock

# 2. Quel container ha creato altri container di recente?
docker events --since 1h | grep "container create"

# 3. Esistono container creati di recente con volumi sospetti?
docker ps -a --format "{{.CreatedAt}}\t{{.Names}}\t{{.Mounts}}" | sort -r | head -20

Se trova un container creato dall'interno di un altro container — specialmente con -v /:/host — e' compromissione attiva.

Warning

Non montare mai /var/run/docker.sock in produzione a meno che non sia strettamente necessario. E' l'equivalente di dare a un processo le chiavi master di tutto il sistema.

Note

Alternativa sicura: Docker API con TLS e certificati client, oppure socket proxy come tecnativa/docker-socket-proxy che espone solo le API necessarie con permessi granulari.

Dove l'ho incontrato
#

Collegato a
#

Related