updates for routing and services

This commit is contained in:
Mike Kell 2025-07-10 15:48:57 +00:00
parent 46426c1567
commit f38c4c30f6
7 changed files with 271 additions and 47 deletions

15
.env
View File

@ -7,3 +7,18 @@ KEYCLOAK_URL=https://kc.kellsupport.com
# Custom project name (avoids long folder names in ~/.local/share/containers) # Custom project name (avoids long folder names in ~/.local/share/containers)
COMPOSE_PROJECT_NAME=cmmc-platform COMPOSE_PROJECT_NAME=cmmc-platform
# Keycloak OIDC config for Kong
KEYCLOAK_URL=https://kc.kellsupport.com
KEYCLOAK_REALM=cmmc
# KEYCLOAK_CLIENT_ID=kong-gateway
# KEYCLOAK_CLIENT_SECRET=3FefJAfN7Rox2x7EW7JzZ38vLI04cXMB
KEYCLOAK_CLIENT_ID=cmmc-oauth2-proxy
KEYCLOAK_CLIENT_SECRET=OOPXQpXhFeG57lC7G1AktnpPyodtDkib
OIDC_SESSION_SECRET=3b4b1b8c8366b1d7c50c49742f879bdd20b85d5b95adaaf4af38d89a36c372ab
OAUTH2_PROXY_CLIENT_ID=${KEYCLOAK_CLIENT_ID}
OAUTH2_PROXY_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET}
OAUTH2_PROXY_COOKIE_SECRET=P1eo4uZRzZM1QNrXIlzlep5dsmbnJr1K19CETok0BhU=
OAUTH2_PROXY_PROVIDER_URL=https://kc.kellsupport.com/realms/cmmc

13
Dockerfile.kong-oidc Normal file
View File

@ -0,0 +1,13 @@
FROM kong:0.14-centos
USER root
RUN yum install -y git unzip openssl-devel gcc && yum clean all
# Install kong-oidc version 1.0.1
RUN luarocks install kong-oidc 1.0.1
# Enable the plugin
ENV KONG_PLUGINS=bundled,oidc
USER kong

View File

@ -27,6 +27,8 @@ check-idp:
echo "🛠 No external Keycloak found."; echo 0 >.idp_flag ; \ echo "🛠 No external Keycloak found."; echo 0 >.idp_flag ; \
fi fi
# kong-template:
# envsubst < kong/kong.template.yml > kong/kong.yml
# ---------------------------------------------------------- # ----------------------------------------------------------
# Lifecycle targets # Lifecycle targets

View File

