Ghid de securitate · România

Cum securizez containerele Docker în producție?

Un container nu e o mașină virtuală: împarte kernelul cu hostul. Rulat ca root, cu --privileged sau cu socket-ul Docker montat, un container compromis înseamnă root pe server. Izolarea e reală doar dacă o configurezi.

Actualizat la

Răspuns scurt

  1. Securizezi containerele Docker rulându-le ca utilizator non-root, declarat prin USER în Dockerfile, fără --privileged și cu --cap-drop ALL, adăugând înapoi doar capabilitățile strict necesare.
  2. Nu montezi niciodată /var/run/docker.sock într-un container, pentru că accesul la socket echivalează cu root pe host.
  3. Folosești imagini minimale, fixate pe digest, scanate cu Trivy sau Grype în CI, rulate cu sistem de fișiere read-only și limite de resurse.
  4. Verifici periodic configurația cu docker-bench-security, care automatizează CIS Docker Benchmark, și treci pe Docker rootless unde e posibil.
Referința de configurare
CIS Docker Benchmark, automatizat de docker-bench-security
Utilizatorul din container
non-root, declarat cu USER în Dockerfile
Ce nu montezi niciodată
/var/run/docker.sock
Flag-uri la rulare
--cap-drop ALL --read-only --security-opt no-new-privileges

De ce un container ca root e root pe host

Docker izolează procese cu namespace-uri și cgroups, dar kernelul e comun. Dacă procesul din container rulează ca root și cineva găsește o vulnerabilitate în kernel sau o configurație permisivă, ieșirea din container îl lasă root pe server. --privileged dezactivează aproape toată izolarea. Montarea socket-ului Docker e echivalentă: cine vorbește cu daemonul poate porni un container privilegiat cu rădăcina hostului montată. De aceea imaginea declară un utilizator neprivilegiat, iar containerul pornește cu capabilitățile eliminate și cu no-new-privileges.

Imagini minimale, fixate și scanate

O imagine bazată pe o distribuție completă aduce sute de pachete cu vulnerabilitățile lor, deși aplicația folosește câteva biblioteci. Alegi imagini minimale, alpine, slim sau distroless, și construiești multi-stage: compilatoarele rămân în etapa de build. Fixezi imaginea de bază pe digest, nu pe tag, și o reconstruiești când scanerul raportează un patch. Scanarea rulează în CI, înainte de push în registru; o imagine cu vulnerabilități critice nu ajunge în producție. Nu pui secrete în imagine și nu rulezi npm sau pip în containerul de producție.

  • FROM node:22-alpine@sha256:... în loc de FROM node:latest
  • Limite: --memory, --cpus, --pids-limit, ca un container să nu sufoce hostul
  • O rețea Docker per aplicație; baza de date nu e pe rețeaua publică
Controale de securitate pentru containere Docker în producție
ControlCum îl apliciCe previne
Utilizator non-rootUSER app în DockerfileRoot în container = root pe host la o evadare
Fără capabilități inutile--cap-drop ALL, --cap-add doar ce trebuieEscaladare prin capabilități de kernel
Fără privilegii noi--security-opt no-new-privilegesEscaladare prin binare setuid
Sistem de fișiere read-only--read-only, --tmpfs /tmpScrierea de backdoor-uri în container
Socket Docker nemontatFără -v /var/run/docker.sockControl total asupra daemonului
Imagini scanate și fixateTrivy în CI, FROM pe digestVulnerabilități cunoscute în producție

Comenzi și configurări

Dockerfile multi-stage cu utilizator non-root
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build --chown=node:node /app/dist ./dist
COPY --from=build --chown=node:node /app/node_modules ./node_modules
USER node
HEALTHCHECK CMD wget -qO- http://127.0.0.1:3000/health || exit 1
CMD ["node", "dist/server.js"]
Rulare cu izolare întărită
docker run -d --name app \
  --read-only --tmpfs /tmp \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  --memory 512m --cpus 1 --pids-limit 200 \
  --network app-net \
  -p 127.0.0.1:3000:3000 \
  exemplu.ro/app@sha256:<digest>
