Blog

Apărarea împotriva evadării din containere: Un ghid practic pentru izolarea Docker în găzduirea multi-tenant

Aflați cum să securizați containerele Docker împotriva vulnerabilităților de evadare și a eșecurilor de izolare în medii multi-tenant, cu pași concreți și exemple.

Rezumat

Containerele Docker partajează kernelul gazdă, făcând izolația critică—în special în găzduirea multi-tenant, unde o singură evadare din container poate compromite toți chiriașii. Mulți dezvoltatori presupun că containerele sunt mașini virtuale perfect izolate, dar realitatea este diferită. Acest articol explică caracteristicile kernelului Linux din spatele izolației Docker (spații de nume, cgroups) și vectorii de atac care le amenință. Veți învăța pași practici pentru a vă întări configurația Docker: limitarea privilegiilor, utilizarea unui runtime securizat, scanarea imaginilor și implementarea segmentării rețelei. Urmând un exemplu din lumea reală al unui furnizor de găzduire multi-tenant WordPress, veți vedea cum să aplicați aceste apărări. De asemenea, acoperim avertismente precum compromisurile de performanță și utilizarea seccomp/AppArmor. Scopul este de a vă oferi o strategie robustă de izolare care previne evadarea din containere și menține chiriașii în siguranță.

Introducere

Dacă operați o platformă de găzduire multi-tenant—fie că este vorba de găzduire WordPress partajată, o aplicație SaaS sau un serviciu de mediu de dezvoltare—evadarea din container este scenariul de coșmar. O vulnerabilitate în kernel sau o configurare greșită poate permite unui chiriaș să iasă din containerul său și să acceseze datele altor chiriași sau chiar gazda. Izolarea Docker se bazează pe caracteristici ale kernelului Linux precum spațiile de nume (namespaces) și cgroups, dar configurațiile implicite sunt adesea insuficiente pentru o securitate robustă. Acest articol vă va ghida prin vectorii de atac și vă va oferi pași acționabili pentru a bloca containerele Docker, ilustrați cu un exemplu real de găzduire multi-tenant WordPress. Pentru o privire mai largă asupra orchestrației în producție, consultați ghidul nostru despre Orchestrarea aplicațiilor containerizate pregătite pentru producție.

Înțelegerea Izolării Docker

Containerele Docker utilizează spațiile de nume Linux (namespaces) pentru a oferi izolare la nivel de proces: spațiile de nume PID izolează arborii de procese, spațiile de nume de rețea separă interfețele de rețea, spațiile de nume de montare izolează montările sistemului de fișiere, iar spațiile de nume de utilizator permit maparea utilizatorului root al containerului la un utilizator gazdă ne-privilegiat. Grupurile de control (cgroups) limitează utilizarea resurselor precum CPU, memoria și I/O pe disc. Aceste caracteristici creează împreună un „sandbox” în jurul fiecărui container. Cu toate acestea, spre deosebire de o mașină virtuală care rulează un kernel separat, containerele partajează kernelul gazdă. Aceasta înseamnă că o vulnerabilitate în kernel (de ex., CVE-2022-0492) poate fi exploatată pentru a ieși din izolarea spațiului de nume al containerului. În plus, configurările greșite, cum ar fi rularea containerelor ca root în interiorul containerului, acordarea tuturor capabilităților containerului sau neabandonarea capabilităților Linux inutile, pot lărgi suprafața de atac.

Vectori de Atac

Vectorii comuni de atac includ:

  • Exploatări ale kernelului: Exploatarea unui bug în kernelul gazdă pentru a obține acces la gazdă.
  • Containere privilegiate: Rularea cu --privileged acordă toate capabilitățile și ocolește majoritatea izolării.
  • Abuz de capabilități: Chiar și fără modul complet privilegiat, un container cu capabilități periculoase precum CAP_SYS_ADMIN sau CAP_NET_ADMIN poate monta sisteme de fișiere sau manipula setările de rețea.
  • Practici nesigure ale imaginilor: Utilizarea imaginilor de bază cu vulnerabilități cunoscute sau includerea de instrumente inutile precum compilatoare sau interpretoare de shell.
  • Spații de nume de montare partajate: Montarea directoarelor gazdă în containere poate permite evadarea dacă nu sunt doar în mod read-only.

