diff --git a/.dockerignore b/.dockerignore index f973e99e..f2b1295a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -171,7 +171,7 @@ backup.sh # =================================================================== # Security and certificates (never include in builds) # =================================================================== -config/ssl/ +_backup_chaos/config/ssl/ **/*.key **/*.pem **/*.p12 diff --git a/.gitignore b/.gitignore index bfdfbcf7..716b0ca3 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ logs/ build/diagrams/ # Local runtime secrets/overrides -config/env/.env.local +_backup_chaos/config/env/.env.local # Python virtual environment .venv/ diff --git a/.env.template b/_backup_chaos/.env.template similarity index 100% rename from .env.template rename to _backup_chaos/.env.template diff --git a/.env~origin_main b/_backup_chaos/.env~origin_main similarity index 100% rename from .env~origin_main rename to _backup_chaos/.env~origin_main diff --git a/_backup_chaos/compose.yaml b/_backup_chaos/compose.yaml new file mode 100644 index 00000000..770d83c0 --- /dev/null +++ b/_backup_chaos/compose.yaml @@ -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 diff --git a/config/.env.dev b/_backup_chaos/config/.env.dev similarity index 100% rename from config/.env.dev rename to _backup_chaos/config/.env.dev diff --git a/config/.env.prod b/_backup_chaos/config/.env.prod similarity index 100% rename from config/.env.prod rename to _backup_chaos/config/.env.prod diff --git a/config/.env.staging b/_backup_chaos/config/.env.staging similarity index 100% rename from config/.env.staging rename to _backup_chaos/config/.env.staging diff --git a/config/.env.template b/_backup_chaos/config/.env.template similarity index 100% rename from config/.env.template rename to _backup_chaos/config/.env.template diff --git a/config/.env.test b/_backup_chaos/config/.env.test similarity index 100% rename from config/.env.test rename to _backup_chaos/config/.env.test diff --git a/config/README.md b/_backup_chaos/config/README.md similarity index 100% rename from config/README.md rename to _backup_chaos/config/README.md diff --git a/config/application.yml b/_backup_chaos/config/application.yml similarity index 100% rename from config/application.yml rename to _backup_chaos/config/application.yml diff --git a/config/central.toml b/_backup_chaos/config/central.toml similarity index 100% rename from config/central.toml rename to _backup_chaos/config/central.toml diff --git a/config/env/.env b/_backup_chaos/config/env/.env similarity index 100% rename from config/env/.env rename to _backup_chaos/config/env/.env diff --git a/config/env/clients/web-app.env b/_backup_chaos/config/env/clients/web-app.env similarity index 100% rename from config/env/clients/web-app.env rename to _backup_chaos/config/env/clients/web-app.env diff --git a/config/env/infrastructure/api-gateway.env b/_backup_chaos/config/env/infrastructure/api-gateway.env similarity index 100% rename from config/env/infrastructure/api-gateway.env rename to _backup_chaos/config/env/infrastructure/api-gateway.env diff --git a/config/env/services/events-service.env b/_backup_chaos/config/env/services/events-service.env similarity index 100% rename from config/env/services/events-service.env rename to _backup_chaos/config/env/services/events-service.env diff --git a/config/env/services/horses-service.env b/_backup_chaos/config/env/services/horses-service.env similarity index 100% rename from config/env/services/horses-service.env rename to _backup_chaos/config/env/services/horses-service.env diff --git a/config/env/services/masterdata-service.env b/_backup_chaos/config/env/services/masterdata-service.env similarity index 100% rename from config/env/services/masterdata-service.env rename to _backup_chaos/config/env/services/masterdata-service.env diff --git a/config/env/services/members-service.env b/_backup_chaos/config/env/services/members-service.env similarity index 100% rename from config/env/services/members-service.env rename to _backup_chaos/config/env/services/members-service.env diff --git a/config/env/services/ping-service.env b/_backup_chaos/config/env/services/ping-service.env similarity index 100% rename from config/env/services/ping-service.env rename to _backup_chaos/config/env/services/ping-service.env diff --git a/config/kafka/secrets/kafka_jaas.conf b/_backup_chaos/config/kafka/secrets/kafka_jaas.conf similarity index 100% rename from config/kafka/secrets/kafka_jaas.conf rename to _backup_chaos/config/kafka/secrets/kafka_jaas.conf diff --git a/config/kafka/secrets/zookeeper_jaas.conf b/_backup_chaos/config/kafka/secrets/zookeeper_jaas.conf similarity index 100% rename from config/kafka/secrets/zookeeper_jaas.conf rename to _backup_chaos/config/kafka/secrets/zookeeper_jaas.conf diff --git a/config/monitoring/alertmanager/alertmanager.yml b/_backup_chaos/config/monitoring/alertmanager/alertmanager.yml similarity index 100% rename from config/monitoring/alertmanager/alertmanager.yml rename to _backup_chaos/config/monitoring/alertmanager/alertmanager.yml diff --git a/config/monitoring/elk/elasticsearch.yml b/_backup_chaos/config/monitoring/elk/elasticsearch.yml similarity index 100% rename from config/monitoring/elk/elasticsearch.yml rename to _backup_chaos/config/monitoring/elk/elasticsearch.yml diff --git a/config/monitoring/elk/logstash.conf b/_backup_chaos/config/monitoring/elk/logstash.conf similarity index 100% rename from config/monitoring/elk/logstash.conf rename to _backup_chaos/config/monitoring/elk/logstash.conf diff --git a/config/monitoring/grafana/dashboards/application-overview-dashboard.json b/_backup_chaos/config/monitoring/grafana/dashboards/application-overview-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/application-overview-dashboard.json rename to _backup_chaos/config/monitoring/grafana/dashboards/application-overview-dashboard.json diff --git a/config/monitoring/grafana/dashboards/infrastructure-dashboard.json b/_backup_chaos/config/monitoring/grafana/dashboards/infrastructure-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/infrastructure-dashboard.json rename to _backup_chaos/config/monitoring/grafana/dashboards/infrastructure-dashboard.json diff --git a/config/monitoring/grafana/dashboards/jvm-dashboard.json b/_backup_chaos/config/monitoring/grafana/dashboards/jvm-dashboard.json similarity index 100% rename from config/monitoring/grafana/dashboards/jvm-dashboard.json rename to _backup_chaos/config/monitoring/grafana/dashboards/jvm-dashboard.json diff --git a/config/monitoring/grafana/provisioning/dashboards/dashboard.yml b/_backup_chaos/config/monitoring/grafana/provisioning/dashboards/dashboard.yml similarity index 100% rename from config/monitoring/grafana/provisioning/dashboards/dashboard.yml rename to _backup_chaos/config/monitoring/grafana/provisioning/dashboards/dashboard.yml diff --git a/config/monitoring/grafana/provisioning/datasources/datasource.yml b/_backup_chaos/config/monitoring/grafana/provisioning/datasources/datasource.yml similarity index 100% rename from config/monitoring/grafana/provisioning/datasources/datasource.yml rename to _backup_chaos/config/monitoring/grafana/provisioning/datasources/datasource.yml diff --git a/config/monitoring/prometheus.dev.yml b/_backup_chaos/config/monitoring/prometheus.dev.yml similarity index 100% rename from config/monitoring/prometheus.dev.yml rename to _backup_chaos/config/monitoring/prometheus.dev.yml diff --git a/config/monitoring/prometheus.prod.yml b/_backup_chaos/config/monitoring/prometheus.prod.yml similarity index 100% rename from config/monitoring/prometheus.prod.yml rename to _backup_chaos/config/monitoring/prometheus.prod.yml diff --git a/config/monitoring/prometheus.yml b/_backup_chaos/config/monitoring/prometheus.yml similarity index 100% rename from config/monitoring/prometheus.yml rename to _backup_chaos/config/monitoring/prometheus.yml diff --git a/config/monitoring/prometheus/rules/alerts.yml b/_backup_chaos/config/monitoring/prometheus/rules/alerts.yml similarity index 100% rename from config/monitoring/prometheus/rules/alerts.yml rename to _backup_chaos/config/monitoring/prometheus/rules/alerts.yml diff --git a/config/nginx/nginx.prod.conf b/_backup_chaos/config/nginx/nginx.prod.conf similarity index 100% rename from config/nginx/nginx.prod.conf rename to _backup_chaos/config/nginx/nginx.prod.conf diff --git a/config/postgres/postgresql.conf b/_backup_chaos/config/postgres/postgresql.conf similarity index 100% rename from config/postgres/postgresql.conf rename to _backup_chaos/config/postgres/postgresql.conf diff --git a/config/redis/redis.conf b/_backup_chaos/config/redis/redis.conf similarity index 100% rename from config/redis/redis.conf rename to _backup_chaos/config/redis/redis.conf diff --git a/config/ssl/README-de.md b/_backup_chaos/config/ssl/README-de.md similarity index 100% rename from config/ssl/README-de.md rename to _backup_chaos/config/ssl/README-de.md diff --git a/docker-compose.clients.yml b/_backup_chaos/docker-compose.clients.yml similarity index 94% rename from docker-compose.clients.yml rename to _backup_chaos/docker-compose.clients.yml index 30bc4c83..cff30daa 100644 --- a/docker-compose.clients.yml +++ b/_backup_chaos/docker-compose.clients.yml @@ -10,9 +10,10 @@ services: # Web Application (Compose for Web) # =================================================================== web-app: + profiles: ["ui", "frontend"] build: - context: . - dockerfile: dockerfiles/clients/web-app/Dockerfile + context: .. + dockerfile: ../dockerfiles/clients/web-app/Dockerfile args: # Global build arguments (centralized DOCKER_* variables) GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} diff --git a/docker-compose.services.yml b/_backup_chaos/docker-compose.services.yml similarity index 91% rename from docker-compose.services.yml rename to _backup_chaos/docker-compose.services.yml index 2c4a7682..241c30e2 100644 --- a/docker-compose.services.yml +++ b/_backup_chaos/docker-compose.services.yml @@ -6,10 +6,11 @@ # =================================================================== services: + profiles: ["app", "backend"] ping-service: build: - context: . - dockerfile: dockerfiles/services/ping-service/Dockerfile + context: .. + dockerfile: ../dockerfiles/services/ping-service/Dockerfile args: # Global build arguments (centralized DOCKER_* variables) GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} @@ -39,9 +40,10 @@ services: restart: unless-stopped api-gateway: + profiles: ["infra", "gateway"] build: - context: . - dockerfile: dockerfiles/infrastructure/gateway/Dockerfile + context: .. + dockerfile: ../dockerfiles/infrastructure/gateway/Dockerfile args: # Global build arguments (centralized DOCKER_* variables) GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} diff --git a/docker-compose.yml b/_backup_chaos/docker-compose.yml similarity index 96% rename from docker-compose.yml rename to _backup_chaos/docker-compose.yml index d742fdbf..b2fafb94 100644 --- a/docker-compose.yml +++ b/_backup_chaos/docker-compose.yml @@ -10,6 +10,7 @@ services: # Database # =================================================================== postgres: + profiles: ["core", "backend"] image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine} container_name: meldestelle-postgres environment: @@ -35,6 +36,7 @@ services: # Cache # =================================================================== redis: + profiles: ["core", "backend"] image: redis:${DOCKER_REDIS_VERSION:-7-alpine} container_name: meldestelle-redis ports: @@ -56,6 +58,7 @@ services: # Authentication # =================================================================== keycloak: + profiles: ["auth", "security"] image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2} container_name: meldestelle-keycloak environment: @@ -87,6 +90,7 @@ services: # Monitoring # =================================================================== prometheus: + profiles: ["monitoring"] image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1} container_name: meldestelle-prometheus ports: @@ -112,6 +116,7 @@ services: restart: unless-stopped grafana: + profiles: ["monitoring"] image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0} container_name: meldestelle-grafana environment: diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 00000000..2e3f3648 --- /dev/null +++ b/compose.yaml @@ -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 diff --git a/docker-compose.clients.yml.optimized b/docker-compose.clients.yml.optimized deleted file mode 100644 index dea29b74..00000000 --- a/docker-compose.clients.yml.optimized +++ /dev/null @@ -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 diff --git a/docker-compose.services.yml.optimized b/docker-compose.services.yml.optimized deleted file mode 100644 index 8f9e01fb..00000000 --- a/docker-compose.services.yml.optimized +++ /dev/null @@ -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 diff --git a/docker-compose.yml.optimized b/docker-compose.yml.optimized deleted file mode 100644 index a501cf04..00000000 --- a/docker-compose.yml.optimized +++ /dev/null @@ -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 diff --git a/docker/services/keycloak/meldestelle-realm.json b/docker/core/keycloak/meldestelle-realm.json similarity index 100% rename from docker/services/keycloak/meldestelle-realm.json rename to docker/core/keycloak/meldestelle-realm.json diff --git a/docker/core/postgres/01-init-keycloak-schema.sql b/docker/core/postgres/01-init-keycloak-schema.sql new file mode 100644 index 00000000..6da768f7 --- /dev/null +++ b/docker/core/postgres/01-init-keycloak-schema.sql @@ -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 $$; diff --git a/docker/services/postgres/02-init-keycloak-schema.sql b/docker/core/postgres/02-init-keycloak-schema.sql similarity index 64% rename from docker/services/postgres/02-init-keycloak-schema.sql rename to docker/core/postgres/02-init-keycloak-schema.sql index 9ccc7ef9..6ddb81ff 100644 --- a/docker/services/postgres/02-init-keycloak-schema.sql +++ b/docker/core/postgres/02-init-keycloak-schema.sql @@ -1,8 +1,8 @@ -- =================================================================== -- Keycloak Schema Init (No-Op) -- =================================================================== --- DEPRECATED: Schema initialization is handled by 01-init-keycloak-schema.sql. --- This file remains to preserve execution order but performs no actions. +-- DEPRECATED: Schema-initialization erfolgt über die Datei 01-init-keycloak-schema.sql. +-- Diese Datei dient lediglich der Sicherstellung der Ausführungsreihenfolge, führt aber keine Aktionen aus. -- =================================================================== DO $$ diff --git a/docker/services/keycloak/meldestelle-realm.json.backup b/docker/services/keycloak/meldestelle-realm.json.backup deleted file mode 100644 index 07966db6..00000000 --- a/docker/services/keycloak/meldestelle-realm.json.backup +++ /dev/null @@ -1,294 +0,0 @@ -{ - "realm": "meldestelle", - "enabled": true, - "displayName": "Meldestelle Authentication", - "displayNameHtml": "
Meldestelle
", - "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" - } -} diff --git a/docker/services/postgres/01-init-keycloak-schema.sql b/docker/services/postgres/01-init-keycloak-schema.sql deleted file mode 100644 index ce9cc7cd..00000000 --- a/docker/services/postgres/01-init-keycloak-schema.sql +++ /dev/null @@ -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 $$;