Scanare și audit CIS
trivy image --severity HIGH,CRITICAL --exit-code 1 exemplu.ro/app:1.4.0

# Auditul CIS e singura excepție de la regula „nu monta socketul": rulează o dată,
# manual, nu ca serviciu permanent. Fără montările de mai jos, secțiunile CIS 1-3
# raportează fals sau se sar. `:ro` pe un socket Unix NU limitează nimic.
docker run --rm --net host --pid host --userns host --cap-add audit_control \
  -v /var/lib:/var/lib:ro -v /etc:/etc:ro \
  -v /usr/bin/containerd:/usr/bin/containerd:ro -v /usr/bin/runc:/usr/bin/runc:ro \
  -v /usr/lib/systemd:/usr/lib/systemd:ro \
  -v /var/run/docker.sock:/var/run/docker.sock docker/docker-bench-security

Exemple practice

SaaS din Iași cu API Node.js în Docker

Imaginea rula ca root pentru că nimeni nu adăugase USER. O vulnerabilitate într-o bibliotecă de procesare de imagini a permis scrierea de fișiere oriunde în container. Trecerea pe utilizatorul node și pe sistem de fișiere read-only a limitat următorul incident la directorul temporar.

Agenție web din Timișoara cu monitorizare în container

Un container de monitorizare avea /var/run/docker.sock montat „ca să vadă celelalte containere”. Era, de fapt, root pe un host cu zece site-uri de client. A fost înlocuit cu un proxy de socket cu drepturi doar de citire, iar montarea directă a fost interzisă.

Greșeli frecvente

  • Crezi că containerele sunt izolate implicit, deși rulate ca root sau cu --privileged sunt root pe host.
  • Montezi /var/run/docker.sock într-un container „doar pentru monitorizare”.
  • Folosești FROM imagine:latest și nu știi ce versiune rulează în producție.
  • Expui API-ul Docker pe TCP fără TLS sau publici porturi cu -p fără adresă, ocolind firewall-ul.

Cum te ajută 4hosting

  • VPS-urile sunt pregătite pentru Docker și Kubernetes; serviciul Docker & Kubernetes proiectează arhitectura de containere, rețelele separate și rollout-ul.
  • Serviciul Hardening & Compliance include hardening-ul containerelor după CIS Docker Benchmark; CI/CD & Monitoring adaugă scanarea imaginilor și centralizează logurile în Grafana, Prometheus și Loki.
  • Orele de DevOps incluse lunar, 1–8 la VPS și 10 la dedicate și GPU, se cer din panoul de client, secțiunea „Servicii DevOps”; o rulare docker-bench-security cu remedieri intră de obicei în cotă.

Întrebări conexe

  • Docker rootless merge cu orice aplicație?

    Cu majoritatea, da. Limitările apar la porturile sub 1024, care cer configurare suplimentară, la unele drivere de rețea și de storage și la aplicații care au nevoie de capabilități de kernel. Testezi în staging; dacă aplicația merge, câștigi un strat de izolare fără să schimbi codul.

  • Cum aplic patch-uri de securitate în containere?

    Nu actualizezi în container, reconstruiești imaginea: schimbi digest-ul imaginii de bază, rulezi din nou build-ul și scanarea în CI și faci rollout cu noua versiune. Containerele sunt imutabile; un apt upgrade în containerul care rulează dispare la următoarea repornire.

  • Trebuie să trec pe Kubernetes ca să fiu în siguranță?

    Nu. Toate controalele de mai sus se aplică la Docker simplu și la Compose. Kubernetes adaugă politici de admitere, secrete gestionate și izolare de rețea la scară, dar și o suprafață de configurare mult mai mare. Îl alegi când ai nevoie de orchestrare, nu de securitate în sine.

Cere o verificare de securitate

Un server de producție e atacat automat din primele minute după ce primește IP public, indiferent cât de mic e proiectul. Ghidul ordonează controalele după impact, de la accesul SSH până la răspunsul la incident, cu legislația din România care se aplică. Fiecare temă are o pagină dedicată, cu răspuns scurt, exemple și configurări.