@ -1,4 +1,4 @@
version: "3.9" # version: "3.9"
x-common-env: &common-env x-common-env: &common-env
TZ: "UTC" TZ: "UTC"
@ -8,21 +8,84 @@ x-common-env: &common-env
############################################################ ############################################################
services: services:
# ────────────────────────────── # ──────────────────────────────
kong: # kong:
image: docker.io/library/kong:3.7 # image: kong/kong:3.6
container_name: kong # container_name: kong
restart: unless-stopped # restart: unless-stopped
# environment:
# KONG_DATABASE: "off"
# KONG_DECLARATIVE_CONFIG: /config/kong.yml
# KONG_LOG_LEVEL: info
# KONG_PLUGINS: bundled
# KONG_PROXY_ACCESS_LOG: /dev/stdout
# KONG_ADMIN_ACCESS_LOG: /dev/stdout
# KONG_PROXY_ERROR_LOG: /dev/stderr
# KONG_ADMIN_ERROR_LOG: /dev/stderr
# volumes:
# - ./kong:/config
# networks:
# - internal
# - nginx-proxy
# depends_on:
# - fastapi
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
container_name: oauth2-proxy
restart: always
networks:
- internal
- nginx-proxy
environment: environment:
<<: *common-env OAUTH2_PROXY_PROVIDER: oidc
KONG_DATABASE: "off" OAUTH2_PROXY_OIDC_ISSUER_URL: https://kc.kellsupport.com/realms/cmmc
KONG_DECLARATIVE_CONFIG: /config/kong.yml OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID}
KONG_LOG_LEVEL: info OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET}
volumes: OAUTH2_PROXY_REDIRECT_URL: https://api.kellsupport.com/oauth2/callback
- ./kong/kong.yml:/config/kong.yml:ro OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET}
ports:
- "8000:8000" # proxy (handy for localhost curl) # Forward all traffic to FastAPI (which handles /api/* etc)
- "8001:8001" # admin OAUTH2_PROXY_UPSTREAMS: http://fastapi:8000
networks: [internal, nginx-proxy]
# Secure cookies and session behavior
OAUTH2_PROXY_COOKIE_DOMAIN: api.kellsupport.com
OAUTH2_PROXY_COOKIE_NAME: _oauth2_proxy
OAUTH2_PROXY_COOKIE_SECURE: "true"
OAUTH2_PROXY_COOKIE_HTTPONLY: "false"
OAUTH2_PROXY_COOKIE_SAMESITE: Lax
OAUTH2_PROXY_COOKIE_EXPIRE: 168h
OAUTH2_PROXY_COOKIE_REFRESH: 60m
# Auth config
OAUTH2_PROXY_EMAIL_DOMAINS: "*"
OAUTH2_PROXY_SET_XAUTHREQUEST: "true"
OAUTH2_PROXY_SET_AUTHORIZATION_HEADER: "true"
OAUTH2_PROXY_PASS_ACCESS_TOKEN: "true"
OAUTH2_PROXY_PASS_USER_HEADERS: "true"
OAUTH2_PROXY_PREFER_EMAIL_TO_USER: "true"
OAUTH2_PROXY_COOKIE_CSRF_PER_REQUEST: "true"
OAUTH2_PROXY_CSRF_COOKIE_NAME: _oauth2_proxy_csrf
OAUTH2_PROXY_SHOW_DEBUG_ON_ERROR: "true"
# Optional: PKCE
OAUTH2_PROXY_CODE_CHALLENGE_METHOD: S256
# Health routes allowed anonymously
OAUTH2_PROXY_SKIP_AUTH_ROUTES: GET=^/gateway-health$,GET=^/healthz$,GET=^/favicon\.ico$
OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: "true"
# Networking
OAUTH2_PROXY_HTTP_ADDRESS: 0.0.0.0:4180
OAUTH2_PROXY_REVERSE_PROXY: "true"
expose:
- "4180"
# ────────────────────────────── # ──────────────────────────────
fastapi: fastapi:
@ -33,7 +96,7 @@ services:
<<: *common-env <<: *common-env
# Default to local container; overridden by external URL in Makefile/CI # Default to local container; overridden by external URL in Makefile/CI
KEYCLOAK_URL: "${KEYCLOAK_URL:-http://keycloak:8080}" KEYCLOAK_URL: "${KEYCLOAK_URL:-http://keycloak:8080}"
KEYCLOAK_REALM: "cmmc-platform-dev" KEYCLOAK_REALM: "cmmc"
KEYCLOAK_CLIENT_ID: "frontend" KEYCLOAK_CLIENT_ID: "frontend"
# ports: # ports:
# # keep reachable only from localhost, not LAN # # keep reachable only from localhost, not LAN

77
kong/kong.template.yml Normal file
View File

@ -0,0 +1,77 @@
_format_version: "3.0"
_transform: true
services:
- name: fastapi-svc
host: fastapi
port: 8000
protocol: http
routes:
- name: api-root
paths: ["/api/"]
strip_path: true
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
plugins:
- name: request-transformer
config:
add:
headers:
- "X-Forwarded-User: $http_x_auth_request_user"
- "X-Forwarded-Email: $http_x_auth_request_email"
remove:
headers:
- "Authorization"
- name: debug-api
url: http://fastapi:8000
# - name: openid
# config:
# issuer: "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}"
# client_id: "${KEYCLOAK_CLIENT_ID}"
# client_secret: "${KEYCLOAK_CLIENT_SECRET}"
# redirect_uri: "https://api.kellsupport.com/api/"
# scopes: ["openid", "profile", "email"]
# bearer_only: false
# response_type: "code"
# session_secret: "${OIDC_SESSION_SECRET}"
# ssl_verify: false
# timeout: 10000
- name: cors
config:
origins: ["*"]
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
headers: ["Accept", "Content-Type", "Authorization"]
credentials: true
max_age: 3600
- name: api-debug-auth
paths: ["/api/debug-auth"]
strip_path: true
methods: ["GET"]
- name: gateway-health
paths: ["/gateway-health"]
strip_path: true
methods: ["GET"]
- name: healthz
paths: ["/healthz"]
strip_path: true
methods: ["GET"]
- name: debug-auth
paths: ["/api/debug-auth"]
strip_path: true
service: ["debug-api"]
plugins:
- name: rate-limiting
config:
second: 25
policy: local