Pași Practici de Securitate

1. Rulați Containerele ca Utilizator Non-Root

Implicit, Docker rulează containerele ca root în interiorul containerului. Dacă un atacator obține acces root în interiorul containerului, are mai multă influență. Creați un utilizator în Dockerfile și utilizați directiva USER. De asemenea, evitați utilizarea flag-ului --user în Docker Compose pentru a mapa la un utilizator gazdă arbitrar, dacă este posibil.

2. Renunțați la Toate Capabilitățile și Adăugați Doar Cele Necesare

Capabilitățile Linux descompun privilegiile superutilizatorului în unități mai mici. În Docker Compose, utilizați cap_drop: ALL apoi cap_add doar cele necesare (de ex., NET_BIND_SERVICE). Evitați capabilitățile periculoase precum SYS_ADMIN, NET_ADMIN, SYS_PTRACE.

3. Utilizați Sistemul de Fișiere Root Read-Only

Setați read_only: true în definiția containerului. Acest lucru împiedică atacatorii să scrie în sistemul de fișiere al containerului. Dacă aplicația dvs. trebuie să scrie fișiere temporare, montați un volum tmpfs în acea locație.

4. Activați Remaparea Spațiului de Nume al Utilizatorilor

Remaparea spațiului de nume al utilizatorilor mapează utilizatorul root al containerului la un utilizator gazdă non-root. Aceasta adaugă un strat de izolare, deoarece chiar dacă un root al containerului evadează, acesta va avea privilegiile utilizatorului remapat. Activați-o în /etc/docker/daemon.json cu "userns-remap": "default". Fiți conștienți că acest lucru poate complica permisiunile volumelor. Pentru mai multe detalii, consultați Stăpânirea Izolării Docker pentru Găzduire Web Securizată și Eficientă.

5. Aplicați Profiluri Seccomp și AppArmor/AppArmor

Seccomp restricționează apelurile de sistem pe care un container le poate face. Docker oferă un profil seccomp implicit care blochează apelurile de sistem periculoase. Puteți, de asemenea, să creați profiluri personalizate. Similar, AppArmor (sau SELinux) oferă control de acces obligatoriu. Utilizați AppArmor pentru a limita containerul la un set minim de operațiuni permise. Profilul de securitate poate fi setat prin security_opt în Docker Compose.

6. Utilizați Imagini de Bază Minime și Scanați pentru Vulnerabilități

Alegeți imagini mici precum Alpine sau Distroless, care au o suprafață de atac mai mică. Scanați periodic imaginile cu instrumente precum Docker Scout, Trivy sau Clair. Integrați scanarea în pipeline-ul dvs. CI/CD pentru a preveni implementarea imaginilor vulnerabile.

7. Segmentarea Rețelei cu Rețele Bridge Personalizate

Creați rețele bridge separate pentru fiecare chiriaș sau nivel de aplicație. Aceasta limitează traficul est-vest. În Docker Compose, definiți rețele și izolați serviciile. Utilizați internal: true dacă un serviciu nu are nevoie de acces la Internet. Regulile de firewall pe gazdă restricționează în continuare traficul inter-container.

8. Limitați Resursele cu Cgroups

Setați limitele de CPU și memorie în Docker Compose utilizând deploy.resources.limits. Aceasta previne ca un container compromis să lanseze un atac de epuizare a resurselor. În plus, setați kernel_memory și memory_reservation pentru un control mai fin.

Exemplu din Lumea Reală: Găzduire Multi-Tenant WordPress cu Docker Compose

Considerați un scenariu în care găzduiți mai multe site-uri WordPress pentru clienți diferiți, fiecare în propriul container Docker. O configurație nesecurizată ar putea arăta astfel:

version: '3'
services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - ./wp-content:/var/www/html/wp-content
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
volumes:
  db_data:

