Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/docker-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Docker Security Scan

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
scan:
name: Scan Docker Image with Anchore
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build image
run: docker build -t python-samples-fastapi-restful .

- name: Run Anchore scan
uses: anchore/scan-action@v2
with:
image-reference: python-samples-fastapi-restful
fail-build: true
137 changes: 70 additions & 67 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,67 +1,70 @@
# ------------------------------------------------------------------------------
# Stage 1: Builder
# This stage builds the application and its dependencies.
# ------------------------------------------------------------------------------
FROM python:3.13.3-slim-bookworm AS builder
WORKDIR /app

# Install system build tools for packages with native extensions
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential gcc libffi-dev libssl-dev && \
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb

# Pre-build all dependencies into wheels for reproducibility and speed
COPY --chown=root:root --chmod=644 requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir=/app/wheelhouse -r requirements.txt

# ------------------------------------------------------------------------------
# Stage 2: Runtime
# This stage creates the final, minimal image to run the application.
# ------------------------------------------------------------------------------
FROM python:3.13.3-slim-bookworm AS runtime
WORKDIR /app

# Metadata labels
LABEL org.opencontainers.image.title="πŸ§ͺ RESTful API with Python 3 and FastAPI"
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful API made with Python 3 and FastAPI"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.source="https://github.com/nanotaboada/python-samples-fastapi-restful"

# Copy prebuilt wheels and install dependencies
COPY --chown=root:root --chmod=644 requirements.txt .
COPY --from=builder --chown=root:root --chmod=755 /app/wheelhouse /app/wheelhouse
RUN pip install --no-cache-dir --no-index --find-links /app/wheelhouse -r requirements.txt && \
rm -rf /app/wheelhouse

# Copy application code (read-only)
COPY --chown=root:root --chmod=644 main.py ./
COPY --chown=root:root --chmod=755 database ./database
COPY --chown=root:root --chmod=755 models ./models
COPY --chown=root:root --chmod=755 routes ./routes
COPY --chown=root:root --chmod=755 schemas ./schemas
COPY --chown=root:root --chmod=755 services ./services

# Copy metadata for GHCR (read-only)
COPY --chown=root:root --chmod=644 README.md ./
COPY --chown=root:root --chmod=755 assets ./assets

# Copy entrypoint sctipt and SQLite database
COPY --chown=root:root --chmod=755 scripts/entrypoint.sh ./entrypoint.sh
COPY --chown=root:root --chmod=755 sqlite3-db ./docker-compose

# Create non-root user and make volume mount point writable
RUN groupadd --system fastapi && \
adduser --system --ingroup fastapi --disabled-password --gecos '' fastapi && \
mkdir -p /sqlite3-db && \
chown fastapi:fastapi /sqlite3-db

# Drop privileges
USER fastapi

# Logging output immediately
ENV PYTHONUNBUFFERED=1

EXPOSE 9000

ENTRYPOINT ["./entrypoint.sh"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "9000"]
# ------------------------------------------------------------------------------
# Stage 1: Builder
# ------------------------------------------------------------------------------
FROM python:3.13.3-slim-bookworm AS builder
WORKDIR /app

# Install build dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
gcc \
libffi-dev \
libssl-dev && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Copy and pre-build Python dependencies
COPY requirements.txt .
RUN pip install --upgrade pip && \

Check warning on line 19 in Dockerfile

View check run for this annotation

codefactor.io / CodeFactor

Dockerfile#L19

Avoid use of cache directory with pip. Use `pip install --no-cache-dir <package>`. (DL3042)

Check warning on line 19 in Dockerfile

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

Dockerfile#L19

Pin versions in pip. Instead of `pip install <package>` use `pip install <package>==<version>` or `pip install --requirement <requirements file>`
pip wheel --no-cache-dir --wheel-dir=/app/wheelhouse -r requirements.txt

# ------------------------------------------------------------------------------
# Stage 2: Runtime
# ------------------------------------------------------------------------------
FROM python:3.13.3-slim-bookworm AS runtime
WORKDIR /app

# Metadata
LABEL org.opencontainers.image.title="πŸ§ͺ RESTful API with Python 3 and FastAPI"
LABEL org.opencontainers.image.description="Proof of Concept for a RESTful API made with Python 3 and FastAPI"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.source="https://github.com/nanotaboada/python-samples-fastapi-restful"

# Install runtime dependencies
COPY requirements.txt .
COPY --from=builder /app/wheelhouse /app/wheelhouse
RUN pip install --no-cache-dir --no-index --find-links=/app/wheelhouse -r requirements.txt && \
rm -rf /app/wheelhouse

# Copy app code
COPY main.py .
COPY database/ ./database/
COPY models/ ./models/
COPY routes/ ./routes/
COPY schemas/ ./schemas/
COPY services/ ./services/
COPY README.md .
COPY assets/ ./assets/

# Copy startup script and SQLite DB seed
COPY scripts/entrypoint.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
COPY sqlite3-db ./docker-compose

# Create non-root user and make volume writable
RUN groupadd --system fastapi && \
useradd --system --gid fastapi --create-home fastapi && \
mkdir -p /sqlite3-db && \
chown -R fastapi:fastapi /app /sqlite3-db

# Configure environment
ENV PYTHONUNBUFFERED=1
EXPOSE 9000

ENTRYPOINT ["./entrypoint.sh"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "9000"]

# πŸ‘‡Run with not root user
USER fastapi

2 changes: 2 additions & 0 deletions scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/bash
set -e
echo "βœ” Fixing permissions..."
chown -R fastapi:fastapi /sqlite3-db

IMAGE_DATABASE_FILE_PATH="/app/docker-compose/players-sqlite3.db"
VOLUME_DATABASE_FILE_PATH="/sqlite3-db/players-sqlite3.db"
Expand Down