View File

@ -1,46 +1,74 @@
_format_version: "3.0" _format_version: "3.0"
_transform: true _transform: true
services: services:
- name: fastapi-svc - name: fastapi-svc
host: fastapi host: fastapi
port: 8000 port: 8000
protocol: http protocol: http
routes: routes:
- name: fastapi-api - name: api-root
paths: ["/api/"] paths: ["/api/"]
strip_path: true strip_path: true
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"] methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
plugins:
- name: cors
config:
origins: ["*"]
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
headers: ["Accept", "Content-Type", "Authorization"]
credentials: false
max_age: 3600
- name: fastapi-health
paths: ["/gateway-health", "/healthz"]
strip_path: true
methods: ["GET"]
- name: kong-meta
url: http://localhost:8001
routes:
- name: root-status
paths: ["/"]
strip_path: true
methods: ["GET"]
plugins: plugins:
- name: request-termination - name: request-transformer
config: config:
status_code: 200 add:
content_type: application/json headers:
body: '{"status":"Kong Gateway OK"}' - "X-Forwarded-User: "
- "X-Forwarded-Email: "
remove:
headers:
- "Authorization"
- name: debug-api
url: http://fastapi:8000
# - name: openid
# config:
# issuer: "https://kc.kellsupport.com/realms/cmmc"
# client_id: "kong-gateway"
# client_secret: "3FefJAfN7Rox2x7EW7JzZ38vLI04cXMB"
# redirect_uri: "https://api.kellsupport.com/api/"
# scopes: ["openid", "profile", "email"]
# bearer_only: false
# response_type: "code"
# session_secret: "3b4b1b8c8366b1d7c50c49742f879bdd20b85d5b95adaaf4af38d89a36c372ab"
# ssl_verify: false
# timeout: 10000
- name: cors
config:
origins: ["*"]
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
headers: ["Accept", "Content-Type", "Authorization"]
credentials: true
max_age: 3600
- name: api-debug-auth
paths: ["/api/debug-auth"]
strip_path: true
methods: ["GET"]
- name: gateway-health
paths: ["/gateway-health"]
strip_path: true
methods: ["GET"]
- name: healthz
paths: ["/healthz"]
strip_path: true
methods: ["GET"]
- name: debug-auth
paths: ["/api/debug-auth"]
strip_path: true
service: ["debug-api"]
plugins: plugins:
- name: rate-limiting - name: rate-limiting

View File

@ -1,4 +1,5 @@
from fastapi import FastAPI from fastapi import FastAPI, Request, Depends, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI(title="CMMC Platform API MVP", version="0.1.0") app = FastAPI(title="CMMC Platform API MVP", version="0.1.0")
@ -8,6 +9,31 @@ async def healthz() -> dict[str, str]:
return {"status": "pong"} return {"status": "pong"}
@app.get("/get-health", tags=["meta"])
async def get_health() -> dict[str, str]:
return {"status": "pong"}
@app.get("/", tags=["meta"]) @app.get("/", tags=["meta"])
async def root() -> dict[str, str]: async def root() -> dict[str, str]:
return {"message": "CMMC Platform it works!"} return {"message": "CMMC Platform it works!"}
def get_current_user(request: Request) -> dict:
user = request.headers.get("X-Auth-Request-User")
email = request.headers.get("X-Auth-Request-Email")
preferred_username = request.headers.get("X-Auth-Request-Preferred-Username")
if not user:
raise HTTPException(status_code=401, detail="Unauthorized")
return {
"user": user,
"email": email,
"id": preferred_username
}
@app.get("/api/debug-auth", tags=["auth"])
def debug_auth(user=Depends(get_current_user)):
return JSONResponse(user)