core Struktur umbau

This commit is contained in:
2025-11-19 23:37:30 +01:00
parent c02a5f7081
commit 42dcdbba32
51 changed files with 158 additions and 1674 deletions
+1 -1
View File
@@ -171,7 +171,7 @@ backup.sh
# =================================================================== # ===================================================================
# Security and certificates (never include in builds) # Security and certificates (never include in builds)
# =================================================================== # ===================================================================
config/ssl/ _backup_chaos/config/ssl/
**/*.key **/*.key
**/*.pem **/*.pem
**/*.p12 **/*.p12
+1 -1
View File
@@ -27,7 +27,7 @@ logs/
build/diagrams/ build/diagrams/
# Local runtime secrets/overrides # Local runtime secrets/overrides
config/env/.env.local _backup_chaos/config/env/.env.local
# Python virtual environment # Python virtual environment
.venv/ .venv/
+12
View File
@@ -0,0 +1,12 @@
# Zentrale Einstiegsdatei für Docker Compose
name: meldestelle-system
include:
- path: docker-compose.yml # Infra (Postgres, Redis, Keycloak...)
- path: docker-compose.services.yml # Gateway & Microservices
- path: docker-compose.clients.yml # Web App
# Hier definieren wir das Netzwerk zentral, damit alle includes es nutzen können
networks:
meldestelle-network:
driver: bridge
View File
@@ -10,9 +10,10 @@ services:
# Web Application (Compose for Web) # Web Application (Compose for Web)
# =================================================================== # ===================================================================
web-app: web-app:
profiles: ["ui", "frontend"]
build: build:
context: . context: ..
dockerfile: dockerfiles/clients/web-app/Dockerfile dockerfile: ../dockerfiles/clients/web-app/Dockerfile
args: args:
# Global build arguments (centralized DOCKER_* variables) # Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
@@ -6,10 +6,11 @@
# =================================================================== # ===================================================================
services: services:
profiles: ["app", "backend"]
ping-service: ping-service:
build: build:
context: . context: ..
dockerfile: dockerfiles/services/ping-service/Dockerfile dockerfile: ../dockerfiles/services/ping-service/Dockerfile
args: args:
# Global build arguments (centralized DOCKER_* variables) # Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
@@ -39,9 +40,10 @@ services:
restart: unless-stopped restart: unless-stopped
api-gateway: api-gateway:
profiles: ["infra", "gateway"]
build: build:
context: . context: ..
dockerfile: dockerfiles/infrastructure/gateway/Dockerfile dockerfile: ../dockerfiles/infrastructure/gateway/Dockerfile
args: args:
# Global build arguments (centralized DOCKER_* variables) # Global build arguments (centralized DOCKER_* variables)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
@@ -10,6 +10,7 @@ services:
# Database # Database
# =================================================================== # ===================================================================
postgres: postgres:
profiles: ["core", "backend"]
image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine} image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine}
container_name: meldestelle-postgres container_name: meldestelle-postgres
environment: environment:
@@ -35,6 +36,7 @@ services:
# Cache # Cache
# =================================================================== # ===================================================================
redis: redis:
profiles: ["core", "backend"]
image: redis:${DOCKER_REDIS_VERSION:-7-alpine} image: redis:${DOCKER_REDIS_VERSION:-7-alpine}
container_name: meldestelle-redis container_name: meldestelle-redis
ports: ports:
@@ -56,6 +58,7 @@ services:
# Authentication # Authentication
# =================================================================== # ===================================================================
keycloak: keycloak:
profiles: ["auth", "security"]
image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2} image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2}
container_name: meldestelle-keycloak container_name: meldestelle-keycloak
environment: environment:
@@ -87,6 +90,7 @@ services:
# Monitoring # Monitoring
# =================================================================== # ===================================================================
prometheus: prometheus:
profiles: ["monitoring"]
image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1} image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1}
container_name: meldestelle-prometheus container_name: meldestelle-prometheus
ports: ports:
@@ -112,6 +116,7 @@ services:
restart: unless-stopped restart: unless-stopped
grafana: grafana:
profiles: ["monitoring"]
image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0} image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0}
container_name: meldestelle-grafana container_name: meldestelle-grafana
environment: environment:
+99
View File
@@ -0,0 +1,99 @@
name: meldestelle-hardcoded
services:
# --- DATENBANK ---
postgres:
image: postgres:16-alpine
container_name: meldestelle-postgres
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: pg-user
POSTGRES_PASSWORD: pg-password
POSTGRES_DB: meldestelle
volumes:
- postgres-data:/var/lib/postgresql/data
# Falls du Init-Scripte hast, lassen wir die erstmal weg,
# um Fehlerquellen zu reduzieren, oder lassen den Pfad, falls er existiert:
- ./docker/core/postgres:/docker-entrypoint-initdb.d
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U pg-user -d meldestelle" ]
interval: 1s
timeout: 5s
retries: 3
networks:
- meldestelle-network
# --- DATENBANK-MANAGEMENT-TOOL ---
pgadmin:
image: dpage/pgadmin4:8
container_name: pgadmin4_container
restart: unless-stopped
ports:
- "8888:80"
environment:
PGADMIN_DEFAULT_EMAIL: user@domain.com
PGADMIN_DEFAULT_PASSWORD: strong-password
volumes:
- pgadmin-data:/var/lib/pgadmin
networks:
- meldestelle-network
# --- CACHE ---
redis:
image: redis:7-alpine
container_name: meldestelle-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: [ "CMD", "redis-cli" ]
interval: 1s
timeout: 5s
retries: 3
networks:
- meldestelle-network
# --- IDENTITY PROVIDER (Wartet auf Postgres) ---
keycloak:
image: quay.io/keycloak/keycloak:26.4
container_name: meldestelle-keycloak
restart: unless-stopped
environment:
KC_HEALTH_ENABLED: true
KC_METRICS_ENABLED: true
KC_BOOTSTRAP_ADMIN_USERNAME: kc-admin
KC_BOOTSTRAP_ADMIN_PASSWORD: kc-password
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/meldestelle
KC_DB_USERNAME: pg-user
KC_DB_PASSWORD: pg-password
KC_HOSTNAME: localhost
ports:
- "8180:8080"
depends_on:
postgres:
condition: service_healthy
volumes:
- ./docker/core/keycloak:/opt/keycloak/data/import
command: start-dev --import-realm
healthcheck:
test: [ "CMD-SHELL", "kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin --password admin" ] #"kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin --password admin || exit 1"
interval: 20s
timeout: 10s
retries: 3
networks:
- meldestelle-network
volumes:
postgres-data:
pgadmin-data:
redis-data:
networks:
meldestelle-network:
driver: bridge
-367
View File
@@ -1,367 +0,0 @@
# ===================================================================
# Docker Compose - Client Applications (OPTIMIZED & SECURED)
# Meldestelle Project - Frontend Components
# ===================================================================
# Security & Performance Improvements:
# - Resource limits and reservations for all clients
# - Security hardening (non-root users, no-new-privileges)
# - Optimized build configurations and caching
# - Enhanced health checks and monitoring
# - Production-ready configurations
# ===================================================================
# Usage Scenarios:
#
# 1. STANDALONE CLIENT DEPLOYMENT:
# docker-compose -f docker-compose.clients.yml.optimized up -d
# - Clients run independently without api-gateway dependency
# - Set GATEWAY_HOST environment variable to external API Gateway
#
# 2. MULTI-FILE WITH INFRASTRUCTURE:
# docker-compose -f docker-compose.yml.optimized -f docker-compose.clients.yml.optimized up -d
# - Infrastructure services start first, then clients connect
#
# 3. COMPLETE SYSTEM:
# docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized -f docker-compose.clients.yml.optimized up -d
# - Full stack deployment with all components
# ===================================================================
version: '3.9'
services:
# ===================================================================
# Web Application - Kotlin/JS + Nginx with Security Hardening
# ===================================================================
web-app:
build:
context: .
dockerfile: dockerfiles/clients/web-app/Dockerfile
args:
# Global build arguments (build-time only)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# Client-specific image tag (build-time only)
NGINX_IMAGE_TAG: ${DOCKER_NGINX_VERSION:-1.28.0-alpine}
# Application-specific arguments
CLIENT_PATH: client
CLIENT_MODULE: client
CLIENT_NAME: meldestelle-web-app
container_name: meldestelle-web-app
env_file:
- config/env/.env
# Optional client-specific overrides (only if file exists)
- config/env/clients/web-app.env
environment:
NODE_ENV: ${NODE_ENV:-production}
APP_TITLE: ${APP_NAME:-Meldestelle}
APP_VERSION: ${VERSION:-1.0.0}
# API Gateway Configuration
API_BASE_URL: http://${GATEWAY_HOST:-api-gateway}:${GATEWAY_PORT:-8081}
# Nginx Worker Processes (for Performance)
NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
NGINX_WORKER_CONNECTIONS: ${NGINX_WORKER_CONNECTIONS:-1024}
# Security Headers
NGINX_SECURITY_HEADERS: "true"
ports:
- "${WEB_APP_PORT:-4000}:4000"
networks:
- meldestelle-network
volumes:
# Nginx cache directory
- web-app-cache:/var/cache/nginx
# Temp directory with proper permissions
- web-app-tmp:/tmp/nginx
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
healthcheck:
test: ["CMD", "curl", "--fail", "--max-time", "5", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# Run as nginx user (built into nginx image)
user: "101:101" # nginx:nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.web-app.rule=Host(`${WEB_APP_DOMAIN:-localhost}`) && PathPrefix(`/`)"
- "traefik.http.services.web-app.loadbalancer.server.port=4000"
- "traefik.http.routers.web-app.tls=true"
# ===================================================================
# Desktop Application - Kotlin Desktop + VNC with Security
# ===================================================================
desktop-app:
build:
context: .
dockerfile: dockerfiles/clients/desktop-app/Dockerfile
args:
- BUILD_DATE=${BUILD_DATE:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}
- VERSION=${VERSION:-1.0.0}
container_name: meldestelle-desktop-app
env_file:
- config/env/.env
environment:
# API Configuration - fallback to external gateway if not in same compose network
API_BASE_URL: http://${GATEWAY_HOST:-api-gateway}:${GATEWAY_PORT:-8081}
# VNC Configuration with Security
DISPLAY: ":99"
VNC_PORT: "5901"
NOVNC_PORT: "6080"
VNC_PASSWORD_FILE: /run/secrets/vnc_password
# App Information
APP_TITLE: ${APP_NAME:-Meldestelle}
APP_VERSION: ${APP_VERSION:-1.0.0}
# JVM Settings for Desktop App
JAVA_OPTS: "-Xmx1g -Xms256m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
ports:
- "${DESKTOP_VNC_WEB_PORT:-6080}:6080" # Web-based VNC (noVNC)
- "${DESKTOP_VNC_PORT:-5901}:5901" # VNC direct access
volumes:
# Desktop app data directory
- desktop-app-data:/app/data
# X11 socket for display
- /tmp/.X11-unix:/tmp/.X11-unix:rw
networks:
- meldestelle-network
secrets:
- vnc_password
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "/opt/health-check.sh"]
interval: 30s
timeout: 10s
retries: 3
start_period: 90s
restart: unless-stopped
security_opt:
- no-new-privileges:true
labels:
- "traefik.enable=true"
- "traefik.http.routers.desktop-app.rule=Host(`${DESKTOP_APP_DOMAIN:-localhost}`) && PathPrefix(`/desktop`)"
- "traefik.http.services.desktop-app.loadbalancer.server.port=6080"
- "traefik.http.routers.desktop-app.tls=true"
profiles:
- desktop
# ===================================================================
# Auth Server - Custom Authentication Service (Enhanced Security)
# ===================================================================
auth-server:
build:
context: .
dockerfile: dockerfiles/infrastructure/auth-server/Dockerfile
args:
# Global build arguments
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# Infrastructure-specific arguments
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT:-default}
container_name: meldestelle-auth-server
volumes:
- auth-server-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${AUTH_SERVICE_PORT:-8087}
# Keycloak Integration
KEYCLOAK_SERVER_URL: http://keycloak:8080
KEYCLOAK_REALM: meldestelle
KEYCLOAK_CLIENT_ID: meldestelle-auth-service
KEYCLOAK_CLIENT_SECRET_FILE: /run/secrets/keycloak_auth_client_secret
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# JWT Configuration via secrets
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${AUTH_SERVICE_PORT:-8087}:8087"
depends_on:
postgres:
condition: service_healthy
keycloak:
condition: service_started
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
- jwt_secret
- keycloak_auth_client_secret
deploy:
resources:
limits:
cpus: '1.5'
memory: 1.5G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "--fail", "--max-time", "10", "http://localhost:8087/actuator/health/readiness"]
interval: 30s
timeout: 15s
retries: 3
start_period: 90s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- auth
# ===================================================================
# Monitoring Server - Custom Grafana Extensions (Enhanced Security)
# ===================================================================
monitoring-server:
build:
context: .
dockerfile: dockerfiles/infrastructure/monitoring-server/Dockerfile
args:
# Global build arguments
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# Infrastructure-specific arguments
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT:-default}
container_name: meldestelle-monitoring-server
volumes:
- monitoring-server-gradle-cache:/home/gradle/.gradle
- monitoring-data:/app/data
- ./docker/monitoring:/app/config:ro
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: 8088
# Monitoring Services URLs
GRAFANA_URL: http://grafana:3000
PROMETHEUS_URL: http://prometheus:9090
# Authentication via secrets
GRAFANA_ADMIN_USER_FILE: /run/secrets/grafana_admin_user
GRAFANA_ADMIN_PASSWORD_FILE: /run/secrets/grafana_admin_password
METRICS_AUTH_USERNAME_FILE: /run/secrets/metrics_auth_username
METRICS_AUTH_PASSWORD_FILE: /run/secrets/metrics_auth_password
ports:
- "${MONITORING_SERVER_PORT:-8088}:8088"
depends_on:
grafana:
condition: service_healthy
prometheus:
condition: service_healthy
networks:
- meldestelle-network
secrets:
- grafana_admin_user
- grafana_admin_password
- metrics_auth_username
- metrics_auth_password
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
healthcheck:
test: ["CMD", "curl", "--fail", "--max-time", "10", "http://localhost:8088/actuator/health/readiness"]
interval: 30s
timeout: 15s
retries: 3
start_period: 90s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- monitoring
# ===================================================================
# Secrets - Client-specific and Shared
# ===================================================================
secrets:
# Shared secrets (external references to main infrastructure secrets)
postgres_user:
external: true
name: meldestelle_postgres_user
postgres_password:
external: true
name: meldestelle_postgres_password
grafana_admin_user:
external: true
name: meldestelle_grafana_admin_user
grafana_admin_password:
external: true
name: meldestelle_grafana_admin_password
# Client-specific secrets
jwt_secret:
external: true
name: meldestelle_jwt_secret
vnc_password:
file: ./docker/secrets/vnc_password.txt
keycloak_auth_client_secret:
file: ./docker/secrets/keycloak_auth_client_secret.txt
metrics_auth_username:
file: ./docker/secrets/metrics_auth_username.txt
metrics_auth_password:
file: ./docker/secrets/metrics_auth_password.txt
# ===================================================================
# Volumes - Client-specific Data and Caches
# ===================================================================
volumes:
# Web App volumes
web-app-cache:
driver: local
web-app-tmp:
driver: local
# Desktop App volumes
desktop-app-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/desktop-app
# Build cache volumes
auth-server-gradle-cache:
driver: local
monitoring-server-gradle-cache:
driver: local
# Monitoring data (shared with main infrastructure)
monitoring-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/monitoring
# ===================================================================
# Networks - Use external network from main infrastructure
# ===================================================================
networks:
meldestelle-network:
external: true
name: meldestelle_meldestelle-network
-446
View File
@@ -1,446 +0,0 @@
# ===================================================================
# Docker Compose - Microservices (OPTIMIZED & SECURED)
# Meldestelle Project - Application Services
# ===================================================================
# Security & Performance Improvements:
# - Secrets management for database credentials
# - Resource limits and reservations for all services
# - Security hardening (non-root users, no-new-privileges)
# - Optimized health checks and startup dependencies
# - Enhanced monitoring and logging configuration
# ===================================================================
# Usage:
# Vollständiges System: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized up -d
# ===================================================================
version: '3.9'
services:
# ===================================================================
# Ping Service - Enhanced Security & Performance
# ===================================================================
ping-service:
build:
context: .
dockerfile: dockerfiles/services/ping-service/Dockerfile
args:
# Global build arguments (build-time only)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-ping-service
env_file:
- config/env/.env
# Optional service-specific overrides (only if file exists)
- config/env/services/ping-service.env
volumes:
# Mount Gradle cache for better build performance
- ping-service-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${PING_SERVICE_PORT:-8082}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: ${CONSUL_ENABLED:-true}
SPRING_CLOUD_CONSUL_DISCOVERY_ENABLED: ${CONSUL_ENABLED:-true}
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis Event Store connection with authentication
REDIS_EVENT_STORE_HOST: redis
REDIS_EVENT_STORE_PORT: 6379
REDIS_EVENT_STORE_PASSWORD_FILE: /run/secrets/redis_password
# JWT Configuration for service-to-service authentication
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${PING_SERVICE_PORT:-8082}:8082"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- meldestelle-network
# Secrets sind für lokale Entwicklung optional; für Prod Profil aktivieren
profiles: ["prod"]
secrets:
- postgres_user
- postgres_password
- redis_password
- jwt_secret
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8082/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Members Service - Production Ready (Currently Commented Out)
# ===================================================================
members-service:
build:
context: .
dockerfile: dockerfiles/services/members-service/Dockerfile
args:
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-members-service
env_file:
- config/env/.env
# Optional service-specific overrides
- config/env/services/members-service.env
volumes:
- members-service-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${MEMBERS_SERVICE_PORT:-8083}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: ${CONSUL_ENABLED:-true}
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis Event Store connection
REDIS_EVENT_STORE_HOST: redis
REDIS_EVENT_STORE_PORT: 6379
REDIS_EVENT_STORE_PASSWORD_FILE: /run/secrets/redis_password
# Kafka messaging
KAFKA_BOOTSTRAP_SERVERS: kafka:29092
# JWT Configuration
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${MEMBERS_SERVICE_PORT:-8083}:8083"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
- redis_password
- jwt_secret
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8083/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- members
# ===================================================================
# Horses Service - Production Ready (Currently Commented Out)
# ===================================================================
horses-service:
build:
context: .
dockerfile: dockerfiles/services/horses-service/Dockerfile
args:
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-horses-service
env_file:
- config/env/.env
# Optional service-specific overrides
- config/env/services/horses-service.env
volumes:
- horses-service-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${HORSES_SERVICE_PORT:-8084}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: ${CONSUL_ENABLED:-true}
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis Event Store connection
REDIS_EVENT_STORE_HOST: redis
REDIS_EVENT_STORE_PORT: 6379
REDIS_EVENT_STORE_PASSWORD_FILE: /run/secrets/redis_password
# Kafka messaging
KAFKA_BOOTSTRAP_SERVERS: kafka:29092
# JWT Configuration
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${HORSES_SERVICE_PORT:-8084}:8084"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
- redis_password
- jwt_secret
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8084/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- horses
# ===================================================================
# Events Service - Production Ready (Currently Commented Out)
# ===================================================================
events-service:
build:
context: .
dockerfile: dockerfiles/services/events-service/Dockerfile
args:
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-events-service
env_file:
- config/env/.env
# Optional service-specific overrides
- config/env/services/events-service.env
volumes:
- events-service-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${EVENTS_SERVICE_PORT:-8085}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: ${CONSUL_ENABLED:-true}
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis Event Store connection
REDIS_EVENT_STORE_HOST: redis
REDIS_EVENT_STORE_PORT: 6379
REDIS_EVENT_STORE_PASSWORD_FILE: /run/secrets/redis_password
# Kafka messaging
KAFKA_BOOTSTRAP_SERVERS: kafka:29092
# JWT Configuration
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${EVENTS_SERVICE_PORT:-8085}:8085"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_healthy
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
- redis_password
- jwt_secret
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8085/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- events
# ===================================================================
# Masterdata Service - Production Ready (Currently Commented Out)
# ===================================================================
masterdata-service:
build:
context: .
dockerfile: dockerfiles/services/masterdata-service/Dockerfile
args:
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-masterdata-service
env_file:
- config/env/.env
# Optional service-specific overrides
- config/env/services/masterdata-service.env
volumes:
- masterdata-service-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-docker}
SERVER_PORT: ${MASTERDATA_SERVICE_PORT:-8086}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: ${CONSUL_ENABLED:-true}
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis Event Store connection
REDIS_EVENT_STORE_HOST: redis
REDIS_EVENT_STORE_PORT: 6379
REDIS_EVENT_STORE_PASSWORD_FILE: /run/secrets/redis_password
# JWT Configuration
JWT_SECRET_FILE: /run/secrets/jwt_secret
JWT_ISSUER: ${JWT_ISSUER:-meldestelle-auth-server}
JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-services}
ports:
- "${MASTERDATA_SERVICE_PORT:-8086}:8086"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
- redis_password
- jwt_secret
deploy:
resources:
limits:
cpus: '1.5'
memory: 1.5G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8086/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
profiles:
- masterdata
# ===================================================================
# Secrets - Shared with main infrastructure
# ===================================================================
secrets:
postgres_user:
external: true
name: meldestelle_postgres_user
postgres_password:
external: true
name: meldestelle_postgres_password
redis_password:
external: true
name: meldestelle_redis_password
jwt_secret:
file: ./docker/secrets/jwt_secret.txt
# ===================================================================
# Volumes - Service-specific Gradle Caches
# ===================================================================
volumes:
ping-service-gradle-cache:
driver: local
members-service-gradle-cache:
driver: local
horses-service-gradle-cache:
driver: local
events-service-gradle-cache:
driver: local
masterdata-service-gradle-cache:
driver: local
# ===================================================================
# Networks - Use external network from main compose
# ===================================================================
networks:
meldestelle-network:
external: true
name: meldestelle_meldestelle-network
-526
View File
@@ -1,526 +0,0 @@
# ===================================================================
# Docker Compose - Basis-Infrastruktur (OPTIMIZED & SECURED)
# Meldestelle Project - Essentielle Services
# ===================================================================
# Security & Performance Improvements:
# - Secrets management for sensitive data
# - Resource limits and reservations
# - Security hardening (read-only volumes, non-root users)
# - Optimized health checks and startup
# - Production-ready configurations
# ===================================================================
version: '3.9'
services:
# ===================================================================
# Datenbank - PostgresQL with Security Hardening
# ===================================================================
postgres:
image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine}
container_name: meldestelle-postgres
environment:
POSTGRES_USER_FILE: /run/secrets/postgres_user
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
POSTGRES_DB: ${POSTGRES_DB:-meldestelle}
# Security hardening
POSTGRES_INITDB_ARGS: "--auth-local=trust --auth-host=scram-sha-256"
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
- ./docker/services/postgres:/docker-entrypoint-initdb.d:ro
networks:
- meldestelle-network
secrets:
- postgres_user
- postgres_password
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $(cat /run/secrets/postgres_user) -d ${POSTGRES_DB:-meldestelle}"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
restart: unless-stopped
# Security: Run as postgres user (built into image)
security_opt:
- no-new-privileges:true
# ===================================================================
# Cache - Redis with Authentication
# ===================================================================
redis:
image: redis:${DOCKER_REDIS_VERSION:-7-alpine}
container_name: meldestelle-redis
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis-data:/data
command: >
redis-server
--appendonly yes
--requirepass "$(cat /run/secrets/redis_password)"
--maxmemory 1gb
--maxmemory-policy allkeys-lru
networks:
- meldestelle-network
secrets:
- redis_password
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
healthcheck:
test: ["CMD", "redis-cli", "--no-auth-warning", "-a", "$(cat /run/secrets/redis_password)", "ping"]
interval: 10s
timeout: 5s
retries: 3
start_period: 20s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Authentifizierung - Keycloak with Enhanced Security
# ===================================================================
keycloak:
image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2}
container_name: meldestelle-keycloak
environment:
# Admin Configuration - Using secrets
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD_FILE: /run/secrets/keycloak_admin_password
# Database Configuration - Using secrets
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/meldestelle
KC_DB_USERNAME_FILE: /run/secrets/postgres_user
KC_DB_PASSWORD_FILE: /run/secrets/postgres_password
KC_DB_SCHEMA: keycloak
# HTTP Configuration - Production settings
KC_HTTP_ENABLED: true
KC_HOSTNAME_STRICT: false
KC_PROXY: edge
# Security Configuration
KC_FEATURES: token-exchange,admin-fine-grained-authz
KC_LOG_LEVEL: ${KEYCLOAK_LOG_LEVEL:-INFO}
ports:
- "${KEYCLOAK_PORT:-8180}:8080"
depends_on:
postgres:
condition: service_healthy
volumes:
- ./docker/services/keycloak:/opt/keycloak/data/import:ro
- keycloak-data:/opt/keycloak/data
command:
# Development mode with realm import enabled
- start-dev
- --import-realm
networks:
- meldestelle-network
secrets:
- keycloak_admin_password
- postgres_user
- postgres_password
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 1G
healthcheck:
test: ['CMD-SHELL', 'curl -fsS --max-time 5 http://localhost:8080/health/ready || exit 1']
interval: 15s
timeout: 10s
retries: 5
start_period: 90s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Service Discovery - Consul
# ===================================================================
consul:
image: hashicorp/consul:${DOCKER_CONSUL_VERSION:-1.15}
container_name: meldestelle-consul
ports:
- "${CONSUL_PORT:-8500}:8500"
command: >
agent -server -ui -node=server-1 -bootstrap-expect=1 -client=0.0.0.0
-encrypt=$(consul keygen)
-datacenter=meldestelle-dc
networks:
- meldestelle-network
volumes:
- consul-data:/consul/data
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
healthcheck:
test: ["CMD", "consul", "members", "-http-addr=localhost:8500"]
interval: 10s
timeout: 5s
retries: 3
start_period: 20s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Messaging - Zookeeper & Kafka with Resource Limits
# ===================================================================
zookeeper:
image: confluentinc/cp-zookeeper:${DOCKER_ZOOKEEPER_VERSION:-7.4.0}
container_name: meldestelle-zookeeper
environment:
ZOOKEEPER_CLIENT_PORT: ${ZOOKEEPER_CLIENT_PORT:-2181}
ZOOKEEPER_TICK_TIME: 2000
ZOOKEEPER_INIT_LIMIT: 5
ZOOKEEPER_SYNC_LIMIT: 2
KAFKA_OPTS: "-Xmx512m -Xms256m"
ports:
- "${ZOOKEEPER_CLIENT_PORT:-2181}:2181"
volumes:
- zookeeper-data:/var/lib/zookeeper/data
- zookeeper-logs:/var/lib/zookeeper/log
networks:
- meldestelle-network
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
healthcheck:
test: ["CMD", "bash", "-c", "echo 'ruok' | nc localhost 2181 | grep imok"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
restart: unless-stopped
security_opt:
- no-new-privileges:true
kafka:
image: confluentinc/cp-kafka:${DOCKER_KAFKA_VERSION:-7.4.0}
container_name: meldestelle-kafka
environment:
KAFKA_BROKER_ID: ${KAFKA_BROKER_ID:-1}
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:${KAFKA_PORT:-9092}
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: ${KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR:-1}
# JVM Settings
KAFKA_HEAP_OPTS: "-Xmx1G -Xms512m"
KAFKA_JVM_PERFORMANCE_OPTS: "-XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35"
ports:
- "${KAFKA_PORT:-9092}:9092"
depends_on:
zookeeper:
condition: service_healthy
volumes:
- kafka-data:/var/lib/kafka/data
networks:
- meldestelle-network
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
healthcheck:
test: ["CMD", "kafka-broker-api-versions", "--bootstrap-server", "localhost:9092"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Monitoring - Prometheus with Security
# ===================================================================
prometheus:
image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1}
container_name: meldestelle-prometheus
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
volumes:
- prometheus-data:/prometheus
- ./docker/monitoring/prometheus:/etc/prometheus:ro
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.retention.time=15d'
- '--storage.tsdb.retention.size=20GB'
- '--web.enable-lifecycle'
- '--web.enable-admin-api'
networks:
- meldestelle-network
deploy:
resources:
limits:
cpus: '1.0'
memory: 2G
reservations:
cpus: '0.25'
memory: 512M
healthcheck:
test: ["CMD", "promtool", "query", "instant", "localhost:9090", "up"]
interval: 15s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped
security_opt:
- no-new-privileges:true
user: "65534:65534" # nobody:nobody
# ===================================================================
# Monitoring - Grafana with Enhanced Security
# ===================================================================
grafana:
image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0}
container_name: meldestelle-grafana
environment:
# Use secrets for admin credentials
GF_SECURITY_ADMIN_USER__FILE: /run/secrets/grafana_admin_user
GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/grafana_admin_password
GF_USERS_ALLOW_SIGN_UP: false
GF_INSTALL_PLUGINS: grafana-piechart-panel
# Security settings
GF_SECURITY_COOKIE_SECURE: true
GF_SECURITY_COOKIE_SAMESITE: strict
GF_SECURITY_DISABLE_GRAVATAR: true
GF_ANALYTICS_REPORTING_ENABLED: false
GF_ANALYTICS_CHECK_FOR_UPDATES: false
GF_SNAPSHOTS_EXTERNAL_ENABLED: false
ports:
- "${GRAFANA_PORT:-3000}:3000"
volumes:
- grafana-data:/var/lib/grafana
- ./docker/monitoring/grafana:/etc/grafana/provisioning:ro
depends_on:
- prometheus
networks:
- meldestelle-network
secrets:
- grafana_admin_user
- grafana_admin_password
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:3000/api/health"]
interval: 15s
timeout: 10s
retries: 3
start_period: 30s
restart: unless-stopped
security_opt:
- no-new-privileges:true
user: "472:0" # grafana user
# ===================================================================
# API Gateway - Enhanced Security & Resource Management
# ===================================================================
api-gateway:
build:
context: .
dockerfile: dockerfiles/infrastructure/gateway/Dockerfile
args:
# Global build arguments (build-time only)
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION}
JAVA_VERSION: ${DOCKER_JAVA_VERSION}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
container_name: meldestelle-api-gateway
env_file:
- config/env/.env
# Optional infrastructure-specific overrides (only if file exists)
- config/env/infrastructure/api-gateway.env
volumes:
# Mount Gradle cache for better build performance
- api-gateway-gradle-cache:/home/gradle/.gradle
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev,keycloak}
CONSUL_HOST: consul
CONSUL_PORT: ${CONSUL_PORT:-8500}
CONSUL_ENABLED: "true"
GATEWAY_PORT: ${GATEWAY_PORT:-8081}
# Keycloak OAuth2 Integration - Using internal network
KEYCLOAK_SERVER_URL: http://keycloak:8080
KEYCLOAK_ISSUER_URI: http://keycloak:8080/realms/meldestelle
KEYCLOAK_JWK_SET_URI: http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs
KEYCLOAK_REALM: meldestelle
KEYCLOAK_CLIENT_ID: api-gateway
# Security: Client secret via file
KEYCLOAK_CLIENT_SECRET_FILE: /run/secrets/keycloak_client_secret
# Custom JWT filter disabled - using oauth2ResourceServer instead
GATEWAY_SECURITY_KEYCLOAK_ENABLED: "false"
# Database connection via secrets
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: ${POSTGRES_DB:-meldestelle}
DB_USERNAME_FILE: /run/secrets/postgres_user
DB_PASSWORD_FILE: /run/secrets/postgres_password
# Redis connection with auth
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD_FILE: /run/secrets/redis_password
ports:
- "${GATEWAY_PORT:-8081}:8081"
depends_on:
consul:
condition: service_healthy
postgres:
condition: service_healthy
redis:
condition: service_healthy
keycloak:
condition: service_started
networks:
- meldestelle-network
# Secrets für lokale Dev optional; mit Profil "prod" aktivieren
profiles: ["prod"]
secrets:
- keycloak_client_secret
- postgres_user
- postgres_password
- redis_password
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 1G
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:${GATEWAY_PORT:-8081}/actuator/health/readiness"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
restart: unless-stopped
security_opt:
- no-new-privileges:true
# ===================================================================
# Secrets Management - Production Ready
# ===================================================================
secrets:
postgres_user:
file: ./docker/secrets/postgres_user.txt
postgres_password:
file: ./docker/secrets/postgres_password.txt
redis_password:
file: ./docker/secrets/redis_password.txt
keycloak_admin_password:
file: ./docker/secrets/keycloak_admin_password.txt
keycloak_client_secret:
file: ./docker/secrets/keycloak_client_secret.txt
grafana_admin_user:
file: ./docker/secrets/grafana_admin_user.txt
grafana_admin_password:
file: ./docker/secrets/grafana_admin_password.txt
# ===================================================================
# Volumes - Enhanced with Better Drivers
# ===================================================================
volumes:
postgres-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/postgres
redis-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/redis
prometheus-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/prometheus
grafana-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/grafana
keycloak-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/keycloak
consul-data:
driver: local
driver_opts:
type: none
o: bind
device: ${DATA_PATH:-./data}/consul
zookeeper-data:
driver: local
zookeeper-logs:
driver: local
kafka-data:
driver: local
api-gateway-gradle-cache:
driver: local
# ===================================================================
# Networks - Enhanced Security
# ===================================================================
networks:
meldestelle-network:
driver: bridge
driver_opts:
com.docker.network.bridge.enable_icc: "true"
com.docker.network.bridge.enable_ip_masquerade: "true"
com.docker.network.driver.mtu: "1500"
ipam:
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
@@ -0,0 +1,29 @@
-- ===================================================================
-- PostgreSQL Initialization Script for Keycloak
-- ===================================================================
-- Dieses Skript erstellt ein separates Schema für Keycloak-Daten innerhalb der
-- meldestelle-Datenbank und sorgt so für Isolation und bessere Organisation.
--
-- Ausführung: Wird automatisch von PostgreSQL beim ersten Start ausgeführt
-- über den docker-entrypoint-initdb.d-Mechanismus.
-- ===================================================================
-- Erstellt das Keycloak-Schema, falls es noch nicht existiert.
CREATE SCHEMA IF NOT EXISTS keycloak;
-- Gewährt dem Benutzer „meldestelle“ alle Berechtigungen für das Schema.
GRANT ALL PRIVILEGES ON SCHEMA keycloak TO "pg-user";
-- Gewährt die Nutzung des Schemas
GRANT USAGE ON SCHEMA keycloak TO "pg-user";
-- Standardberechtigungen für zukünftige Tabellen im Keycloak-Schema festlegen
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON TABLES TO "pg-user";
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON SEQUENCES TO "pg-user";
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON FUNCTIONS TO "pg-user";
-- Log successful schema Erstellung
DO $$
BEGIN
RAISE NOTICE 'Keycloak schema created successfully in database';
END $$;
@@ -1,8 +1,8 @@
-- =================================================================== -- ===================================================================
-- Keycloak Schema Init (No-Op) -- Keycloak Schema Init (No-Op)
-- =================================================================== -- ===================================================================
-- DEPRECATED: Schema initialization is handled by 01-init-keycloak-schema.sql. -- DEPRECATED: Schema-initialization erfolgt über die Datei 01-init-keycloak-schema.sql.
-- This file remains to preserve execution order but performs no actions. -- Diese Datei dient lediglich der Sicherstellung der Ausführungsreihenfolge, führt aber keine Aktionen aus.
-- =================================================================== -- ===================================================================
DO $$ DO $$
@@ -1,294 +0,0 @@
{
"realm": "meldestelle",
"enabled": true,
"displayName": "Meldestelle Authentication",
"displayNameHtml": "<div class=\"kc-logo-text\"><span>Meldestelle</span></div>",
"sslRequired": "external",
"registrationAllowed": false,
"registrationEmailAsUsername": false,
"rememberMe": true,
"verifyEmail": false,
"loginWithEmailAllowed": true,
"duplicateEmailsAllowed": false,
"resetPasswordAllowed": true,
"editUsernameAllowed": false,
"bruteForceProtected": true,
"permanentLockout": false,
"maxFailureWaitSeconds": 900,
"minimumQuickLoginWaitSeconds": 60,
"waitIncrementSeconds": 60,
"quickLoginCheckMilliSeconds": 1000,
"maxDeltaTimeSeconds": 43200,
"failureFactor": 5,
"defaultSignatureAlgorithm": "RS256",
"offlineSessionMaxLifespan": 5184000,
"offlineSessionMaxLifespanEnabled": false,
"accessTokenLifespan": 300,
"accessTokenLifespanForImplicitFlow": 900,
"ssoSessionIdleTimeout": 1800,
"ssoSessionMaxLifespan": 36000,
"refreshTokenMaxReuse": 0,
"accessCodeLifespan": 60,
"accessCodeLifespanUserAction": 300,
"accessCodeLifespanLogin": 1800,
"actionTokenGeneratedByAdminLifespan": 43200,
"actionTokenGeneratedByUserLifespan": 300,
"oauth2DeviceCodeLifespan": 600,
"oauth2DevicePollingInterval": 5,
"internationalizationEnabled": true,
"supportedLocales": ["de", "en"],
"defaultLocale": "de",
"roles": {
"realm": [
{
"name": "ADMIN",
"description": "Administrator role with full system access",
"composite": false,
"clientRole": false
},
{
"name": "USER",
"description": "Standard user role with limited access",
"composite": false,
"clientRole": false
},
{
"name": "MONITORING",
"description": "Monitoring role for system health checks",
"composite": false,
"clientRole": false
},
{
"name": "GUEST",
"description": "Guest role with minimal access",
"composite": false,
"clientRole": false
}
]
},
"clients": [
{
"clientId": "api-gateway",
"name": "API Gateway Client",
"description": "OAuth2 client for the Meldestelle API Gateway",
"enabled": true,
"alwaysDisplayInConsole": false,
"clientAuthenticatorType": "client-secret",
"secret": "**********",
"redirectUris": [
"http://localhost:8081/*",
"http://localhost:3000/*",
"https://app.meldestelle.at/*"
],
"webOrigins": [
"http://localhost:8081",
"http://localhost:3000",
"https://app.meldestelle.at"
],
"protocol": "openid-connect",
"bearerOnly": false,
"publicClient": false,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"serviceAccountsEnabled": true,
"authorizationServicesEnabled": false,
"fullScopeAllowed": true,
"frontchannelLogout": true,
"attributes": {
"access.token.lifespan": "300",
"client.secret.creation.time": "0",
"oauth2.device.authorization.grant.enabled": "false",
"backchannel.logout.session.required": "true",
"backchannel.logout.revoke.offline.tokens": "false"
},
"protocolMappers": [
{
"name": "realm-roles",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-realm-role-mapper",
"consentRequired": false,
"config": {
"multivalued": "true",
"userinfo.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "realm_access.roles",
"jsonType.label": "String"
}
},
{
"name": "client-roles",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-client-role-mapper",
"consentRequired": false,
"config": {
"multivalued": "true",
"userinfo.token.claim": "true",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "resource_access.${client_id}.roles",
"jsonType.label": "String"
}
},
{
"name": "username",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-property-mapper",
"consentRequired": false,
"config": {
"userinfo.token.claim": "true",
"user.attribute": "username",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "preferred_username",
"jsonType.label": "String"
}
},
{
"name": "email",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-property-mapper",
"consentRequired": false,
"config": {
"userinfo.token.claim": "true",
"user.attribute": "email",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "email",
"jsonType.label": "String"
}
},
{
"name": "full-name",
"protocol": "openid-connect",
"protocolMapper": "oidc-full-name-mapper",
"consentRequired": false,
"config": {
"id.token.claim": "true",
"access.token.claim": "true",
"userinfo.token.claim": "true"
}
}
]
},
{
"clientId": "web-app",
"name": "Web Application Client",
"description": "Public client for web frontend",
"enabled": true,
"publicClient": true,
"standardFlowEnabled": true,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"redirectUris": [
"http://localhost:3000/*",
"https://app.meldestelle.at/*"
],
"webOrigins": [
"http://localhost:3000",
"https://app.meldestelle.at"
],
"protocol": "openid-connect",
"attributes": {
"pkce.code.challenge.method": "S256"
}
}
],
"users": [
{
"username": "admin",
"enabled": true,
"emailVerified": true,
"firstName": "System",
"lastName": "Administrator",
"email": "admin@meldestelle.local",
"credentials": [
{
"type": "password",
"value": "Change_Me_In_Production!",
"temporary": true
}
],
"realmRoles": ["ADMIN", "USER"],
"clientRoles": {
"api-gateway": ["ADMIN"]
}
}
],
"groups": [],
"defaultRoles": ["USER", "GUEST"],
"requiredCredentials": ["password"],
"passwordPolicy": "length(8)",
"otpPolicyType": "totp",
"otpPolicyAlgorithm": "HmacSHA1",
"otpPolicyInitialCounter": 0,
"otpPolicyDigits": 6,
"otpPolicyLookAheadWindow": 1,
"otpPolicyPeriod": 30,
"otpSupportedApplications": ["FreeOTP", "Google Authenticator"],
"webAuthnPolicyRpEntityName": "meldestelle",
"webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"],
"smtpServer": {},
"eventsEnabled": true,
"eventsListeners": ["jboss-logging"],
"enabledEventTypes": [
"LOGIN",
"LOGIN_ERROR",
"LOGOUT",
"REGISTER",
"REGISTER_ERROR",
"UPDATE_PASSWORD",
"UPDATE_PASSWORD_ERROR"
],
"adminEventsEnabled": true,
"adminEventsDetailsEnabled": true,
"identityProviders": [],
"identityProviderMappers": [],
"components": {
"org.keycloak.keys.KeyProvider": [
{
"name": "rsa-generated",
"providerId": "rsa-generated",
"subComponents": {},
"config": {
"priority": ["100"]
}
},
{
"name": "hmac-generated",
"providerId": "hmac-generated",
"subComponents": {},
"config": {
"priority": ["100"],
"algorithm": ["HS256"]
}
},
{
"name": "aes-generated",
"providerId": "aes-generated",
"subComponents": {},
"config": {
"priority": ["100"]
}
}
]
},
"authenticationFlows": [],
"authenticatorConfig": [],
"requiredActions": [],
"browserFlow": "browser",
"registrationFlow": "registration",
"directGrantFlow": "direct grant",
"resetCredentialsFlow": "reset credentials",
"clientAuthenticationFlow": "clients",
"dockerAuthenticationFlow": "docker auth",
"attributes": {
"frontendUrl": "",
"acr.loa.map": "{}",
"clientOfflineSessionMaxLifespan": "0",
"clientSessionIdleTimeout": "0",
"clientSessionMaxLifespan": "0",
"clientOfflineSessionIdleTimeout": "0"
}
}
@@ -1,31 +0,0 @@
-- ===================================================================
-- PostgreSQL Initialization Script for Keycloak
-- ===================================================================
-- This script creates a separate schema for Keycloak data within the
-- meldestelle database, providing isolation and better organization.
--
-- Execution: Automatically executed by PostgreSQL on first startup
-- via docker-entrypoint-initdb.d mechanism.
-- ===================================================================
-- Create Keycloak schema if it doesn't exist
CREATE SCHEMA IF NOT EXISTS keycloak;
-- Grant all privileges on the schema to the meldestelle user
GRANT ALL PRIVILEGES ON SCHEMA keycloak TO meldestelle;
-- Grant usage on the schema
GRANT USAGE ON SCHEMA keycloak TO meldestelle;
-- Set default privileges for future tables in the keycloak schema
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON TABLES TO meldestelle;
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON SEQUENCES TO meldestelle;
ALTER DEFAULT PRIVILEGES IN SCHEMA keycloak GRANT ALL ON FUNCTIONS TO meldestelle;
-- Log successful schema creation
DO $$
BEGIN
RAISE NOTICE 'Keycloak schema created successfully';
RAISE NOTICE 'Schema: keycloak';
RAISE NOTICE 'Owner: meldestelle';
END $$;