Non-root user able to bind to port 80; why?

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?

1 Like

Hello.

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.

best regards,
limsangwoons

3 Likes

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.

Cheers!

1 Like

Thank you.

I’m glad that it was a good answer, too

Best Regards.
limsangwoon

1 Like

I have learned something new today.

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.

3 Likes

Thank you for adding this to the discussion, for future reference.

1 Like