Skip to main content

python-fast-api-kube

Project description

Fast-api-kube API

GitHub code size in bytes GitHub License GitHub Actions Workflow Status

Branches

There is 3 branches :

A branch for each stage of deployement:

  • dev
  • stagging
  • prod

Prerequisites

Docker

Docker-compose

hadolint

for linux:

 sudo wget https://github.com/hadolint/hadolint/releases/download/v2.12.1-beta/hadolint-Linux-x86_64 -O /bin/hadolint
 sudo chmod +x /bin/hadolint

Getting started for developer

  • Clone this repo ☝️:
git clone https://github.com/maher-naija-pro/fast-api-kube.git
cd fast-api-kube
  • Build the container image :
sh scripts/build.sh

or manually execute :

docker build  --build-arg ENVIRONMENT=dev  --pull --rm -f "Dockerfile" -t fastapiapp:latest "."
  • Rename .env_exemple to .env and set your variable for posgtres database
mv .env_exemple  .env
  • Bring up the container:
sh scripts/up.sh

or manually execute :

docker compose down --volumes
docker-compose -f "docker-compose.yml" up -d --build

Tests

  • Run the test script
sh scripts/test.sh

or manually execute :

docker-compose run test

Clean Docker-compose

  • Stop docker-compose
 sudo docker compose down --volumes

Interactive API docs

Environment Variables

Variable Name Description Default Value Mandatory / Optional
POSTGRES_USER Username for the PostgreSQL database. admin Mandatory
POSTGRES_PASSWORD Password for the PostgreSQL database. secretpassword Mandatory
POSTGRES_NAME Name of the PostgreSQL database. my_database Mandatory
RATE_LIMIT_REQUESTS Maximum number of requests allowed within the time window. 100 Optional
RATE_LIMIT_WINDOW Time window (in seconds) for rate limiting requests. 60 Optional
RETRY_LIMIT Maximum number of retries allowed for failed requests. 60 Optional

Deep Configuration

Customizing Dockerfile

The Dockerfile Below are the default configurations that you may want to adjust based on your specific project needs:

  • Base Image:

    • Default: python:3.9.20-slim
    • You can customize the Python version
  • Environment:

    • Default: ENVIRONMENT=dev
    • Customize this value to switch between different environments. For example:
      • dev: For development environment (includes development dependencies).
      • staging: For staging environment.
      • prod: For production environment (includes only production dependencies).
    • Modify the default ENVIRONMENT by adjusting the ARG ENVIRONMENT line in the Dockerfile.
  • Application Port:

    • Default: 3000
    • This can be customized by changing the EXPOSE directive in the Dockerfile if your application listens on a different port.
  • Non-Root User:

    • Default: appuser
    • A non-root user is created and used by default for enhanced security. You can modify or remove this by adjusting the RUN and USER directives in the Dockerfile if your application needs specific user permissions.
  • Python Environment Variables:

    • The following environment variables are set by default to optimize Python behavior in Docker:
      • PYTHONDONTWRITEBYTECODE=1: Prevents Python from writing .pyc files.
      • PYTHONUNBUFFERED=1: Ensures output is sent directly to terminal without being buffered.
    • These can be adjusted or removed based on your specific application needs.
  • Application Entrypoint:

    • Default command to run the application:
      hypercorn --reload --log-level info --graceful-timeout 0 src.main:app
      
    • Customize this if you use a different server (e.g., uvicorn, gunicorn) or a different application structure.

Customizing docker-compose.yml

The docker-compose.yml file in this repository is designed to set up and manage multiple services, including the FastAPI API service, a PostgreSQL database, and a test service. Below are the default configurations that can be customized to suit your specific project requirements.