Această configurație este vulnerabilă: containerul WordPress rulează ca root în interior, are toate capabilitățile (deoarece nu sunt renunțate), montează un director gazdă cu acces la scriere și are acces neîngrădit la rețea.

Acum să o întărim:

version: '3'
services:
  wordpress:
    image: wordpress:latest
    user: www-data
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    read_only: true
    tmpfs:
      - /var/www/html/wp-content/plugins
    security_opt:
      - seccomp=seccomp-profile.json
      - apparmor=wordpress-profile
    networks:
      - frontend
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: exampleuser
      WORDPRESS_DB_PASSWORD: examplepass
      WORDPRESS_DB_NAME: exampledb
    volumes:
      - wp-uploads:/var/www/html/wp-content/uploads
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M
  db:
    image: mysql:5.7
    user: mysql
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    networks:
      - backend
    environment:
      MYSQL_DATABASE: exampledb
      MYSQL_USER: exampleuser
      MYSQL_PASSWORD: examplepass
      MYSQL_ROOT_PASSWORD: somewordpress
    volumes:
      - db_data:/var/lib/mysql
    deploy:
      resources:
        limits:
          cpus: '0.25'
          memory: 128M
networks:
  frontend:
    driver: bridge
    internal: false
  backend:
    driver: bridge
    internal: true
volumes:
  wp-uploads:
  db_data:

Îmbunătățiri cheie:

  • Ambele containere rulează ca utilizatori non-root (www-data și mysql).
  • Toate capabilitățile sunt renunțate, doar NET_BIND_SERVICE este adăugată.
  • Sistemul de fișiere WordPress este read-only, cu excepția unui montaj tmpfs și a unui volum de încărcări.
  • Sunt aplicate profiluri Seccomp și AppArmor (ar trebui să furnizați profiluri personalizate).
  • Rețele separate izolează web-ul de baza de date, cu rețeaua bazei de date internă.
  • Limitele de resurse previn epuizarea resurselor.

Pentru mai multe informații despre întărirea specifică WordPress cu Docker, consultați Docker pentru WordPress: De ce containerele izolate schimbă totul.

Avertismente

  • Remaparea Spațiului de Nume al Utilizatorilor: Deși puternică, aceasta perturbă montarea volumelor deoarece UID-ul gazdă remapat nu este același cu UID-ul containerului. S-ar putea să fie necesar să creați în prealabil directoare cu permisiunile corecte sau să utilizați volume Docker cu suport pentru remapare.
  • Profiluri Seccomp/AppArmor: Profilurile personalizate necesită înțelegerea apelurilor de sistem și a modelelor de acces la fișiere ale aplicației dvs. Profilurile excesiv de restrictive pot perturba funcționalitatea. Testați temeinic.
  • Performanță: Straturile suplimentare de securitate precum seccomp și AppArmor au un impact minim, dar limitele de resurse și sistemele de fișiere read-only pot afecta aplicațiile cu scrieri intensive.
  • Complexitatea Orchestrației: Într-un mediu multi-tenant, gestionarea fișierelor Docker Compose per chiriaș poate deveni dificilă. Luați în considerare utilizarea unui instrument de orchestrație de nivel superior precum Kubernetes, dar acesta introduce propriile considerații de securitate.

Concluzie

Evadarea din container este o amenințare reală în găzduirea multi-tenant Docker, dar poate fi prevenită. Prin înțelegerea mecanismelor de izolare și aplicarea apărării în profunzime—renunțarea la capabilități, rularea ca non-root, activarea spațiilor de nume ale utilizatorilor, seccomp, AppArmor, segmentarea rețelei și scanarea periodică a imaginilor—puteți reduce dramatic riscul. Amintiți-vă că setările implicite ale Docker nu sunt pregătite pentru producție pentru sarcini de lucru multi-tenant. Implementați acești pași astăzi pentru a vă proteja chiriașii și infrastructura. Pentru o prezentare generală cuprinzătoare a celor mai bune practici de securitate Docker, consultați Securizarea aplicațiilor dvs. web cu Docker: Un ghid practic pentru izolare și cele mai bune practici.

Sources (5)