De ce procesele din containerele Docker nu ar trebui să ruleze ca rădăcină

Publicat: 2022-08-19

Grafic care arată sigla Docker

Procesele dintr-un container Docker nu ar trebui să fie rulate ca root. Este mai sigur să rulați aplicațiile ca utilizator non-root, pe care îl specificați ca parte a fișierului Dockerfile sau când utilizați docker run . Acest lucru minimizează riscul prin prezentarea unei suprafețe de atac reduse oricăror amenințări din containerul dumneavoastră.

În acest articol, veți afla despre pericolele rulării aplicațiilor containerizate ca root. Veți vedea, de asemenea, cum să creați un utilizator non-root și să configurați spația dintre nume în situațiile în care acest lucru nu este posibil.

De ce este alergatul ca rădăcină periculos?

Containerele sunt rulate implicit ca root. Daemonul Docker se execută ca root pe gazda dvs. și containerele care rulează vor fi și ele root.

Deși poate părea că root din interiorul containerului este un utilizator independent, este de fapt același cu contul root de pe gazda dvs. Separarea este asigurată doar de mecanismele de izolare a containerelor Docker. Nu există o graniță fizică puternică; containerul tău este un alt proces rulat de utilizatorul rădăcină pe nucleul gazdei tale. Aceasta înseamnă că o vulnerabilitate în aplicația dvs., în timpul de execuție Docker sau în nucleul Linux ar putea permite atacatorilor să iasă din container și să efectueze operațiuni cu privilegii root pe mașina dvs.

Există unele protecții încorporate care reduc riscul ca acest lucru să se întâmple. Rădăcina din interiorul containerului nu este privilegiată și are capacități limitate. Acest lucru împiedică containerul să folosească comenzi de administrare a sistemului, cu excepția cazului în care adăugați manual capabilități sau utilizați modul privilegiat atunci când porniți containerele.

În ciuda acestei atenuări, permiterea rulării aplicațiilor ca root rămâne un pericol. La fel cum ați restricționa utilizarea rădăcinii într-un mediu tradițional, nu este înțelept să o utilizați în mod inutil în containerele dvs. Oferiți un mediu supraprivilegiat care oferă atacatorilor mai mult un punct de sprijin în cazul în care are loc o încălcare.

Rularea aplicațiilor containerizate ca utilizator non-root

Este cea mai bună practică ca aplicațiile containerizate să ruleze ca utilizator obișnuit. Majoritatea software-ului nu necesită acces root, așa că schimbarea utilizatorului oferă un nivel imediat de apărare împotriva erupției containerului.

Ar trebui să creați un nou cont de utilizator ca una dintre etapele finale în fișierul dvs. Docker. Puteți realiza acest lucru cu instrucțiunile USER :

 DIN imaginea de bază: cel mai recent
RUN pachetul demonstrativ apt install
USER demo-user:demo-group
ENTRYPOINT [„demo-binar”]

Containerele începute de la această imagine vor rula ca demo-user . Utilizatorul va fi membru al grupului demo-group group. Puteți omite numele grupului dacă nu aveți nevoie ca utilizatorul să fie într-un grup:

 UTILIZATOR utilizator demo

Puteți specifica un ID de utilizator (UID) și un ID de grup (GID) în loc de nume:

 UTILIZATOR 950:950

Alocarea unui UID și GID cunoscut este de obicei cea mai sigură modalitate de a proceda. Împiedică utilizatorul din container să fie mapat la un cont de gazdă cu privilegii excesive.

USER este adesea specificat ca penultima etapă într-un fișier Docker. Aceasta înseamnă că puteți executa operațiuni care necesită root mai devreme în construirea imaginii. Instrucțiunea de apt install din exemplul de mai sus are o nevoie legitimă de root. Dacă instrucțiunea USER a fost plasată deasupra acesteia, apt ar fi rulat ca demo-user care nu ar avea permisiunile necesare. Întrucât instrucțiunile Dockerfile se aplică numai pentru construcțiile de imagini, nu pentru rularea containerelor, este sigur să lăsați schimbarea utilizatorului până mai târziu în Dockerfile.

Schimbarea utilizatorului rulează containerul dvs., deoarece ar putea fi necesar să actualizați permisiunile pentru fișierele și folderele pe care le accesează. Setați dreptul de proprietate asupra oricăror căi care vor fi utilizate de aplicația dvs.:

 COPIEAZĂ initial-config.yaml /data/config.yaml

USER demo-user:demo-group
RUN utilizator demonstrativ chown: grup demo/date

În acest exemplu, directorul /data trebuie să fie deținut de demo-user astfel încât aplicația să poată face modificări fișierului său de configurare. Instrucțiunea COPY anterioară va fi copiat fișierul ca root. O prescurtare este disponibilă prin utilizarea steagului --chown cu copy :

 COPY --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

Schimbarea utilizatorului la pornirea unui container

Deși puteți schimba cu ușurință utilizatorul în propriile fișiere Dockerfile, multe aplicații terță parte continuă să ruleze ca root. Puteți reduce riscul asociat utilizării acestora setând --user de fiecare dată când apelați docker run . Aceasta anulează setarea de utilizator în fișierul Dockerfile al imaginii.

 $ docker run -d --user demo-user:demo-group demo-image:latest