API Service (FastAPI)

  1. Build Context: The api service is built using the Dockerfile in the root directory.

    • Default: context: ., dockerfile: Dockerfile
    • You can modify the build context or Dockerfile location as needed.
  2. Command: The default command runs database migrations using alembic and starts the API with hypercorn.

    • Default:
      bash -c "alembic upgrade head && hypercorn src/main:app -b 0.0.0.0:3000 --reload --access-logfile - --graceful-timeout 0"
      
    • You can modify this command to suit your needs (e.g., changing the entrypoint or server).
  3. Develop Mode: The develop section allows live reloading of the source code (/src/) and rebuilding when changes are made to requirements/dev.txt.

    • Default:
      watch:
        - action: sync
          path: ./src/
          target: /app/src/
        - action: rebuild
          path: requirements/dev.txt
      
    • Customize the watch paths or actions based on your development workflow.
  4. Ports: The default exposed port is 3000.

    • Default: 3000:3000
    • You can change the exposed ports if your application needs a different one.
  5. Volumes: A bind mount is used to link the source code on your host machine to the /app directory in the container.

    • Default:
      volumes:
        - type: bind
          source: .
          target: /app/
      
    • Modify the source or target paths based on your project structure.
  6. Environment Variables: The database connection string is provided through environment variables.

    • Default: DB_URI=postgresql+psycopg2://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB}
    • You can change this environment variable to connect to different databases or use other database drivers.
  7. Resources: CPU and memory limits are set to ensure the service does not over-consume resources.

    • Default:
      limits:
        cpus: '1.0'
        memory: 512M
      
    • Adjust these limits as needed based on your server's capacity.

Test Service

  1. Build Context: Similar to the api service, it builds from the same Dockerfile.

    • Default: context: ., dockerfile: Dockerfile
    • Modify if the Dockerfile is located elsewhere.
  2. Command: The default command runs Alembic migrations and executes tests using pytest.

    • Default:
      bash -c "alembic upgrade head && pytest"
      
    • Customize this if your testing setup differs.
  3. Ports: The test service is exposed on port 4000 to avoid conflict with the API service.

    • Default: 4000:3000
    • You can adjust the port mappings.
  4. Volumes: A bind mount is used to link the source code on your host machine to the /app directory in the container, similar to the API service.

    • Default:
      volumes:
        - type: bind
          source: .
          target: /app/
      
    • Modify the source or target paths based on your project structure.
  5. Resources: CPU and memory limits are set to ensure the service does not over-consume resources.

    • Default:
      limits:
        cpus: '1.0'
        memory: 512M
      
    • Adjust these limits as needed.

Database Service (PostgreSQL)

  1. Image: The default image is postgres:12.1-alpine, which is a lightweight version of PostgreSQL.

    • Default: postgres:12.1-alpine
    • You can update the image version or switch to a different database if necessary.
  2. Environment Variables: The PostgreSQL service uses environment variables for configuring the database.

    • Default:
      environment:
        - POSTGRES_USER
        - POSTGRES_PASSWORD
        - POSTGRES_DB
      
    • These values are loaded from an .env file. Customize them by changing the .env file or setting them directly in the docker-compose.yml file.
  3. Volumes: The database data is persisted using a named volume (postgres_data_disk).

    • Default:
      volumes:
        - postgres_data_disk:/var/lib/postgresql/data/
      
    • You can modify the volume name or path if needed.
  4. Resources: CPU and memory limits are set for this service to ensure the database doesn’t consume excessive resources.

    • Default:
      limits:
        cpus: '0.5'
        memory: 256M
      
    • Customize this based on your database's performance needs.

Networks

  1. app_network: All services communicate over a custom bridge network (app_network).
    • Default:
      networks:
        app_network:
          driver: bridge
      
    • You can add other services to this network or change the network driver if needed.

Volumes

  1. postgres_data_disk: This volume is used to persist PostgreSQL data.
    • Default:
      volumes:
        postgres_data_disk:
          driver: local
      
    • You can modify the volume driver or name as needed.

Production deployment

  • For production, you can find under fast-api-kube-helm helm charts to deploy application on Kubernetes

Please read the Readme.md in this directory for detailed step-by-step instructions on deploying this project in a production environment.

