Dockerfile
Rama main · réplica de lectura del repositorio original.
# Production Dockerfile for py-idp
#
# Build: docker build -t py-idp:0.2.0 .
# Run: docker run --rm -p 8080:8080 \
# -e IDP_API_KEY=... \
# -e IDP_STORAGE_BACKEND=sql \
# -e IDP_STORAGE_PATH=sqlite:////data/idp.db \
# -v idp-data:/data \
# py-idp:0.2.0
# ---- Build stage (deps only; cached separately from source) ----
FROM python:3.12-slim@sha256:44ff437bba879d4941b710a369a8f19266aea34b29002807f0c487fabc9eec9b AS deps
WORKDIR /app
# Install build deps (none currently required; future-proofs native extensions)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
COPY pyproject.toml ./
COPY src ./src
COPY examples ./examples
# Install with the [api] extra (FastAPI + uvicorn). --no-cache-dir keeps the
# image small; --no-compile keeps .pyc files out of the layer.
RUN pip install --no-cache-dir --no-compile -e .[api]
# ---- Runtime stage ----
FROM python:3.12-slim@sha256:44ff437bba879d4941b710a369a8f19266aea34b29002807f0c487fabc9eec9b AS runtime
# Hardening: run as a non-root user. Bind to a fixed UID so volume mounts
# from the host work predictably across deployments.
RUN groupadd --system --gid 1000 idp \
&& useradd --system --uid 1000 --gid idp --home-dir /app --shell /sbin/nologin idp
WORKDIR /app
COPY --from=deps --chown=idp:idp /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=deps --chown=idp:idp /usr/local/bin /usr/local/bin
COPY --from=deps --chown=idp:idp /app/src /app/src
COPY --from=deps --chown=idp:idp /app/examples /app/examples
# Persistent storage for SQLite + uploads. Mount a volume here in prod.
RUN mkdir -p /data/uploads && chown -R idp:idp /data
# Install tini as PID 1. PID 1 doesn't handle SIGTERM cleanly without an
# init shim; tini forwards signals to the child process and reaps zombies,
# so in-flight HTTP requests drain on `docker stop` instead of being killed
# mid-flight. Pinned to tini 0.19.0-1 (the current Debian-bookworm
# version) for reproducibility — using `tini` without a version would
# float with the base image's apt index.
RUN apt-get update && apt-get install -y --no-install-recommends \
tini=0.19.0-1 \
&& rm -rf /var/lib/apt/lists/*
ENV IDP_UPLOAD_DIR=/data/uploads
# Real-time logs (no buffering) so container log collectors see entries
# immediately.
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
IDP_API_HOST=0.0.0.0 \
IDP_API_PORT=8080 \
IDP_LOG_LEVEL=INFO \
IDP_LOG_FORMAT=human \
IDP_API_KEY_REQUIRED=true \
IDP_STORAGE_BACKEND=memory \
IDP_RATE_LIMIT_PER_MINUTE=60
# CRITICAL: lock X-Forwarded-For trust to a specific CIDR. The previous
# default of "*" trusted the header from anyone, which lets an attacker
# who can reach the uvicorn port directly (bypassing the reverse proxy)
# spoof their IP to bypass per-IP rate limits and taint audit logs.
# Override at deploy time with:
# docker build --build-arg FORWARDED_ALLOW_IPS=10.0.0.0/8 .
# Production default is the loopback only (the reverse proxy on the same
# host). For k8s, set to the in-cluster pod CIDR.
ARG FORWARDED_ALLOW_IPS=127.0.0.1/32
ENV IDP_FORWARDED_ALLOW_IPS=${FORWARDED_ALLOW_IPS}
USER idp
EXPOSE 8080
# Healthcheck hits /healthz (cheap, no LLM call). 30s interval, 5s timeout,
# 3 retries before marking unhealthy.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=2).read()" \
|| exit 1
# Run uvicorn under tini. Single worker is correct for development; for prod
# use --workers $(( 2 * $(nproc) )) or rely on the orchestrator (k8s) to
# Run uvicorn under tini so PID 1 reaps zombies and forwards signals.
# Single worker is correct for development; for prod use
# --workers $(( 2 * $(nproc) )) or rely on the orchestrator (k8s) to
# scale replicas. Forwarded-allow-ips is baked into the runtime env from
# the build-arg above; exec form would NOT expand it, so we keep an
# explicit `sh -c` shell between tini and uvicorn.
ARG FORWARDED_ALLOW_IPS
CMD ["/usr/bin/tini", "--", "sh", "-c", "exec uvicorn idp.api:app \
--host 0.0.0.0 \
--port 8080 \
--proxy-headers \
--forwarded-allow-ips \"${IDP_FORWARDED_ALLOW_IPS}\" \
--log-level info"]