fix(06): CR-01 CR-02 WR-02 WR-05 WR-06 WR-08 docker-compose security hardening

- CR-01: add CLOUD_CREDS_KEY to backend service environment
- CR-02: disable Grafana anonymous access, add admin credentials, bind Grafana and Loki to loopback (127.0.0.1)
- WR-02: replace --reload with --workers 2 for production backend
- WR-05: add read_only/tmpfs/cap_drop/no-new-privileges to celery-beat; redirect schedule file to /tmp
- WR-06: change LOG_JSON from hardcoded true to ${LOG_JSON:-true} for env-var override
- WR-08: add SECRET_KEY to celery-worker environment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-06-04 23:15:48 +02:00
co-authored by Claude Sonnet 4.6
parent ee4df4537d
commit a8dbb02ff0
+17 -8
View File
@@ -68,12 +68,13 @@ services:
- FRONTEND_URL=${FRONTEND_URL:-http://localhost:5173} - FRONTEND_URL=${FRONTEND_URL:-http://localhost:5173}
- PYTHONDONTWRITEBYTECODE=1 - PYTHONDONTWRITEBYTECODE=1
- LOG_LEVEL=${LOG_LEVEL:-INFO} - LOG_LEVEL=${LOG_LEVEL:-INFO}
- LOG_JSON=${LOG_JSON:-false} - LOG_JSON=${LOG_JSON:-true}
- CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY}
labels: labels:
logging: "promtail" logging: "promtail"
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload command: uvicorn main:app --host 0.0.0.0 --port 8000 --workers 2
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
@@ -99,6 +100,7 @@ services:
- MINIO_BUCKET=${MINIO_BUCKET} - MINIO_BUCKET=${MINIO_BUCKET}
- REDIS_URL=${REDIS_URL} - REDIS_URL=${REDIS_URL}
- CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY} - CLOUD_CREDS_KEY=${CLOUD_CREDS_KEY}
- SECRET_KEY=${SECRET_KEY}
- PYTHONDONTWRITEBYTECODE=1 - PYTHONDONTWRITEBYTECODE=1
labels: labels:
logging: "promtail" logging: "promtail"
@@ -122,7 +124,6 @@ services:
security_opt: security_opt:
- "no-new-privileges:true" - "no-new-privileges:true"
# celery-beat: NOT hardened — writes celerybeat-schedule to working directory (Phase 6 Pitfall 7).
celery-beat: celery-beat:
build: ./backend build: ./backend
environment: environment:
@@ -135,7 +136,7 @@ services:
- PYTHONDONTWRITEBYTECODE=1 - PYTHONDONTWRITEBYTECODE=1
extra_hosts: extra_hosts:
- "host.docker.internal:host-gateway" - "host.docker.internal:host-gateway"
command: celery -A celery_app beat --loglevel=info command: celery -A celery_app beat --loglevel=info --schedule /tmp/celerybeat-schedule
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
@@ -143,11 +144,18 @@ services:
condition: service_healthy condition: service_healthy
redis: redis:
condition: service_healthy condition: service_healthy
read_only: true
tmpfs:
- "/tmp:mode=1777"
cap_drop:
- ALL
security_opt:
- "no-new-privileges:true"
loki: loki:
image: grafana/loki:latest image: grafana/loki:latest
ports: ports:
- "3100:3100" - "127.0.0.1:3100:3100"
volumes: volumes:
- ./docker/loki/loki-config.yaml:/etc/loki/local-config.yaml - ./docker/loki/loki-config.yaml:/etc/loki/local-config.yaml
- loki_data:/loki - loki_data:/loki
@@ -166,10 +174,11 @@ services:
grafana: grafana:
image: grafana/grafana:latest image: grafana/grafana:latest
ports: ports:
- "3000:3000" - "127.0.0.1:3000:3000"
environment: environment:
- GF_AUTH_ANONYMOUS_ENABLED=true - GF_AUTH_ANONYMOUS_ENABLED=false
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-changeme}
volumes: volumes:
- grafana_data:/var/lib/grafana - grafana_data:/var/lib/grafana
depends_on: depends_on: