# Multi-stage build for Gatehouse Auth API # Build stage FROM python:3.11-slim as builder # Install build dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libpq-dev \ curl \ && rm -rf /var/lib/apt/lists/* # Create virtual environment RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" # Copy requirements files WORKDIR /app COPY requirements/base.txt requirements/base.txt COPY requirements/production.txt requirements/production.txt # Install dependencies # Upgrade build tooling too: clears CVE-2026-24049 (wheel) and CVE-2026-23949 (jaraco.context) RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \ pip install --no-cache-dir -r requirements/production.txt # Production stage FROM python:3.11-slim # Install runtime dependencies # apt-get upgrade pulls patched openssl/openssh/etc. so the image isn't pinned to # whatever was current when the base layer was published. # curl intentionally omitted: it was only used by HEALTHCHECK (now a stdlib Python # check), and dropping it removes libcurl4t64 + libssh2 and their unfixed CVEs. # NOTE: openssh-client retained for SSH CA workflows; drop it too if nothing shells # out to ssh/scp (sshkey-tools signing is pure Python). RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \ libpq5 \ openssh-client \ && rm -rf /var/lib/apt/lists/* # Patch the base image's system-level build tooling that Trivy flags in # /usr/local site-packages: wheel (CVE-2026-24049) and the jaraco.context # (CVE-2026-23949) vendored by setuptools. Runs against system pip before the # venv takes over PATH below. RUN pip install --no-cache-dir --upgrade pip setuptools wheel # Create non-root user RUN groupadd --gid 1000 appgroup && \ useradd --uid 1000 --gid appgroup --shell /bin/bash --create-home appuser # Copy virtual environment from builder COPY --from=builder /opt/venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" # Copy application code WORKDIR /app COPY --chown=appuser:appgroup . . # Create log and session directories RUN mkdir -p /app/logs /app/flask_session && chown -R appuser:appgroup /app/logs /app/flask_session # Switch to non-root user USER appuser # Expose port EXPOSE 5000 # Health check (stdlib urllib — avoids shipping curl) HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD ["python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:5000/api/health', timeout=5).getcode()==200 else 1)"] # Run gunicorn with gevent workers CMD ["gunicorn", "--bind", "0.0.0.0:5000", \ "--workers", "4", \ "--worker-class", "gevent", \ "--worker-connections", "1000", \ "--timeout", "120", \ "--access-logfile", "-", \ "--error-logfile", "-", \ "--log-level", "info", \ "wsgi:application"]