CI/CD

CI/CD tasks

  • We use github action for CI/CD to:
    • Check Code Quality with flake8
    • Run tests with pytest
    • Build Docker image and push it to GitHub regitry
    • Build py package and publish it to pypi.org
    • Codacy Static Code Analysis
    • Lint and check helm charts
    • Validate docker file
    • Pages-build-deployment
    • Pycharm Python security scanner
    • Trivy docker image vulnerability scanning tools
    • Bandit Static Application Security Testing (SAST) security scanner

Repository Secrets

These secrets are used for automating the CI/CD pipeline and managing external integrations such as Docker Hub, PostgreSQL, and PyPI.

Setting Up Secrets in GitHub Actions

To configure the required secrets in your repository:

  1. Go to your repository on GitHub.
  2. Click on the Settings tab.
  3. In the left sidebar, navigate to Secrets and variables > Actions.
  4. Click New repository secret.
  5. Enter the Name and Value for each secret (as shown in the table below).
  6. Click Add secret.

Secrets Table

Secret Name Description Example
DOCKER_PASSWORD Docker Hub password my-docker-password
DOCKER_USERNAME Docker Hub username my-docker-username
POSTGRES_DB PostgreSQL database name my_database
POSTGRES_PASSWORD PostgreSQL password my-postgres-password
POSTGRES_USER PostgreSQL username my-postgres-user
PYPI_API_TOKEN API token for uploading packages to PyPI pypi-12345-abcde-token

CI/CD Artifacts

  • CI/CD workflow generate these artifacts:
    • flake8-coverage-report
    • pytest-coverage-report
    • bandit-findings-report

Python requirement

  • To add a new library to Python there is a requirement directory with a file for each stage of deployement

    • dev.txt
    • prod.txt
    • stagging.txt

Add an env var:

To add environment variable to docker and docker-compose update these files:

  • Docker-compose-file:28 => environment:
  • Get the env var form python code using:
 import os
 ENV_NAME =  os.getenv("ENV_NAME")

NB: Fixed version should mbe added

Middleware config:

Security Headers Middleware

This FastAPI application includes a custom middleware called SecurityHeadersMiddleware that automatically adds essential security headers to every HTTP response. These headers help enhance the security of your application by mitigating common vulnerabilities such as clickjacking, MIME sniffing, and cross-site scripting (XSS).

Security Headers Added

The middleware adds the following headers to all responses:

Header Description Example Value
Strict-Transport-Security Enforces the use of HTTPS and tells the browser to only interact with the site over HTTPS for a specified time period. Also applies the rule to all subdomains. max-age=31536000; includeSubDomains
X-Content-Type-Options Prevents browsers from MIME-sniffing the content-type of responses, reducing the risk of some types of attacks, such as XSS. nosniff
X-Frame-Options Protects against clickjacking by preventing the page from being embedded in an iframe. DENY
X-XSS-Protection Enables the browser’s built-in cross-site scripting (XSS) protection to prevent some forms of XSS attacks. 1; mode=block
Content-Security-Policy Defines which content sources are allowed to load. Helps prevent XSS by restricting allowed scripts and resources. default-src 'self'; script-src 'self'; object-src 'none'

Global rate limiting Middleware

This FastAPI application includes custom middleware to enforce global rate-limiting. The rate-limiting middleware is configured using environment variables (requests are limited across all clients).

Environment Variable Description Default Value
RATE_LIMIT_REQUESTS Maximum number of global requests allowed in the time window. If the total number of requests exceeds this limit, subsequent requests will receive a 429 Too Many Requests response. 100
RATE_LIMIT_WINDOW The time window (in seconds) during which the maximum number of requests is counted. Once the time window expires, the counter resets. 60

Control Access Middleware

This FastAPI application includes two essential middlewares for controlling access: TrustedHostMiddleware and CORSMiddleware. You can customize their configuration parameters in the middleware/security_access.py file, which defines the allowed origins, methods, headers, and hosts for accessing your FastAPI application.

