diff --git a/.env.sample b/.env.sample deleted file mode 100644 index f7a57fe..0000000 --- a/.env.sample +++ /dev/null @@ -1,6 +0,0 @@ -KEYCLOAK_SERVER_URL=https://sample.com -KEYCLOAK_CLIENT_ID=sample -KEYCLOAK_REALM_NAME=sample -KEYCLOAK_CLIENT_SECRET=sample -KEYCLOAK_ADMIN_CLIENT_SECRET=sample -KEYCLOAK_CALLBACK_URI=http://sample.com/callback diff --git a/.gitignore b/.gitignore index 99cd9f4..6d112de 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ var/ *.egg .venv/ venv/ -.env +.envs/ # Python debug pdb/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..336ced6 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Edgecutters + +Simple FastAPI template with Keycloak integration in mind. + +_A work in progress_ diff --git a/app/api/endpoints.py b/app/api/endpoints.py index 3715212..352ffa2 100644 --- a/app/api/endpoints.py +++ b/app/api/endpoints.py @@ -1,7 +1,7 @@ from fastapi import APIRouter, Depends from fastapi_keycloak import OIDCUser -from app.keycloak import idp +from app.config.keycloak import idp router = APIRouter() diff --git a/app/api/routers.py b/app/api/routers.py index 12c716b..3e91456 100644 --- a/app/api/routers.py +++ b/app/api/routers.py @@ -1,6 +1,6 @@ from fastapi import APIRouter -from app import api +from app.api.endpoints import router api_router_v1 = APIRouter() -api_router_v1.include_router(api.router) +api_router_v1.include_router(router) diff --git a/app/config/base.py b/app/config/base.py index 197477c..e597ba9 100644 --- a/app/config/base.py +++ b/app/config/base.py @@ -1,18 +1,8 @@ -from pydantic import BaseModel from pydantic_settings import BaseSettings, SettingsConfigDict -class KeycloakSettings(BaseModel): - server_url: str - client_id: str - client_secret: str - realm_name: str - admin_client_secret: str - callback_uri: str - - class Settings(BaseSettings): - model_config = SettingsConfigDict(env_file=".env", extra='ignore') + model_config = SettingsConfigDict(env_file=".envs/.local", extra="ignore") keycloak_server_url: str keycloak_client_id: str diff --git a/app/config/keycloak.py b/app/config/keycloak.py index 8967ccb..d5e8d9f 100644 --- a/app/config/keycloak.py +++ b/app/config/keycloak.py @@ -8,5 +8,5 @@ client_secret=settings.keycloak_client_secret, admin_client_secret=settings.keycloak_admin_client_secret, realm=settings.keycloak_realm_name, - callback_uri=settings.keycloak_callback_uri + callback_uri=settings.keycloak_callback_uri, ) diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..0f3b8f8 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,32 @@ +FROM python:3.12-slim + +ENV PYTHONDONTWRITEBYTECODE 1 +ENV DOCKER_BUILDKIT 1 +ENV PYTHONUNBUFFERED 1 + +RUN addgroup --system app && adduser --system --group app + +WORKDIR /app + +RUN rm -rf /var/lib/apt/lists/* && \ + apt-get purge --auto-remove && \ + apt-get clean + +COPY ./requirements.txt /requirements.txt + +RUN --mount=type=cache,target=/root/.cache \ + pip install -r /requirements.txt --no-cache-dir + +COPY ./docker/run.sh /run.sh +RUN chmod +x /run.sh + +COPY ./docker/prestart.sh /prestart.sh +RUN chmod +x /prestart.sh + +COPY --chown=app . /app + +ENV PYTHONPATH=/app + +USER app + +ENTRYPOINT ["/prestart.sh"] diff --git a/docker/prestart.sh b/docker/prestart.sh new file mode 100644 index 0000000..5f679b9 --- /dev/null +++ b/docker/prestart.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + +# Run migrations +#alembic upgrade head + +exec "$@" diff --git a/docker/run.sh b/docker/run.sh new file mode 100644 index 0000000..4c06e71 --- /dev/null +++ b/docker/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + +export APP_MODULE=${APP_MODULE-app.main:app} +export HOST=${HOST:-0.0.0.0} +export PORT=${PORT:-8000} + +uvicorn --host $HOST --port $PORT "$APP_MODULE" diff --git a/keycloak.yml b/keycloak.yml new file mode 100644 index 0000000..b9dfa0f --- /dev/null +++ b/keycloak.yml @@ -0,0 +1,33 @@ +volumes: + postgres_data: {} + +name: local-keycloak + +services: + postgres: + image: postgres:12-bullseye + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + POSTGRES_DB: keycloak + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: password + + keycloak: + image: quay.io/keycloak/keycloak:latest + ports: + - "8080:8080" + environment: + DB_VENDOR: POSTGRES + DB_ADDR: postgres + DB_DATABASE: keycloak + DB_USER: keycloak + DB_SCHEMA: public + DB_PASSWORD: password + KEYCLOAK_ADMIN: admin + KEYCLOAK_ADMIN_PASSWORD: admin + # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it. + #JDBC_PARAMS: "ssl=true" + depends_on: + - postgres + command: start-dev diff --git a/local.yml b/local.yml new file mode 100644 index 0000000..269b7ca --- /dev/null +++ b/local.yml @@ -0,0 +1,28 @@ +volumes: + local_postgres_data: {} + local_redis_data: {} + +services: + backend: + image: backend_api + build: + context: . + dockerfile: docker/Dockerfile + command: /run.sh + depends_on: + - postgres + ports: + - "8000:8000" + env_file: + - .envs/.local + extra_hosts: + - "host.docker.internal:host-gateway" + + postgres: + image: postgres:14 + volumes: + - local_postgres_data:/var/lib/postgresql/data + env_file: + - .envs/.local.postgres + ports: + - "5434:5432" diff --git a/requirements.txt b/requirements.txt index b856c96..110f81a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ filelock==3.13.1 h11==0.14.0 httptools==0.6.1 identify==2.5.33 -idna==3.6 +idna==3.7 itsdangerous==2.1.2 nodeenv==1.8.0 packaging==23.2