$ docker run -d --user demo-user demo-image:latest
$ docker run -d --user 950:950 demo-image:latest

Indicatorul --user rulează procesul containerului ca utilizator specificat. Este mai puțin sigur decât instrucțiunea Dockerfile USER , deoarece trebuie să o aplicați individual la fiecare comandă de docker run . O opțiune mai bună pentru imaginile utilizate în mod regulat este să vă creați propria imagine derivată care poate seta un nou cont de utilizator:

 FROM imagine-that-runs-as-root:latest
UTILIZATOR utilizator demo
 $ docker build . -t imagine-that-now-runs-as-non-root:latest

Schimbarea utilizatorului unei imagini terță parte poate cauza probleme: dacă containerul se așteaptă să fie rulat ca root sau trebuie să acceseze căile sistemului de fișiere deținute de root, veți vedea erori pe măsură ce utilizați aplicația. Puteți încerca să modificați manual permisiunile de pe căile care cauzează probleme. Alternativ, verificați dacă furnizorul are o metodă acceptată pentru rularea aplicației cu un cont de utilizator fără privilegii.

Gestionarea aplicațiilor care trebuie să ruleze ca root

Spațiul numelor de utilizator este o tehnică de tratare a aplicațiilor care au nevoie de anumite privilegii de root. Vă permite să mapați rădăcina în interiorul unui container către un utilizator non-root de pe gazda dvs. Rădăcina simulată din interiorul containerului are privilegiile de care are nevoie, dar un breakout nu va oferi acces root la gazdă.

Remaparea spațiului de nume este activată prin adăugarea unui userns-remap utilizator la fișierul /etc/docker/daemon.json :

 {
    "userns-remap": "implicit"
}

Utilizarea default ca valoare pentru userns-remap indică Docker să creeze automat un nou utilizator pe gazda dumneavoastră numit dockremap . Rădăcina din containere se va mapa înapoi la dockremap pe gazda dvs. Opțional, puteți specifica un utilizator și un grup existent, folosind o combinație UID/GID sau nume de utilizator/nume grup:

 {
    "userns-remap": "demo-user"
}

Reporniți demonul Docker după aplicarea modificării:

 $ sudo service docker restart

Dacă utilizați nsuser-remap: default , utilizatorul dockremap ar trebui să existe acum pe gazda dvs.:

 $ id dockremap

uid=140(dockremap) gid=119(dockremap) grupuri=119(dockremap)

Utilizatorul ar trebui să apară și în fișierele ID subordonate /etc/subuid și /etc/subgid :

 $ dockremap:231500:65535

Utilizatorului i s-a alocat un interval de 65.535 ID-uri subordonate începând de la 231500. În spațiul de nume de utilizator, ID-ul 231500 este mapat la 0 , devenind utilizatorul rădăcină în containerele dvs. Fiind un UID cu numere mari, 231500 nu are privilegii pe gazdă, astfel încât atacurile de tip breakout container nu vor putea provoca atât de multe daune.

Toate containerele pe care le începeți vor rula folosind spațiul de nume de utilizator remapat, cu excepția cazului în care renunțați cu docker run --userns=host . Mecanismul funcționează prin crearea de directoare cu spațiu de nume în /var/lib/docker care sunt deținute de UID-ul și GID-ul subordonat al utilizatorului cu spațiu de nume:

 $ sudo ls -l /var/lib/docker/231500.231500

total 14
drwx------ 5 231500 231500 13 iul 22 19:00 aufs
drwx------ 3 231500 231500 13 iul 22 19:00 containere
...

Spațiul numelor utilizatorilor este o modalitate eficientă de a crește izolarea containerului, de a evita întreruperile și de a păstra compatibilitatea cu aplicațiile care au nevoie de privilegii root. Există totuși câteva compromisuri: caracteristica funcționează cel mai bine pe o instanță Docker nouă, volumele montate de pe gazdă trebuie să aibă permisiunile ajustate, iar unele drivere de stocare externe nu acceptă deloc maparea utilizatorilor. Ar trebui să revizuiți documentația înainte de a adopta această opțiune.

rezumat

Rularea aplicațiilor containerizate ca root reprezintă un risc de securitate. Deși ușor de trecut cu vederea, izolarea oferită de containere nu este suficient de puternică pentru a separa complet utilizatorii nucleului de utilizatorii containerului. Root în container este același cu root pe gazda dvs., astfel încât un compromis de succes ar putea oferi controlul mașinii dvs.

În calitate de autor de imagini, ar trebui să includeți instrucțiunea USER în fișierul Docker, astfel încât aplicația dvs. să ruleze fără root. Utilizatorii de imagini pot înlocui acest lucru cu docker run --user pentru a atribui un anumit UID și GID. Acest lucru ajută la atenuarea cazurilor în care imaginea utilizează în mod normal root.

Puteți înăspri și mai mult securitatea prin eliminarea tuturor capabilităților din container utilizând --cap-drop=ALL , apoi plasându-le pe lista albă pe cele care sunt necesare cu --cap-add steaguri. Combinarea acestor tehnici va rula aplicația dvs. ca utilizator non-root, cu setul minim de privilegii de care are nevoie, îmbunătățindu-vă postura de securitate.