Configuration Parameters

The following table outlines the configurable parameters for the CORSMiddleware and TrustedHostMiddleware used in this FastAPI application:

Parameter Middleware Description Default Value Recommended Value for Production
allow_origins CORSMiddleware Defines which domains are allowed to make requests to the API. ["*"] List of trusted domains, e.g., ["https://example.com"]
allow_methods CORSMiddleware Specifies the allowed HTTP methods (GET, POST, PUT, etc.). ["*"] Restrict to required methods, e.g., ["GET", "POST"]
allow_headers CORSMiddleware Controls which headers are allowed in the requests. ["*"] Specify required headers, e.g., ["Authorization", "Content-Type"]
allow_credentials CORSMiddleware Allows cookies or authentication credentials to be included in the requests. True True (if using cookies or credentials)
allowed_hosts TrustedHostMiddleware Limits the hosts that can access the API. ["*", "localhost"] List of trusted hosts, e.g., ["example.com"]

Notes:

  • allow_origins: Setting ["*"] (allow all origins) is insecure in production environments, as it permits requests from any domain. For production, restrict this to specific trusted domains like ["https://example.com"].
  • allow_methods: While ["*"] allows all HTTP methods, it is recommended to restrict this to only the required methods for your API, such as ["GET", "POST"].
  • allowed_hosts: Allowing all hosts with ["*"] is insecure for production environments. Restrict access to specific trusted hosts, such as ["example.com"] or ["api.example.com"].
  • allow_credentials: Set this to True if your API uses cookies or authentication tokens that require credentials to be sent across domains.
  • allow_headers: While ["*"] allows all headers, you should explicitly specify the headers that are required for your application, such as ["Authorization", "Content-Type"].

Make sure to update these parameters in middleware/security.py for a production setup to enhance security.

Manual Test API

curl http://0.0.0.0:3000/health
curl http://0.0.0.0:3000/
curl http://0.0.0.0:3000/metrics
curl -X POST "http://localhost:3000/v1/tools/validate" -H "Content-Type: application/json" -d "{\"ip\": \"192.168.1.1\"}"
curl "http://localhost:3000/v1/tools/lookup?domain=example.com"
curl "http://localhost:3000/v1/history"

Manuel install python dependencies

pip install  --no-cache-dir -r ./requirements/dev.txt

Manuel push to docker hub

docker build  --build-arg ENVIRONMENT=dev .
docker login -u username
docker tag fastapiapp:latest  username/fastapiapp:latest
docker push username/fastapiapp:latest

Manual Alembic Database migration

alembic init migrations
alembic revision --autogenerate -m "Create a baseline migrations"
alembic upgrade head
alembic revision -m "Fill empty "

Lint Docker file :

docker run --rm -i hadolint/hadolint < Dockerfile

Application Metrics

This repository exposes various application metrics that can be monitored using Prometheus. Below is a breakdown of the metrics and what each one represents.

Exposed Metrics

