From 20fb39fd0549bafffe6643de19b881d6e93b4353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Thu, 9 Apr 2026 21:41:15 +0200 Subject: [PATCH] =?UTF-8?q?fix(security):=20harden=20production=20Docker?= =?UTF-8?q?=20=E2=80=94=20bind=20DB/Redis=20to=20localhost,=20add=20Redis?= =?UTF-8?q?=20auth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Postgres and Redis ports now bind to 127.0.0.1 only, preventing exposure to the network even if the host firewall has a gap - Redis requires a password (REDIS_PASSWORD) via --requirepass; REDIS_URL in app and migrator services updated to include the credential - Redis healthcheck updated to pass -a flag so it still works with auth enabled - REDIS_PASSWORD added to .env.example with generation hint Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 6 ++++++ docker-compose.prod.yml | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index cd56468..bdfffd8 100644 --- a/.env.example +++ b/.env.example @@ -29,6 +29,12 @@ DATABASE_URL=postgresql://capakraken:capakraken_dev@localhost:5433/capakraken # ─── Redis ─────────────────────────────────────────────────────────────────── +# REQUIRED in production — password for the Redis server. +# The Docker Compose prod stack passes this both to the redis-server process +# (--requirepass) and to the application via REDIS_URL. +# Generate one with: openssl rand -hex 32 +REDIS_PASSWORD= + # REQUIRED for SSE (real-time updates) and rate limiting. # When using Docker Compose this is handled automatically inside the container # (redis://redis:6379). Only needed when running `pnpm dev` directly on the host. diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7553086..6f7d8f5 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -5,7 +5,7 @@ services: image: postgres:16-alpine restart: unless-stopped ports: - - "${POSTGRES_PORT:-5432}:5432" + - "127.0.0.1:${POSTGRES_PORT:-5432}:5432" environment: POSTGRES_DB: capakraken POSTGRES_USER: capakraken @@ -31,12 +31,12 @@ services: image: redis:7-alpine restart: unless-stopped ports: - - "${REDIS_PORT:-6379}:6379" - command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru + - "127.0.0.1:${REDIS_PORT:-6379}:6379" + command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru --requirepass ${REDIS_PASSWORD} volumes: - capakraken_prod_redis:/data healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "--no-auth-warning", "ping"] interval: 10s timeout: 5s retries: 5 @@ -50,7 +50,7 @@ services: - .env.production environment: DATABASE_URL: postgresql://capakraken:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/capakraken - REDIS_URL: redis://redis:6379 + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 RATE_LIMIT_BACKEND: ${RATE_LIMIT_BACKEND:-redis} depends_on: postgres: @@ -68,7 +68,7 @@ services: - .env.production environment: DATABASE_URL: postgresql://capakraken:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/capakraken - REDIS_URL: redis://redis:6379 + REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 RATE_LIMIT_BACKEND: ${RATE_LIMIT_BACKEND:-redis} depends_on: postgres: