Ga naar hoofdinhoud

Online zetten: niet als root

Hier bouw je op verder: Rechten op bestanden en mappen

Weet je dit niet meer zeker? Lees het terug voordat je verdergaat.

Je container uit les 18 draait nog. Vraag wie je site draait:

docker exec gastenboek whoami
root

Het antwoord is root: je site mag alles in de container. Dat is een risico. Zit er een gat in je code, zoals een bestandsnaam van een bezoeker uit Invoer controleren: een bestandsnaam van een bezoeker, dan kan wie dat gat vindt ook alles. Hij kan je code veranderen, programma's installeren, en zoeken naar een weg uit de container.

Een webserver hoort daarom te draaien als een gewone gebruiker, die zo weinig mag als kan.

Een eigen gebruiker in het image​

RUN useradd --system app maakt een gebruiker app zonder wachtwoord en zonder thuismap: niemand logt als hem in. USER app zegt dat alles hierna als app draait, ook de CMD.

Voorspel
Je zet alleen RUN useradd --system app en USER app na COPY . . in je Dockerfile, bouwt, en start een container. Wat gebeurt er?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Daarom maakt de Dockerfile de map data zelf, en geeft hij hem aan app. Zet na COPY . . deze twee regels:

RUN useradd --system app && mkdir data && chown app data
USER app

&& voert de volgende stap alleen uit als de vorige lukte. Je hele Dockerfile is nu:

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .
RUN python -m pip install -r requirements.txt

COPY . .

RUN useradd --system app && mkdir data && chown app data
USER app

CMD ["fastapi", "run", "main.py", "--port", "8000"]

Bouw en start opnieuw, en kijk:

docker rm -f gastenboek
docker build -t gastenboek .
docker run -d --name gastenboek -p 8000:8000 gastenboek
docker exec gastenboek whoami

Met docker exec gastenboek ls -l data zie je je databases, met app als eigenaar. Zet de Dockerfile in git:

git add Dockerfile
git commit -m "Niet als root"
git push
Controlevraag
Je zet de regels in een andere volgorde: eerst RUN useradd --system app, dan USER app, en daarna RUN mkdir data && chown app data. Wat gebeurt er bij docker build?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Er gaat iets mis​

unable to open database file​

Je site start, maar geeft bij sommige pagina's een 500, en in docker logs gastenboek staat:

sqlite3.OperationalError: unable to open database file

Oorzaak: een database staat nog niet in data/, en app mag in /app niets maken. Als root zag je die fout nog niet.

Oplossing: zoek in main.py naar SqliteDict(" zonder data/ erachter, verbeter het, en bouw opnieuw.

Permission denied: 'data'​

De container stopt meteen, en docker logs gastenboek eindigt met:

PermissionError: [Errno 13] Permission denied: 'data'

Oorzaak: de Dockerfile maakt de map data niet. Dan probeert os.makedirs("data", exist_ok=True) uit les 18 hem te maken, als app, in de map van root.

Oplossing: zet && mkdir data && chown app data achter useradd in je Dockerfile, en bouw opnieuw.

cannot create directory ‘data’: File exists​

mkdir: cannot create directory ‘data’: File exists

Oorzaak: de map data uit je project kwam met COPY . . mee in het image, met je testdatabases erin.

Oplossing: zet data/ in .dockerignore, zoals in les 18, en bouw opnieuw. Je .dockerignore is dan:

.venv
__pycache__
.git
*.db
data/

Opdrachten​

Opdracht 1: Investigate - Wat mag app niet?​

Probeer als app je code te veranderen: docker exec gastenboek touch main.py. Wat zegt de container? Wat betekent dat voor iemand die een gat in je site vindt?

Antwoord
touch: cannot touch 'main.py': Permission denied

main.py is van root, en app mag hem lezen maar niet veranderen. Vindt iemand een gat in je site, dan kan hij je databases lezen en veranderen, want die zijn van app. Maar je code aanpassen, of iets installeren, lukt hem niet. Dat is minder erg, en het is precies wat je met een eigen gebruiker wilde.

Door naar les 20: je berichten bewaren.