# syntax=docker/dockerfile:1.7 # FIPS 140-3 variant (workstream A of the FIPS roadmap). Builds on # chainguard-base-fips so python/node/openssl resolve to Chainguard's # FIPS-provider-linked packages from the image's pinned virtualapk repo. # Build requires a Chainguard token: # CGR_TOKEN=$(chainctl auth token --audience apk.cgr.dev) \ # docker build --secret id=cgr-token,env=CGR_TOKEN -f docker/Dockerfile.fips . ARG LITELLM_BUILD_IMAGE=cgr.dev/berri.ai/chainguard-base-fips@sha256:4f23c1a31be6a0778c4851c54474c7630b2feda7d113c7b1b5e7b1def8c89b04 ARG LITELLM_RUNTIME_IMAGE=cgr.dev/berri.ai/chainguard-base-fips@sha256:4f23c1a31be6a0778c4851c54474c7630b2feda7d113c7b1b5e7b1def8c89b04 ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a # UI builder only emits static JS assets; no binary from it reaches the final # image, so it does not need a FIPS base. ARG UI_BUILD_IMAGE=node:24.19-alpine3.24@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43 # Checksum from https://www.pgbouncer.org/downloads/ ARG PGBOUNCER_VERSION=1.26.0 ARG PGBOUNCER_SHA256=afd25dd61ee6775d37b40629b87ce08736b3e6955f3057bb212e410fbf21c71d FROM $UV_IMAGE AS uvbin FROM $LITELLM_BUILD_IMAGE AS pgbouncer-builder ARG PGBOUNCER_VERSION ARG PGBOUNCER_SHA256 USER root # openssl-dev here is the FIPS-configured system OpenSSL, so pgbouncer links # libcrypto.so.3 and inherits the FIPS provider at runtime. RUN --mount=type=secret,id=cgr-token \ HTTP_AUTH="basic:virtualapk.cgr.dev:user:$(cat /run/secrets/cgr-token)" \ apk add --no-cache build-base pkgconf libevent-dev openssl-dev curl WORKDIR /build RUN curl -fsSL -o pgbouncer.tar.gz "https://www.pgbouncer.org/downloads/files/${PGBOUNCER_VERSION}/pgbouncer-${PGBOUNCER_VERSION}.tar.gz" && \ echo "${PGBOUNCER_SHA256} pgbouncer.tar.gz" | sha256sum -c - && \ tar xzf pgbouncer.tar.gz --strip-components=1 && \ ./configure --prefix=/usr/local --with-openssl=/usr && \ make -j"$(nproc)" pgbouncer && \ install -m 0755 pgbouncer /usr/local/bin/pgbouncer FROM --platform=$BUILDPLATFORM $UI_BUILD_IMAGE AS ui-builder ENV NEXT_TELEMETRY_DISABLED=1 \ npm_config_fund=false \ npm_config_audit=false WORKDIR /ui COPY ui/litellm-dashboard/package.json ui/litellm-dashboard/package-lock.json ./ COPY ui/litellm-dashboard/vendor/ ./vendor/ RUN --mount=type=cache,target=/root/.npm npm ci --prefer-offline COPY ui/litellm-dashboard/ ./ RUN npm run build FROM $LITELLM_BUILD_IMAGE AS builder WORKDIR /app USER root COPY --from=uvbin /uv /usr/local/bin/uv COPY --from=uvbin /uvx /usr/local/bin/uvx RUN --mount=type=secret,id=cgr-token \ HTTP_AUTH="basic:virtualapk.cgr.dev:user:$(cat /run/secrets/cgr-token)" \ apk add --no-cache \ bash \ gcc \ python-3.13 \ python-3.13-dev \ rust \ openssl \ libssl3 \ openssl-dev \ nodejs \ npm \ libsndfile # UV_PYTHON_DOWNLOADS=0: uv must never substitute a standalone CPython with # its own bundled OpenSSL for the FIPS-linked system python. ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ UV_PYTHON_DOWNLOADS=0 \ PATH="/app/.venv/bin:${PATH}" COPY pyproject.toml uv.lock ./ COPY enterprise/pyproject.toml enterprise/ COPY litellm-proxy-extras/pyproject.toml litellm-proxy-extras/ COPY packaging/litellm-proxy/pyproject.toml packaging/litellm-proxy/ RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --group admin-mcp \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ --extra bedrock-realtime \ --python python3.13 COPY . . RUN rm -rf litellm/proxy/_experimental/out COPY --from=ui-builder /ui/out/. litellm/proxy/_experimental/out/ RUN sed -i 's/\r$//' docker/build_admin_ui.sh && chmod +x docker/build_admin_ui.sh && ./docker/build_admin_ui.sh # litellm-proxy, the opt-in Rust forwarding server, is left out of this image. RUN uv sync --frozen --no-install-package litellm-proxy --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --group admin-mcp \ --extra extra_proxy \ --extra semantic-router \ --extra saml \ --extra bedrock-realtime \ --python python3.13 RUN HOME=/opt/prisma XDG_CACHE_HOME=/opt/prisma/.cache PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ npm_config_cache=/root/.npm \ prisma generate --schema=./schema.prisma RUN sed -i 's/\r$//' docker/entrypoint.sh && chmod +x docker/entrypoint.sh && \ sed -i 's/\r$//' docker/prod_entrypoint.sh && chmod +x docker/prod_entrypoint.sh FROM $LITELLM_RUNTIME_IMAGE AS runtime ARG LITELLM_RELEASE_TAG="" ENV LITELLM_RELEASE_TAG=${LITELLM_RELEASE_TAG} USER root # Unlike the non-FIPS images, the public Wolfi repo is deliberately NOT added # here: apk in this image may only resolve FIPS-linked packages from the # pinned Chainguard repo. RUN --mount=type=secret,id=cgr-token \ HTTP_AUTH="basic:virtualapk.cgr.dev:user:$(cat /run/secrets/cgr-token)" \ apk add --no-cache bash openssl libssl3 openssl-fips-test tzdata nodejs python-3.13 libsndfile libevent COPY --from=pgbouncer-builder /usr/local/bin/pgbouncer /usr/local/bin/pgbouncer WORKDIR /app ENV PATH="/app/.venv/bin:${PATH}" \ PRISMA_BINARY_CACHE_DIR=/opt/prisma/binaries \ PRISMA_CLI_PATH=/opt/prisma/binaries/node_modules/.bin/prisma \ PRISMA_CLI_QUERY_ENGINE_TYPE=binary \ PRISMA_OFFLINE_MODE=true COPY --from=builder /app/.venv /app/.venv COPY --from=builder /app/docker /app/docker COPY --from=builder /app/schema.prisma /app/schema.prisma COPY --from=builder /app/litellm/proxy/prisma_migration.py /app/litellm/proxy/prisma_migration.py COPY --from=builder /app/enterprise /app/enterprise COPY --from=builder /app/litellm-proxy-extras /app/litellm-proxy-extras COPY --from=builder /opt/prisma /opt/prisma RUN find /app/.venv -type f -path "*/tornado/test/*" -delete && \ find /app/.venv -type d -path "*/tornado/test" -delete && \ chmod -R a+rX /opt/prisma && \ test -x /opt/prisma/binaries/node_modules/.bin/prisma && \ test -f /opt/prisma/binaries/node_modules/prisma/build/index.js && \ python -c "from prisma.client import BINARY_PATHS; paths = list(BINARY_PATHS.query_engine.values()); assert paths and all(p.startswith('/opt/prisma/') for p in paths), paths" # Build-time FIPS assertions. binutils (objdump) is installed only in this # throwaway stage; the final image below is FROM runtime and never sees it. FROM runtime AS fips-check RUN --mount=type=secret,id=cgr-token \ HTTP_AUTH="basic:virtualapk.cgr.dev:user:$(cat /run/secrets/cgr-token)" \ apk add --no-cache binutils RUN openssl-fips-test RUN chmod +x docker/scan_bundled_crypto.sh && \ docker/scan_bundled_crypto.sh /app/.venv /opt/prisma /usr/local/bin FROM runtime AS final # Forces the fips-check stage to build and records its evidence in the image. COPY --from=fips-check /fips-scan-report.txt /fips-scan-report.txt EXPOSE 4000/tcp ENTRYPOINT ["docker/prod_entrypoint.sh"] CMD ["--port", "4000"]