Files
max/Dockerfile
T
finnandClaude Opus 5.5 931243dd60 Harden the container: non-root, no build tools, read-only, stdout logging
The app ran as root, and the production image contained gcc, vim, wget
and gnupg. Code execution in the container would have allowed changing
the app code and fetching or compiling further tools.

- Multi-stage build: the wheels (psycopg2) are built in a build stage.
  The runtime image only contains libpq5, postgresql-client and
  wait-for-it (724 MB -> 298 MB).
- The app runs as the system user max (uid/gid 10001). The code is
  owned by root and precompiled, the user has no writable directory.
- Log to stdout only; docker collects it. The log file under /app/log
  was lost on every container recreation anyway.
- docker-compose: read-only filesystem (tmpfs for /tmp), no
  capabilities, no-new-privileges and log rotation (5 x 10 MB).
- Add a .dockerignore and set MAX_ORIGIN in docker-compose.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 18:09:30 +00:00

40 lines
1.2 KiB
Docker

# Build stage: compile the wheels (psycopg2 needs gcc and libpq-dev)
FROM python:3.15-slim-trixie AS build
RUN apt-get update && \
apt-get install --no-install-recommends -y gcc libc-dev libpq-dev && \
rm -rf /var/lib/apt/lists/*
WORKDIR /build
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
# Runtime stage: no compiler and no tools besides what db-setup.sh needs
FROM python:3.15-slim-trixie
RUN apt-get update && apt-get upgrade -y && \
apt-get install --no-install-recommends -y libpq5 postgresql-client wait-for-it && \
rm -rf /var/lib/apt/lists/*
COPY --from=build /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
RUN groupadd --system --gid 10001 max && \
useradd --system --uid 10001 --gid max --no-create-home --shell /usr/sbin/nologin max
WORKDIR /app
ENV PYTHONPATH=/app/
ENV FLASK_APP=max.app
# Owned by root, so the app cannot modify its own code
COPY max/ ./max
COPY scripts/prod/ .
# Precompile, since the app cannot write __pycache__ at runtime
RUN python -m compileall -q max
USER max
ENTRYPOINT ["./entrypoint.sh"]
CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:8000", "max.app:app"]