"Een container is een geïsoleerde ruimte, dus is het niet oké om binnenin root te gebruiken?"

"Als ik een USER maak, worden er alleen maar lagen toegevoegd en dat is vervelend..."

"Als ik de container USER de volume bind-mount van de host-directory wil laten gebruiken, is het een gedoe om de rechten goed te regelen..."

Veel ontwikkelaars denken zo en gebruiken de standaard root gebruiker in de Dockerfile.

Maar dit is een zeer gevaarlijke praktijk op het gebied van beveiliging. De 'isolatie' van een container is geen perfecte firewall, en het draaien van een container met root rechten kan een snelle manier zijn om de hele server in gevaar te brengen.

In dit artikel zal ik duidelijk uitleggen waarom het niet goed is om containers als root uit te voeren en hoe je dit kunt voorkomen.


1. Het ergste scenario: "Container Escape"



Dit is de meest doorslaggevende reden om root gebruik te vermijden.

  • Basis mapping: De root gebruiker (UID 0) binnen een Docker container is in principe hetzelfde als de host (Host) server's root gebruiker (UID 0).

  • Wanneer de isolatie doorbroken is: Stel je voor dat een aanvaller erin slaagt om de geïsoleerde omgeving van de container te 'ontvluchten' door gebruik te maken van een kwetsbaarheid in de applicatie, Docker, of zelfs de Linux kernel zelf.

  • Gevolg: Als de container toen draaide met root rechten, zou de aanvaller onmiddellijk toegang krijgen tot de root rechten van de host server. De hele server wordt dan volledig overgenomen.

Analogie: Een container draaien als root is als een "gast met de hotelsleutel van de master" in een kamer laten slapen. Zodra die gast de deur van zijn kamer (de container) opent, kan hij vrij door het hele hotel (de host) rondlopen.

Anderzijds, als je de container uitvoert als een niet-prive gebruiker zoals appuser (UID 1001), wat zou er dan gebeuren? Zelfs als een aanvaller ontsnappen zou kunnen, zou hij enkel de rechten hebben van appuser, wat de schade zou minimaliseren.


2. Het principe van de minimale rechten (Principle of Least Privilege)

Het meest fundamentele principe van beveiliging is dat "alle programma's en gebruikers alleen de minimale rechten mogen hebben die nodig zijn om hun taken uit te voeren".

Voor het draaien van webapplicaties zijn root rechten totaal niet nodig.

  • Als het root is: Als een aanvaller binnenkomt in de container (zelfs als hij niet ontsnapt), is hij in de container root.

    • Hij kan malware scanners en crypto miners vrijelijk installeren via apt-get install.

    • Hij kan alle bestanden aanpassen en verwijderen, inclusief configuratiebestanden met database verbindingsinformatie (settings.py etc.).

  • Als het appuser is: Zelfs als een aanvaller binnenkomt, is hij alleen maar appuser.

    • apt-get install? Toestemming geweigerd.

    • Het aanpassen van systeemconfiguratiebestanden? Toestemming geweigerd.

    • De schade is beperkt tot de applicatiebroncode directory die appuser bezit.


3. Veelvoorkomende Misvattingen Rechtzetten



🤔 "Voegt het USER commando alleen maar lagen toe aan de afbeelding?"

Nee. Dit is de grootste misvatting.

Het USER commando in een Dockerfile genereert geen bestandssysteemlagen. Dit commando voegt enkel een instructie toe aan de metadata van de afbeelding, die zegt: "stel de basisgebruiker in als 'appuser' wanneer deze container opstart".

De afbeeldingsgrootte neemt geen 1KB toe en heeft geen invloed op de bouwsnelheid.

Uiteraard, het RUN useradd... commando creëert een gebruiker en voegt een zeer kleine laag toe, maar dit is de kost die je uiteraard moet betalen voor beveiliging.

🤔 "Ik heb toch root nodig om poort 80 te openen?"

Dat klopt. In Linux kunnen alleen root poorten onder de 1024 openen (bijv. 80, 443). Maar dat betekent niet dat je nog steeds een container als root moet uitvoeren.

De moderne aanpak is als volgt:

  1. Voer de app in de container uit met appuser rechten op een hoge poort zoals 8000.

  2. Laat Docker de poorten mappen (docker run -p 80:8000) of laat een reverse proxy zoals Nginx de externe aanvraag op poort 80 doorverwijzen naar poort 8000.

Voor de container zijn er totaal geen root rechten nodig.


4. Hoe: Best Practices voor Dockerfile

Hoe pas je dit toe? Het toevoegen van de volgende paar regels aan het einde van de Dockerfile is geen verspilling maar een fundamentele en belangrijke beveiligingsregel.

Dockerfile

FROM python:3.12-slim

WORKDIR /app

# ... (nodige taken zoals apt-get install, pip install)

# 1. Maak een niet-prive groep en gebruiker aan
# -r: maak aan als systeemgebruiker/groep, --no-create-home: maak geen thuismap aan
RUN groupadd -r appgroup && useradd -r -g appgroup --no-create-home appuser

# 2. Geef bij het kopiëren van de applicatiebestanden het eigendom aan appuser
# (de bestanden in de WORKDIR volgen ook dit eigendom)
COPY --chown=appuser:appgroup . .

# 3. Verander de gebruiker voor het uitvoeren van de volgende commando's naar appuser
USER appuser

# 4. Voer de applicatie uit op een hoge poort zoals 8000
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

Samenvatting

Het draaien van een container als root is het opgeven van het concept van "defensie in diepte". Het is een handeling waarbij je zelf de tweede verdedigingslinie (USER) verwijdert, voor het geval de eerste verdedigingslijn van isolatie wordt doorbroken.

Controleer nu meteen je Dockerfile.