Metric Description Labels Type Example
metric_app_requests_total Total number of requests received by the /metrics endpoint. None Counter metric_app_requests_total 1.0
metric_app_requests_created Timestamp of the first request on the /metrics endpoint since Unix epoch. None Gauge metric_app_requests_created 1.7276320847868874e+09
metric_app_request_errors_total Total number of request errors encountered on the /metrics endpoint. None Counter metric_app_request_errors_total 0.0
metric_app_request_errors_created Timestamp of the first request error on the /metrics endpoint since Unix epoch. None Gauge metric_app_request_errors_created 1.7276320847869053e+09
metric_app_request_latency_seconds Request latency in seconds on the /metrics endpoint, split into histogram buckets. le: Latency bucket (e.g., 0.005s, 0.01s, etc.) Histogram metric_app_request_latency_seconds_bucket{le="0.005"} 0.0
metric_app_request_latency_seconds_bucket{le="0.01"} 0.0
metric_app_request_latency_seconds_created Timestamp of first latency measurement on the /metrics endpoint. None Gauge metric_app_request_latency_seconds_created 1.727632084786929e+09
validate_app_requests_total Total number of requests received on the /validate endpoint. None Counter validate_app_requests_total 0.0
validate_app_requests_created Timestamp of the first request on the /validate endpoint since Unix epoch. None Gauge validate_app_requests_created 1.727632084825792e+09
validate_request_duration_seconds Duration of requests on the /validate endpoint, split into histogram buckets. le: Latency bucket (e.g., 0.005s, 0.01s, etc.) Histogram validate_request_duration_seconds_bucket{le="0.005"} 0.0
validate_request_duration_seconds_bucket{le="0.01"} 0.0
validate_request_duration_seconds_created Timestamp of first duration measurement for /validate requests. None Gauge validate_request_duration_seconds_created 1.7276320848258443e+09
lookup_request_duration_seconds Duration of requests on the /lookup endpoint, split into histogram buckets. le: Latency bucket (e.g., 0.005s, 0.01s, etc.) Histogram lookup_request_duration_seconds_bucket{le="0.005"} 0.0
lookup_request_duration_seconds_bucket{le="0.01"} 0.0
lookup_request_duration_seconds_created Timestamp of first duration measurement for /lookup requests. None Gauge lookup_request_duration_seconds_created 1.727632084826711e+09
lookup_app_requests_total Total number of requests received on the /lookup endpoint. None Counter lookup_app_requests_total 0.0
lookup_app_requests_created Timestamp of the first request on the /lookup endpoint since Unix epoch. None Gauge lookup_app_requests_created 1.727632084826785e+09
history_app_requests_total Total number of requests received on the /history endpoint. None Counter history_app_requests_total 1.0
history_app_requests_created Timestamp of the first request on the /history endpoint since Unix epoch. None Gauge history_app_requests_created 1.727632084837052e+09
history_app_request_errors_total Total number of request errors encountered on the /history endpoint. None Counter history_app_request_errors_total 0.0
history_app_request_errors_created Timestamp of the first request error on the /history endpoint since Unix epoch. None Gauge history_app_request_errors_created 1.7276320848370783e+09
history_app_request_latency_seconds Request latency in seconds on the /history endpoint, split into histogram buckets. le: Latency bucket (e.g., 0.005s, 0.01s, etc.) Histogram history_app_request_latency_seconds_bucket{le="0.005"} 0.0
history_app_request_latency_seconds_bucket{le="0.01"} 1.0
root_app_requests_total Total number of requests received on the / (root) endpoint. None Counter root_app_requests_total 0.0
root_app_requests_created Timestamp of the first request on the / (root) endpoint since Unix epoch. None Gauge root_app_requests_created 1.727632084847543e+09
root_app_request_errors_total Total number of request errors encountered on the / (root) endpoint. None Counter root_app_request_errors_total 0.0
root_app_request_errors_cre ated Timestamp of the first request error on the / (root) endpoint since Unix epoch. None Gauge root_app_request_errors_created 1.727632084847571e+09

Pre-Commit Hooks Setup

This project uses pre-commit hooks to automatically ensure that code follows consistent style and quality standards. The hooks are triggered before every commit to check and format Python code using the following tools:

Tools Used

  1. Black - Python code formatter
  2. Flake8 - Python code linting
  3. Pylint - Advanced Python linting
  4. Hadolint - Dockerfile linting
  5. Detect-Secrets - Detecting and preventing secret leaks in code

How it Works

  • Every time you commit code, these tools run automatically, ensuring that the code is formatted and free of common issues before being committed.
  • If any problems are detected, the commit is rejected, and you are prompted to fix the issues.

License

This project is licensed under the MIT License.

