I have written a simple Dockerfile for a sample FastAPI application. My objective is to play around with using a non-root user to own files and the main process within the container. Everything seems fine except that I was expecting to get a permission denied error when attempting to bind to port 80, which did not happen. Why is that? It looks as though my newly-created foo user has root privileges for some reason.
requirements.txt
fastapi==0.110.0
uvicorn==0.29.0
main.py
from datetime import datetime
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def get_home():
return {"message": "Yo!", "when": datetime.now()}
Dockerfile
FROM python:3.10-slim-bullseye
RUN groupadd bar && useradd -g bar -m foo
USER foo
ENV PATH=/home/foo/.local/bin:$PATH
WORKDIR /app
COPY --chown=foo:bar --chmod=444 requirements.txt .
RUN pip install -r requirements.txt
COPY --chown=foo:bar --chmod=444 main.py .
ENTRYPOINT ["uvicorn", "--host", "0.0.0.0", "--port", "80", "main:app"]
Why is the user allowed to use the privileged port within the container?
In a container environment like DOCKER, it provides an isolated environment, so FOO users can bind to port 80 even if they do not have ROOT privileges, regardless of your HOST environment.
Inside the container, non-root users can also open any port, including low-numbered ports (usually 1024 or less), such as port 80.
Thank you very much for your reply. You’ve made me realize that, yes, I have had containerized applications binding to port 80 several times before (which were mapped to some other port on the host) and never even questioned it. It was only that this time I was misled by a colleague at work who was very keen in warning me about using a port other than 80 once I moved from using the root user.
Thank you again for helping me get back on track on this issue.
A short research shows that kernel 4.11 introduced the sysctl parameter ipv4.ip_unprivileged_port_start, which is responsible for this. By default, it is set to 1024, but Docker will set it to 0 for created containers.