TODO

  • Add Helm Secrets Plugin and manage secret encryption:

    • Install the Helm Secrets Plugin.
    • Use sops with GPG for encrypting secrets or integrate with a secret management solution like AWS Secrets Manager or HashiCorp Vault.
  • Add Ingress Rules for Production with TLS and WAF:

    • Configure ingress rules with TLS support using Cert-Manager for automatic certificate provisioning.
    • Integrate a WAF (e.g., AWS WAF, GCP Cloud Armor) or use NGINX Ingress with ModSecurity for enhanced security.
  • Add Authentication and Security to FastAPI:

    • Implement OAuth2 with JWT for secure user authentication using FastAPI's built-in support.
    • Add role-based access control (RBAC) for fine-grained permission handling.
  • Connect the Application to PostgreSQL in Production:

    • Ensure the FastAPI app is connected to a managed PostgreSQL instance in your production environment using environment variables for connection strings.
  • Integrate ArgoCD or Flux for Continuous Delivery (CD):

    • Set up ArgoCD or Flux to manage GitOps-based continuous delivery for your Kubernetes deployments.
  • Add Helm Hooks for Alembic Database Migrations in Production:

    • Use Helm post-deploy hooks to trigger Alembic migrations automatically after successful deployments.
  • Add Helm Tests Hook to Verify Database Connection:

    • Create Helm test hooks to validate the connection between the FastAPI app and the PostgreSQL database after deployment.
  • Add Helm Release to CI Pipeline:

    • Integrate Helm release steps in your CI pipeline to automatically deploy changes to your Kubernetes cluster.
  • Implement Authentication (OAuth2/JWT):

    • Set up OAuth2 with JWT tokens for secure access control within your FastAPI application.
  • Implement Role-Based Access Control (RBAC):

    • Define and enforce role-based permissions within the FastAPI application to ensure proper access control.
  • Test Horizontal Pod Autoscaling (HPA):

    • Configure and test Kubernetes HPA to automatically scale your application based on CPU or memory usage.
  • Test Multi-Stage Builds:

    • Optimize Docker builds with multi-stage builds to reduce image size and improve build efficiency.
  • Mock External Dependencies for Testing:

    • Use tools like pytest-mock or custom mock services to simulate external dependencies during unit and integration tests.
  • Set up CI to Regularly Update Dependencies:

    • Automate dependency updates in your CI pipeline using tools like Dependabot or Renovate to ensure packages stay up-to-date.
  • Add Sphinx Documentation:

    • Integrate Sphinx for generating project documentation and ensure it's part of your CI pipeline for regular updates.
  • Use External Vault for Secrets with Rotation:

    • Store sensitive information in an external vault (like HashiCorp Vault or AWS Secrets Manager) and implement automatic secret rotation.
  • Add Static Application Security Testing (SAST):

    • Integrate a SAST tool (like Bandit or SonarQube) into your CI pipeline to scan for security vulnerabilities in the codebase.
  • Add Dependency Vulnerability Scanning:

    • Use tools like safety or pip-audit in the CI pipeline to detect and address vulnerabilities in Python dependencies.
  • Add Load Testing:

    • Implement load testing using tools like Locust or k6 to simulate real- world traffic and ensure the system scales properly.
  • Add Rollback Functionality for Helm and Alembic Migration:

    • Implement rollback strategies for both Helm deployments and Alembic migrations to handle failed deployments gracefully.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

python_fast_api_kube-0.0.5.tar.gz (32.2 kB view details)

Uploaded Source

File details

Details for the file python_fast_api_kube-0.0.5.tar.gz.

File metadata

  • Download URL: python_fast_api_kube-0.0.5.tar.gz
  • Upload date:
  • Size: 32.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for python_fast_api_kube-0.0.5.tar.gz
Algorithm Hash digest
SHA256 3e16455f462dbab35052f3cdbfaaa771885dac6f8a1ca9b54c20cb78727024d4
MD5 deaddac1ac1b2e7772b10f5445b23859
BLAKE2b-256 ca8335c3ce933816b6db272684cd8fa9da8f73d9d04a8aa434831d8e98a82d60

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page