feature Keycloak Auth

This commit is contained in:
2025-10-06 01:07:16 +02:00
parent 82b1a2679d
commit a2ffb1e076
24 changed files with 3089 additions and 65 deletions
+207
View File
@@ -0,0 +1,207 @@
# ===================================================================
# Environment Configuration Template - Meldestelle Project
# ===================================================================
# Copy this file to .env and customize the values for your environment
# Security Note: Never commit .env files containing production secrets!
# ===================================================================
# ===================================================================
# Build Configuration
# ===================================================================
# Docker image versions
DOCKER_GRADLE_VERSION=9.0.0
DOCKER_JAVA_VERSION=21
DOCKER_KEYCLOAK_VERSION=26.4.0
DOCKER_PROMETHEUS_VERSION=v2.54.1
DOCKER_GRAFANA_VERSION=11.3.0
# Application version
DOCKER_APP_VERSION=1.0.0
APP_VERSION=1.0.0
APP_NAME=Meldestelle
# Build metadata
BUILD_DATE=
# BUILD_DATE will be auto-generated if not set
# Spring profiles for services
SPRING_PROFILES_ACTIVE=docker,keycloak
DOCKER_SPRING_PROFILES_DEFAULT=default
DOCKER_SPRING_PROFILES_DOCKER=docker
# ===================================================================
# Infrastructure Services - Port Configuration
# ===================================================================
# Database
POSTGRES_DB=meldestelle
# Note: Username and password are now managed via Docker secrets
# Redis Cache
REDIS_PORT=6379
# Keycloak Authentication
KEYCLOAK_PORT=8180
KEYCLOAK_LOG_LEVEL=INFO
# Service Discovery
CONSUL_HOST=consul
CONSUL_PORT=8500
CONSUL_ENABLED=true
# Messaging
ZOOKEEPER_CLIENT_PORT=2181
KAFKA_PORT=9092
KAFKA_BROKER_ID=1
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1
# Monitoring
PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
# ===================================================================
# Application Services - Port Configuration
# ===================================================================
# API Gateway
GATEWAY_HOST=api-gateway
GATEWAY_PORT=8081
# Microservices
PING_SERVICE_PORT=8082
MEMBERS_SERVICE_PORT=8083
HORSES_SERVICE_PORT=8084
EVENTS_SERVICE_PORT=8085
MASTERDATA_SERVICE_PORT=8086
AUTH_SERVICE_PORT=8087
MONITORING_SERVER_PORT=8088
# ===================================================================
# Client Applications - Port Configuration
# ===================================================================
# Web Application
WEB_APP_PORT=4000
WEB_APP_DOMAIN=localhost
NODE_ENV=production
# Nginx Configuration
NGINX_WORKER_PROCESSES=auto
NGINX_WORKER_CONNECTIONS=1024
# Desktop Application
DESKTOP_VNC_WEB_PORT=6080
DESKTOP_VNC_PORT=5901
DESKTOP_APP_DOMAIN=localhost
# ===================================================================
# Security Configuration
# ===================================================================
# JWT Configuration
JWT_ISSUER=meldestelle-auth-server
JWT_AUDIENCE=meldestelle-services
# Note: JWT_SECRET is now managed via Docker secrets
# Generate with: openssl rand -hex 32
# Keycloak Configuration
KEYCLOAK_REALM=meldestelle
KEYCLOAK_CLIENT_ID=api-gateway
# Note: All passwords and secrets are now managed via Docker secrets
# Run: ./docker/secrets/setup-secrets.sh to generate secure secrets
# ===================================================================
# Data Storage Configuration
# ===================================================================
# Data directory for persistent volumes
# Default: ./data (relative to project root)
# Production: /var/lib/meldestelle or dedicated mount point
DATA_PATH=./data
# Volume configuration
# These directories will be created under DATA_PATH:
# - postgres/ (PostgreSQL data)
# - redis/ (Redis data)
# - prometheus/ (Prometheus metrics)
# - grafana/ (Grafana dashboards)
# - keycloak/ (Keycloak data)
# - consul/ (Consul data)
# - monitoring/ (Custom monitoring data)
# - desktop-app/ (Desktop application data)
# ===================================================================
# Development and Testing
# ===================================================================
# Enable debug mode for Java applications
DEBUG=false
# Enable Wasm compilation for client applications
enableWasm=false
# ===================================================================
# Production Deployment Settings
# ===================================================================
# Container resource limits (configured in docker-compose files)
# These are documented here for reference:
# Infrastructure Services Resource Limits:
# - postgres: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - redis: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - keycloak: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# - consul: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - kafka: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - zookeeper: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - prometheus: 1 CPU, 2GB RAM (reserved: 0.25 CPU, 512MB RAM)
# - grafana: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - api-gateway: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM)
# Microservices Resource Limits:
# - ping-service: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# - members-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - horses-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - events-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - masterdata-service: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - auth-server: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM)
# Client Applications Resource Limits:
# - web-app: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM)
# - desktop-app: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM)
# - monitoring-server: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM)
# ===================================================================
# Security Notes
# ===================================================================
# 1. All passwords and secrets are managed via Docker secrets
# 2. Run ./docker/secrets/setup-secrets.sh to generate secure credentials
# 3. Containers run as non-root users where possible
# 4. Security options: no-new-privileges enabled for all services
# 5. Networks are isolated with custom subnet (172.20.0.0/16)
# 6. Volumes have proper permissions and are mounted read-only where appropriate
# 7. Health checks are configured for all services
# 8. Resource limits prevent resource exhaustion attacks
# ===================================================================
# Usage Instructions
# ===================================================================
# 1. Copy this file: cp .env.template .env
# 2. Customize values in .env for your environment
# 3. Generate secrets: ./docker/secrets/setup-secrets.sh --all
# 4. Create data directories: mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul}
# 5. Deploy infrastructure: docker-compose -f docker-compose.yml.optimized up -d
# 6. Deploy services: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized up -d
# 7. Deploy clients: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized -f docker-compose.clients.yml.optimized up -d
# ===================================================================
# Monitoring and Logging
# ===================================================================
# Access URLs (when running with default ports):
# - Grafana Dashboard: http://localhost:3000 (admin credentials in secrets)
# - Prometheus Metrics: http://localhost:9090
# - Consul UI: http://localhost:8500
# - Keycloak Admin: http://localhost:8180/admin (admin credentials in secrets)
# - API Gateway: http://localhost:8081
# - Web Application: http://localhost:4000
# - Desktop VNC: http://localhost:6080
# Log locations (inside containers):
# - Application logs: /app/logs/
# - Nginx logs: /var/log/nginx/
# - System logs: journalctl -u docker
+427
View File
@@ -0,0 +1,427 @@
# Docker Configuration Optimization & Security Analysis
## Executive Summary
This document outlines the comprehensive analysis, corrections, and optimizations made to all Docker and docker-compose configurations in the Meldestelle project. The optimizations focus on **security hardening**, **performance improvements**, and **production readiness**.
### Key Achievements
-**Critical Security Vulnerabilities Fixed**: Eliminated hardcoded credentials and exposed secrets
-**Resource Management**: Added comprehensive CPU and memory limits for all services
-**Security Hardening**: Implemented Docker secrets, non-root users, and security constraints
-**Performance Optimization**: Enhanced health checks, startup dependencies, and resource allocation
-**Production Readiness**: Added proper volume management, networking, and monitoring
---
## Security Improvements
### 🔐 Critical Security Issues Resolved
#### 1. **Secrets Management**
**Problem**: Hardcoded credentials in environment variables
```yaml
# BEFORE (INSECURE)
environment:
POSTGRES_PASSWORD: meldestelle
KEYCLOAK_CLIENT_SECRET: K5RqonwVOaxPKaXVH4mbthSRbjRh5tOK
GF_SECURITY_ADMIN_PASSWORD: admin
```
**Solution**: Docker secrets with secure file-based management
```yaml
# AFTER (SECURE)
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
KEYCLOAK_CLIENT_SECRET_FILE: /run/secrets/keycloak_client_secret
GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/grafana_admin_password
secrets:
- postgres_password
- keycloak_client_secret
- grafana_admin_password
```
#### 2. **Container Security Hardening**
**Added Security Measures**:
- `no-new-privileges:true` for all containers
- Non-root user execution where possible
- Read-only volume mounts for configuration files
- Secure file permissions (600) for all secrets
#### 3. **Network Security**
**Improvements**:
- Custom isolated network with dedicated subnet (172.20.0.0/16)
- Proper inter-container communication controls
- Enhanced CORS and security headers for web applications
### 🛡️ Security Features Added
| Security Feature | Implementation | Benefit |
|-----------------|----------------|---------|
| Docker Secrets | File-based secrets management | Eliminates hardcoded credentials |
| Non-root Users | Custom user/group for applications | Reduces attack surface |
| Security Options | `no-new-privileges` flag | Prevents privilege escalation |
| Read-only Mounts | Config files mounted read-only | Prevents runtime tampering |
| Network Isolation | Custom bridge network | Isolates container communication |
| Resource Limits | CPU/Memory constraints | Prevents resource exhaustion attacks |
---
## Performance Optimizations
### 🚀 Resource Management
#### Comprehensive Resource Limits
All services now have properly configured resource limits and reservations:
**Infrastructure Services**:
```yaml
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.5'
memory: 1G
```
**Resource Allocation Summary**:
| Service | CPU Limit | Memory Limit | CPU Reserved | Memory Reserved |
|---------|-----------|--------------|--------------|-----------------|
| PostgreSQL | 2.0 | 2GB | 0.5 | 512MB |
| Redis | 1.0 | 1GB | 0.25 | 256MB |
| Keycloak | 2.0 | 2GB | 0.5 | 1GB |
| API Gateway | 2.0 | 2GB | 0.5 | 1GB |
| Kafka | 2.0 | 2GB | 0.5 | 512MB |
| Grafana | 1.0 | 1GB | 0.25 | 256MB |
| Prometheus | 1.0 | 2GB | 0.25 | 512MB |
### 🔧 Performance Enhancements
#### 1. **Optimized Health Checks**
```yaml
# Enhanced health check configuration
healthcheck:
test: ["CMD", "curl", "--fail", "--max-time", "5", "http://localhost:8080/health/ready"]
interval: 15s
timeout: 10s
retries: 3
start_period: 60s
```
#### 2. **JVM Optimization**
**Kafka JVM Settings**:
```yaml
environment:
KAFKA_HEAP_OPTS: "-Xmx1G -Xms512m"
KAFKA_JVM_PERFORMANCE_OPTS: "-XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35"
```
#### 3. **Database Performance**
**PostgreSQL Enhancements**:
- SCRAM-SHA-256 authentication for better security
- Optimized connection settings
- Proper data persistence with bind mounts
**Redis Optimizations**:
- Memory management with `maxmemory` and `allkeys-lru` policy
- Persistent storage with AOF (Append Only File)
- Authentication enabled
---
## Configuration Structure
### 📁 File Organization
The optimized configuration consists of:
```
├── docker-compose.yml.optimized # Infrastructure services
├── docker-compose.services.yml.optimized # Microservices
├── docker-compose.clients.yml.optimized # Client applications
├── .env.template # Environment configuration template
└── docker/
└── secrets/
├── setup-secrets.sh # Automated secrets generation
├── postgres_user.txt # Database username
├── postgres_password.txt # Database password (generated)
├── redis_password.txt # Redis password (generated)
├── keycloak_admin_password.txt # Keycloak admin password (generated)
├── keycloak_client_secret.txt # API Gateway client secret (generated)
├── grafana_admin_user.txt # Grafana admin username
├── grafana_admin_password.txt # Grafana admin password (generated)
├── jwt_secret.txt # JWT signing secret (generated)
└── vnc_password.txt # VNC access password (generated)
```
### 🔄 Profile-based Deployment
The optimized configuration supports selective service deployment:
```bash
# Infrastructure only
docker-compose -f docker-compose.yml.optimized up -d
# Infrastructure + Microservices
docker-compose -f docker-compose.yml.optimized \
-f docker-compose.services.yml.optimized up -d
# Full stack deployment
docker-compose -f docker-compose.yml.optimized \
-f docker-compose.services.yml.optimized \
-f docker-compose.clients.yml.optimized up -d
# Selective services with profiles
docker-compose -f docker-compose.services.yml.optimized \
--profile members --profile horses up -d
```
---
## Migration Guide
### 🚀 Quick Start
#### 1. **Generate Secrets**
```bash
# Generate all required secrets
./docker/secrets/setup-secrets.sh --all
# Or generate individually
./docker/secrets/setup-secrets.sh --generate
./docker/secrets/setup-secrets.sh --validate
```
#### 2. **Configure Environment**
```bash
# Copy template and customize
cp .env.template .env
# Edit configuration values
nano .env
```
#### 3. **Create Data Directories**
```bash
# Create persistent data directories
mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul,monitoring,desktop-app}
```
#### 4. **Deploy Services**
```bash
# Start infrastructure
docker-compose -f docker-compose.yml.optimized up -d
# Verify all services are healthy
docker-compose -f docker-compose.yml.optimized ps
# Add microservices
docker-compose -f docker-compose.yml.optimized \
-f docker-compose.services.yml.optimized up -d
# Add client applications
docker-compose -f docker-compose.yml.optimized \
-f docker-compose.services.yml.optimized \
-f docker-compose.clients.yml.optimized up -d
```
### 🔄 Migration from Original Configuration
#### Step 1: Backup Current Setup
```bash
# Stop existing services
docker-compose down
# Backup current data (optional)
cp -r data/ data.backup/
```
#### Step 2: Update Configuration
```bash
# Generate secrets first
./docker/secrets/setup-secrets.sh --all
# Update environment configuration
cp .env.template .env
# Edit .env as needed
```
#### Step 3: Deploy Optimized Configuration
```bash
# Deploy with new configuration
docker-compose -f docker-compose.yml.optimized up -d
```
---
## Security Best Practices
### 🛡️ Production Security Checklist
- [ ] **Secrets Generated**: Run secrets setup script
- [ ] **File Permissions**: Ensure secret files have 600 permissions
- [ ] **Network Isolation**: Use custom Docker networks
- [ ] **Resource Limits**: All services have CPU/memory limits
- [ ] **Non-root Users**: Applications run as non-privileged users
- [ ] **Read-only Mounts**: Configuration mounted read-only
- [ ] **Security Options**: `no-new-privileges` enabled
- [ ] **Health Checks**: All critical services have health checks
- [ ] **Backup Strategy**: Regular data backups configured
- [ ] **Monitoring**: Prometheus and Grafana configured
- [ ] **Log Management**: Centralized logging configured
### 🔐 Security Monitoring
#### Access URLs (Default Configuration)
- **Grafana Dashboard**: http://localhost:3000
- **Prometheus Metrics**: http://localhost:9090
- **Consul UI**: http://localhost:8500
- **Keycloak Admin**: http://localhost:8180/admin
#### Security Metrics to Monitor
- Failed authentication attempts
- Resource usage patterns
- Container restart frequency
- Network connection anomalies
- Secret access patterns
---
## Troubleshooting
### 🔍 Common Issues and Solutions
#### Issue 1: Secret File Permissions
**Problem**: Containers cannot read secret files
**Solution**:
```bash
# Fix permissions
chmod 600 docker/secrets/*.txt
# Or regenerate with correct permissions
./docker/secrets/setup-secrets.sh --force
```
#### Issue 2: Resource Constraints
**Problem**: Services failing due to resource limits
**Solution**:
```bash
# Check resource usage
docker stats
# Adjust limits in docker-compose files or increase system resources
```
#### Issue 3: Network Connectivity
**Problem**: Services cannot communicate
**Solution**:
```bash
# Check network configuration
docker network inspect meldestelle_meldestelle-network
# Verify service health
docker-compose -f docker-compose.yml.optimized ps
```
#### Issue 4: Volume Mount Issues
**Problem**: Data not persisting or permission errors
**Solution**:
```bash
# Create data directories with correct permissions
mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul}
chown -R 999:999 ./data/postgres # PostgreSQL user
chown -R 472:0 ./data/grafana # Grafana user
```
### 📊 Health Check Commands
```bash
# Check all service status
docker-compose -f docker-compose.yml.optimized ps
# View service logs
docker-compose -f docker-compose.yml.optimized logs [service-name]
# Check resource usage
docker stats
# Validate secrets
./docker/secrets/setup-secrets.sh --validate
# Test connectivity
docker exec meldestelle-api-gateway curl -f http://postgres:5432
```
---
## Performance Tuning
### 🎯 Resource Optimization Guidelines
#### Memory Allocation Strategy
1. **Infrastructure Services**: Higher memory allocation for databases and messaging
2. **Application Services**: Balanced CPU/memory for microservices
3. **Client Applications**: Lower resource requirements
#### CPU Allocation Strategy
1. **I/O Bound Services** (Database, Redis): Moderate CPU, high memory
2. **Compute Bound Services** (Application logic): Higher CPU allocation
3. **Static Content Services** (Web apps): Lower overall resources
#### JVM Tuning for Java Services
```yaml
environment:
JAVA_OPTS: |
-XX:MaxRAMPercentage=75.0
-XX:+UseG1GC
-XX:+UseStringDeduplication
-XX:+UseContainerSupport
-Djava.security.egd=file:/dev/./urandom
```
---
## Monitoring and Observability
### 📈 Metrics Collection
#### Prometheus Metrics
- Container resource usage
- Application performance metrics
- Health check status
- Network traffic patterns
#### Grafana Dashboards
- Infrastructure overview
- Application performance
- Security events
- Resource utilization trends
#### Logging Strategy
- Centralized logging via Docker logs
- Structured JSON logging for applications
- Log rotation and retention policies
- Security event logging
---
## Conclusion
The Docker configuration optimization provides:
1. **Enhanced Security**: Complete elimination of hardcoded credentials and implementation of Docker secrets
2. **Production Readiness**: Comprehensive resource limits, health checks, and monitoring
3. **Improved Performance**: Optimized resource allocation and container configurations
4. **Operational Excellence**: Automated secret management, comprehensive documentation, and troubleshooting guides
5. **Scalability**: Profile-based deployment and modular service architecture
### Next Steps
1. **Deploy optimized configuration** in development environment
2. **Validate all security measures** are properly implemented
3. **Monitor performance metrics** and adjust resource limits as needed
4. **Implement backup and recovery procedures** for persistent data
5. **Set up automated monitoring and alerting** for production deployment
For questions or issues with the optimized configuration, refer to the troubleshooting section or consult the detailed configuration comments in the docker-compose files.
+65 -65
View File
@@ -45,7 +45,7 @@ services:
# depends_on removed for standalone client deployment
# When using multi-file setup, api-gateway dependency is handled externally
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:4000/health"]
test: [ "CMD", "curl", "--fail", "http://localhost:4000/health" ]
interval: 30s
timeout: 10s
retries: 3
@@ -59,82 +59,82 @@ services:
# ===================================================================
# Desktop Application (Kotlin Desktop + VNC)
# ===================================================================
# desktop-app:
# build:
# context: .
# dockerfile: dockerfiles/clients/desktop-app/Dockerfile
# container_name: meldestelle-desktop-app
# 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
# DISPLAY: ":99"
# VNC_PORT: "5901"
# NOVNC_PORT: "6080"
# # App Information
# APP_TITLE: ${APP_NAME:-Meldestelle}
# APP_VERSION: ${APP_VERSION:-1.0.0}
# ports:
# - "6080:6080" # Web-based VNC (noVNC)
# - "5901:5901" # VNC direct access
# networks:
# - meldestelle-network
# # depends_on removed for standalone client deployment
# # When using multi-file setup, api-gateway dependency is handled externally
# healthcheck:
# test: [ "CMD", "/opt/health-check.sh" ]
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 60s
# restart: unless-stopped
# labels:
# - "traefik.enable=true"
# - "traefik.http.routers.desktop-app.rule=Host(`localhost`) && PathPrefix(`/desktop`)"
# - "traefik.http.services.desktop-app.loadbalancer.server.port=6080"
# ===================================================================
# Auth Server (Custom Keycloak Extension)
# ===================================================================
# auth-server:
# desktop-app:
# build:
# context: .
# dockerfile: dockerfiles/infrastructure/auth-server/Dockerfile
# args:
# # Global build arguments (from docker/build-args/global.env)
# GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.0.0}
# JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
# BUILD_DATE: ${BUILD_DATE}
# VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# # Infrastructure-specific arguments (from docker/build-args/infrastructure.env)
# SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT:-default}
# container_name: meldestelle-auth-server
# dockerfile: dockerfiles/clients/desktop-app/Dockerfile
# container_name: meldestelle-desktop-app
# environment:
# SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
# SERVER_PORT: ${AUTH_SERVICE_PORT:-8087}
# KEYCLOAK_SERVER_URL: http://keycloak:8080
# KEYCLOAK_REALM: meldestelle
# KEYCLOAK_CLIENT_ID: meldestelle-auth-service
# KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET:-auth-service-secret}
# DB_HOST: postgres
# DB_PORT: 5432
# DB_NAME: ${POSTGRES_DB:-meldestelle}
# DB_USER: ${POSTGRES_USER:-meldestelle}
# DB_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle}
# JWT_SECRET: ${JWT_SECRET:-meldestelle-jwt-secret-key-for-development-change-in-production}
# JWT_ISSUER: ${JWT_ISSUER:-meldestelle-api}
# JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-clients}
# # 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
# DISPLAY: ":99"
# VNC_PORT: "5901"
# NOVNC_PORT: "6080"
# # App Information
# APP_TITLE: ${APP_NAME:-Meldestelle}
# APP_VERSION: ${APP_VERSION:-1.0.0}
# ports:
# - "${AUTH_SERVICE_PORT:-8087}:${AUTH_SERVICE_PORT:-8087}"
# - "6080:6080" # Web-based VNC (noVNC)
# - "5901:5901" # VNC direct access
# networks:
# - meldestelle-network
# # depends_on removed for standalone client deployment
# # When using multi-file setup, api-gateway dependency is handled externally
# healthcheck:
# test: ["CMD", "curl", "--fail", "http://localhost:${AUTH_SERVICE_PORT:-8087}/actuator/health"]
# test: [ "CMD", "/opt/health-check.sh" ]
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 60s
# restart: unless-stopped
# labels:
# - "traefik.enable=true"
# - "traefik.http.routers.desktop-app.rule=Host(`localhost`) && PathPrefix(`/desktop`)"
# - "traefik.http.services.desktop-app.loadbalancer.server.port=6080"
# ===================================================================
# Auth Server (Custom Keycloak Extension)
# ===================================================================
# auth-server:
# build:
# context: .
# dockerfile: dockerfiles/infrastructure/auth-server/Dockerfile
# args:
# # Global build arguments (from docker/build-args/global.env)
# GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.0.0}
# JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
# BUILD_DATE: ${BUILD_DATE}
# VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# # Infrastructure-specific arguments (from docker/build-args/infrastructure.env)
# SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT:-default}
# container_name: meldestelle-auth-server
# environment:
# SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev}
# SERVER_PORT: ${AUTH_SERVICE_PORT:-8087}
# KEYCLOAK_SERVER_URL: http://keycloak:8080
# KEYCLOAK_REALM: meldestelle
# KEYCLOAK_CLIENT_ID: meldestelle-auth-service
# KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET:-auth-service-secret}
# DB_HOST: postgres
# DB_PORT: 5432
# DB_NAME: ${POSTGRES_DB:-meldestelle}
# DB_USER: ${POSTGRES_USER:-meldestelle}
# DB_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle}
# JWT_SECRET: ${JWT_SECRET:-meldestelle-jwt-secret-key-for-development-change-in-production}
# JWT_ISSUER: ${JWT_ISSUER:-meldestelle-api}
# JWT_AUDIENCE: ${JWT_AUDIENCE:-meldestelle-clients}
# ports:
# - "${AUTH_SERVICE_PORT:-8087}:${AUTH_SERVICE_PORT:-8087}"
# networks:
# - meldestelle-network
# healthcheck:
# test: [ "CMD", "curl", "--fail", "http://localhost:${AUTH_SERVICE_PORT:-8087}/actuator/health" ]
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 60s
# restart: unless-stopped
# ===================================================================
# Monitoring Server (Custom Grafana Extensions)
+353
View File
@@ -0,0 +1,353 @@
# ===================================================================
# 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:
- BUILD_DATE=${BUILD_DATE:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}
- VERSION=${APP_VERSION:-1.0.0}
- NODE_ENV=${NODE_ENV:-production}
container_name: meldestelle-web-app
environment:
NODE_ENV: ${NODE_ENV:-production}
APP_TITLE: ${APP_NAME:-Meldestelle}
APP_VERSION: ${APP_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=${APP_VERSION:-1.0.0}
container_name: meldestelle-desktop-app
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:-9.0.0}
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:-9.0.0}
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
+430
View File
@@ -0,0 +1,430 @@
# ===================================================================
# 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
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.0.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
# Service-specific arguments
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER:-docker}
container_name: meldestelle-ping-service
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:
- 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:-9.0.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER:-docker}
container_name: meldestelle-members-service
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:-9.0.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER:-docker}
container_name: meldestelle-horses-service
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:-9.0.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER:-docker}
container_name: meldestelle-events-service
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:-9.0.0}
JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21}
BUILD_DATE: ${BUILD_DATE:-unknown}
VERSION: ${DOCKER_APP_VERSION:-1.0.0}
SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER:-docker}
container_name: meldestelle-masterdata-service
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
+522
View File
@@ -0,0 +1,522 @@
# ===================================================================
# 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: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: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.0}
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: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: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: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
GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.0.0}
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-api-gateway
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:
- 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 @@
TiB6FRRYW4gjM7xie17mKtTYFOp
+1
View File
@@ -0,0 +1 @@
admin
+1
View File
@@ -0,0 +1 @@
ba960b899f72d5ed192b5597d7f4b5b8853d9d641a2dc23c6b1a4b692b20211c
@@ -0,0 +1 @@
XASb7AzVy7G5fEKulE1mNPTy2Sw6pHi
@@ -0,0 +1 @@
s8N3r59JwS0lFsJobKWFJXh9qvdbHgcC6S3fYXYdXFM6eMKkRMtQbxHo0NJKFJC
@@ -0,0 +1 @@
lRo7W15UNy60EFRlvk1XP99MmgrgK2Z97QK9btl9ZPVIVzWcY81Bebp9hpB
+1
View File
@@ -0,0 +1 @@
pON4NxxsKPWseVg1gw5PyLNN4YYrj8h
+1
View File
@@ -0,0 +1 @@
metrics
+1
View File
@@ -0,0 +1 @@
pGnDFSiwacGxfKCtb8VJmTQc9Emlcdow
+1
View File
@@ -0,0 +1 @@
meldestelle
+1
View File
@@ -0,0 +1 @@
p701HhKOnZJ4zbY9dGRvyH9kQTKcsUm
+345
View File
@@ -0,0 +1,345 @@
#!/bin/bash
# ===================================================================
# Docker Secrets Setup Script - Meldestelle Project
# ===================================================================
# This script generates secure secrets for all Docker services
# Security Features:
# - Generates cryptographically secure random passwords
# - Creates JWT secrets with proper length for HMAC512
# - Sets appropriate file permissions (600) for security
# - Provides backup functionality
# - Validates secret file creation
# ===================================================================
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SECRETS_DIR="${SCRIPT_DIR}"
# Logging function
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
warn() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
error() {
echo -e "${RED}[ERROR] $1${NC}"
exit 1
}
# Function to generate secure random password
generate_password() {
local length=${1:-32}
openssl rand -base64 $((length * 3 / 4)) | tr -d "=+/" | cut -c1-${length}
}
# Function to generate JWT secret (64 characters for HMAC512)
generate_jwt_secret() {
openssl rand -hex 32
}
# Function to create secret file with proper permissions
create_secret_file() {
local filename="$1"
local content="$2"
local filepath="${SECRETS_DIR}/${filename}"
# Check if file already exists
if [[ -f "$filepath" ]]; then
warn "Secret file $filename already exists. Use --force to overwrite."
return 1
fi
# Create the secret file
echo -n "$content" > "$filepath"
chmod 600 "$filepath"
log "Created secret file: $filename"
return 0
}
# Function to backup existing secrets
backup_secrets() {
local backup_dir="${SECRETS_DIR}/backup_$(date +%Y%m%d_%H%M%S)"
if find "$SECRETS_DIR" -name "*.txt" -type f | grep -q .; then
log "Creating backup of existing secrets..."
mkdir -p "$backup_dir"
find "$SECRETS_DIR" -name "*.txt" -type f -exec cp {} "$backup_dir/" \;
log "Backup created in: $backup_dir"
fi
}
# Function to validate secret file
validate_secret_file() {
local filepath="$1"
local min_length="$2"
if [[ ! -f "$filepath" ]]; then
error "Secret file does not exist: $filepath"
fi
local content_length=$(wc -c < "$filepath")
if [[ $content_length -lt $min_length ]]; then
error "Secret file $filepath is too short (${content_length} < ${min_length})"
fi
local permissions=$(stat -c %a "$filepath")
if [[ "$permissions" != "600" ]]; then
warn "Secret file $filepath has incorrect permissions: $permissions (should be 600)"
chmod 600 "$filepath"
fi
}
# Function to generate all secrets
generate_all_secrets() {
local force_overwrite=${1:-false}
log "Starting secret generation for Meldestelle Docker infrastructure..."
# Create backup if not forcing overwrite
if [[ "$force_overwrite" != "true" ]]; then
backup_secrets
fi
# Database secrets
log "Generating database secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_user.txt" ]]; then
create_secret_file "postgres_user.txt" "meldestelle"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_password.txt" ]]; then
create_secret_file "postgres_password.txt" "$(generate_password 32)"
fi
# Redis secrets
log "Generating Redis secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/redis_password.txt" ]]; then
create_secret_file "redis_password.txt" "$(generate_password 32)"
fi
# Keycloak secrets
log "Generating Keycloak secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_admin_password.txt" ]]; then
create_secret_file "keycloak_admin_password.txt" "$(generate_password 32)"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_client_secret.txt" ]]; then
create_secret_file "keycloak_client_secret.txt" "$(generate_password 64)"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_auth_client_secret.txt" ]]; then
create_secret_file "keycloak_auth_client_secret.txt" "$(generate_password 64)"
fi
# Grafana secrets
log "Generating Grafana secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_user.txt" ]]; then
create_secret_file "grafana_admin_user.txt" "admin"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_password.txt" ]]; then
create_secret_file "grafana_admin_password.txt" "$(generate_password 32)"
fi
# JWT secrets
log "Generating JWT secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/jwt_secret.txt" ]]; then
create_secret_file "jwt_secret.txt" "$(generate_jwt_secret)"
fi
# VNC secrets (for desktop app)
log "Generating VNC secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/vnc_password.txt" ]]; then
create_secret_file "vnc_password.txt" "$(generate_password 16)"
fi
# Monitoring secrets
log "Generating monitoring secrets..."
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_username.txt" ]]; then
create_secret_file "metrics_auth_username.txt" "metrics"
fi
if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_password.txt" ]]; then
create_secret_file "metrics_auth_password.txt" "$(generate_password 32)"
fi
log "Secret generation completed successfully!"
}
# Function to validate all secrets
validate_all_secrets() {
log "Validating all secret files..."
# Define expected secrets with minimum lengths
declare -A secrets=(
["postgres_user.txt"]=8
["postgres_password.txt"]=16
["redis_password.txt"]=16
["keycloak_admin_password.txt"]=16
["keycloak_client_secret.txt"]=32
["keycloak_auth_client_secret.txt"]=32
["grafana_admin_user.txt"]=4
["grafana_admin_password.txt"]=16
["jwt_secret.txt"]=64
["vnc_password.txt"]=8
["metrics_auth_username.txt"]=4
["metrics_auth_password.txt"]=16
)
local all_valid=true
for secret_file in "${!secrets[@]}"; do
local filepath="${SECRETS_DIR}/${secret_file}"
local min_length=${secrets[$secret_file]}
if validate_secret_file "$filepath" "$min_length" 2>/dev/null; then
log "$secret_file is valid"
else
error "$secret_file is invalid or missing"
all_valid=false
fi
done
if [[ "$all_valid" == "true" ]]; then
log "All secret files are valid and properly secured!"
else
error "Some secret files are invalid. Please regenerate secrets."
fi
}
# Function to create Docker secrets
create_docker_secrets() {
log "Creating Docker secrets..."
# Get the project name (directory name)
local project_name=$(basename "$(dirname "$(dirname "$SCRIPT_DIR")")")
# Define secrets to create
declare -A docker_secrets=(
["postgres_user"]="postgres_user.txt"
["postgres_password"]="postgres_password.txt"
["redis_password"]="redis_password.txt"
["keycloak_admin_password"]="keycloak_admin_password.txt"
["keycloak_client_secret"]="keycloak_client_secret.txt"
["grafana_admin_user"]="grafana_admin_user.txt"
["grafana_admin_password"]="grafana_admin_password.txt"
["jwt_secret"]="jwt_secret.txt"
)
for secret_name in "${!docker_secrets[@]}"; do
local secret_file="${docker_secrets[$secret_name]}"
local filepath="${SECRETS_DIR}/${secret_file}"
local docker_secret_name="${project_name}_${secret_name}"
# Check if Docker secret already exists
if docker secret ls --format "{{.Name}}" | grep -q "^${docker_secret_name}$"; then
warn "Docker secret $docker_secret_name already exists"
else
# Create Docker secret
if docker secret create "$docker_secret_name" "$filepath"; then
log "Created Docker secret: $docker_secret_name"
else
error "Failed to create Docker secret: $docker_secret_name"
fi
fi
done
}
# Function to show usage
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --help Show this help message"
echo " --generate Generate all secret files (default)"
echo " --force Force overwrite existing secret files"
echo " --validate Validate existing secret files"
echo " --docker-secrets Create Docker secrets from files"
echo " --all Generate files, validate, and create Docker secrets"
echo ""
echo "Examples:"
echo " $0 # Generate secrets (skip existing files)"
echo " $0 --force # Generate secrets (overwrite existing files)"
echo " $0 --validate # Validate existing secret files"
echo " $0 --all # Complete setup (generate, validate, docker secrets)"
}
# Main execution
main() {
local action="generate"
local force_overwrite=false
# Check dependencies
if ! command -v openssl &> /dev/null; then
error "openssl is required but not installed"
fi
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help)
show_usage
exit 0
;;
--generate)
action="generate"
shift
;;
--force)
force_overwrite=true
shift
;;
--validate)
action="validate"
shift
;;
--docker-secrets)
action="docker-secrets"
shift
;;
--all)
action="all"
shift
;;
*)
error "Unknown option: $1"
;;
esac
done
# Ensure secrets directory exists
mkdir -p "$SECRETS_DIR"
# Execute requested action
case $action in
"generate")
generate_all_secrets "$force_overwrite"
;;
"validate")
validate_all_secrets
;;
"docker-secrets")
create_docker_secrets
;;
"all")
generate_all_secrets "$force_overwrite"
validate_all_secrets
create_docker_secrets
;;
*)
error "Invalid action: $action"
;;
esac
log "Operation completed successfully!"
}
# Run main function with all arguments
main "$@"
+1
View File
@@ -0,0 +1 @@
nrscAXfIoOKTAEt
@@ -0,0 +1,294 @@
{
"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"
}
}
+27
View File
@@ -0,0 +1,27 @@
2025-10-05 21:49:40.525 [background-preinit] INFO [] o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2025-10-05 21:49:40.564 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Starting GatewayApplicationKt using Java 21.0.8 with PID 783949 (/home/stefan-mo/WsMeldestelle/Meldestelle/infrastructure/gateway/build/classes/kotlin/main started by stefan-mo in /home/stefan-mo/WsMeldestelle/Meldestelle)
2025-10-05 21:49:40.565 [main] DEBUG [] a.m.i.gateway.GatewayApplicationKt - Running with Spring Boot v3.5.5, Spring v6.2.10
2025-10-05 21:49:40.565 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - The following 1 profile is active: "dev"
2025-10-05 21:49:41.913 [main] INFO [] o.s.cloud.context.scope.GenericScope - BeanFactory id=548af07a-4d4c-30b3-8388-eaf5c0d95d23
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [After]
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Before]
2025-10-05 21:49:44.188 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Between]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Cookie]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Header]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Host]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Method]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Path]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Query]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [ReadBody]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [RemoteAddr]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [XForwardedRemoteAddr]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [Weight]
2025-10-05 21:49:44.189 [main] INFO [] o.s.c.g.r.RouteDefinitionRouteLocator - Loaded RoutePredicateFactory [CloudFoundryRouteService]
2025-10-05 21:49:44.880 [main] INFO [] o.s.b.a.e.web.EndpointLinksResolver - Exposing 6 endpoints beneath base path '/actuator'
2025-10-05 21:49:45.585 [main] WARN [] o.s.c.l.c.LoadBalancerCacheAutoConfiguration$LoadBalancerCaffeineWarnLogger - Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2025-10-05 21:49:45.714 [main] INFO [] o.s.b.w.e.netty.NettyWebServer - Netty started on port 8080 (http)
2025-10-05 21:49:45.716 [main] INFO [] o.s.c.c.s.ConsulServiceRegistry - Registering service with consul: NewService{id='meldestelle-8080-2567c504-f48c-4f6e-918e-23b80c37675e', name='meldestelle', tags=[], address='10.0.0.18', meta={secure=false}, port=8080, enableTagOverride=null, check=Check{script='null', dockerContainerID='null', shell='null', interval='10s', ttl='null', http='http://10.0.0.18:8080/actuator/health', method='null', header={}, tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null', grpc='null', grpcUseTLS=null}, checks=null}
2025-10-05 21:49:45.865 [main] INFO [] a.m.i.gateway.GatewayApplicationKt - Started GatewayApplicationKt in 5.753 seconds (process running for 6.365)
2025-10-05 21:53:53.365 [SpringApplicationShutdownHook] INFO [] o.s.b.w.e.netty.GracefulShutdown - Commencing graceful shutdown. Waiting for active requests to complete
2025-10-05 21:53:53.367 [netty-shutdown] INFO [] o.s.b.w.e.netty.GracefulShutdown - Graceful shutdown complete
2025-10-05 21:53:55.378 [SpringApplicationShutdownHook] INFO [] o.s.c.c.s.ConsulServiceRegistry - Deregistering service with consul: meldestelle-8080-2567c504-f48c-4f6e-918e-23b80c37675e
+371
View File
@@ -0,0 +1,371 @@
# docker compose config output
name: meldestelle
services:
api-gateway:
build:
context: /home/stefan-mo/WsMeldestelle/Meldestelle
dockerfile: dockerfiles/infrastructure/gateway/Dockerfile
args:
BUILD_DATE: unknown
GRADLE_VERSION: 9.0.0
JAVA_VERSION: "21"
SPRING_PROFILES_ACTIVE: default
VERSION: 1.0.0
container_name: meldestelle-api-gateway
depends_on:
consul:
condition: service_healthy
required: true
keycloak:
condition: service_healthy
required: true
postgres:
condition: service_healthy
required: true
redis:
condition: service_healthy
required: true
environment:
CONSUL_ENABLED: "true"
CONSUL_HOST: consul
CONSUL_PORT: "8500"
GATEWAY_PORT: "8081"
GATEWAY_SECURITY_KEYCLOAK_ENABLED: "false"
KEYCLOAK_CLIENT_ID: api-gateway
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_SERVER_URL: http://keycloak:8080
SPRING_PROFILES_ACTIVE: dev,keycloak
healthcheck:
test:
- CMD
- curl
- --fail
- http://localhost:8081/actuator/health
timeout: 5s
interval: 15s
retries: 3
start_period: 30s
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 8081
published: "8081"
protocol: tcp
restart: unless-stopped
volumes:
- type: volume
source: api-gateway-gradle-cache
target: /home/gradle/.gradle
volume: {}
consul:
command:
- agent
- -server
- -ui
- -node=server-1
- -bootstrap-expect=1
- -client=0.0.0.0
container_name: meldestelle-consul
healthcheck:
test:
- CMD
- curl
- -f
- http://localhost:8500/v1/status/leader
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: hashicorp/consul:1.15
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 8500
published: "8500"
protocol: tcp
restart: unless-stopped
grafana:
container_name: meldestelle-grafana
depends_on:
prometheus:
condition: service_started
required: true
environment:
GF_INSTALL_PLUGINS: grafana-piechart-panel
GF_SECURITY_ADMIN_PASSWORD: admin
GF_SECURITY_ADMIN_USER: admin
GF_USERS_ALLOW_SIGN_UP: "false"
healthcheck:
test:
- CMD
- curl
- --fail
- http://localhost:3000/api/health
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: grafana/grafana:11.3.0
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 3000
published: "3000"
protocol: tcp
restart: unless-stopped
volumes:
- type: volume
source: grafana-data
target: /var/lib/grafana
volume: {}
- type: bind
source: /home/stefan-mo/WsMeldestelle/Meldestelle/docker/monitoring/grafana
target: /etc/grafana/provisioning
read_only: true
bind:
create_host_path: true
kafka:
container_name: meldestelle-kafka
depends_on:
zookeeper:
condition: service_healthy
required: true
environment:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_BROKER_ID: "1"
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1"
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
healthcheck:
test:
- CMD
- kafka-broker-api-versions
- --bootstrap-server
- localhost:9092
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: confluentinc/cp-kafka:7.4.0
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 9092
published: "9092"
protocol: tcp
restart: unless-stopped
keycloak:
command:
- start-dev
- --import-realm
container_name: meldestelle-keycloak
depends_on:
postgres:
condition: service_healthy
required: true
environment:
JAVA_OPTS_APPEND: -XX:MaxRAMPercentage=75.0 -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+DisableExplicitGC -Djava.net.preferIPv4Stack=true -Duser.timezone=Europe/Vienna
KC_CACHE: ispn
KC_DB: postgres
KC_DB_PASSWORD: meldestelle
KC_DB_POOL_INITIAL_SIZE: "5"
KC_DB_POOL_MAX_SIZE: "20"
KC_DB_POOL_MIN_SIZE: "5"
KC_DB_SCHEMA: keycloak
KC_DB_URL: jdbc:postgresql://postgres:5432/meldestelle
KC_DB_USERNAME: meldestelle
KC_HEALTH_ENABLED: "true"
KC_HOSTNAME_STRICT: "false"
KC_HTTP_ENABLED: "true"
KC_HTTP_PORT: "8080"
KC_LOG_CONSOLE_COLOR: "false"
KC_LOG_CONSOLE_FORMAT: plain
KC_LOG_LEVEL: info
KC_METRICS_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
healthcheck:
test:
- CMD-SHELL
- 'if command -v curl >/dev/null 2>&1; then curl -fsS http://localhost:8080/health/ready | grep -q "\"status\":\"UP\""; elif command -v wget >/dev/null 2>&1; then wget -q -O - http://localhost:8080/health/ready | grep -q "\"status\":\"UP\""; else echo "Healthcheck: curl/wget not found, using bash /dev/tcp fallback" >&2; timeout 25 bash -lc "exec 3<>/dev/tcp/127.0.0.1/8080 && printf \"GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" >&3 && head -n 1 <&3 | grep -q \"200 OK\""; fi'
timeout: 30s
interval: 15s
retries: 10
start_period: 3m0s
image: quay.io/keycloak/keycloak:26.4.0
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 8080
published: "8180"
protocol: tcp
restart: unless-stopped
volumes:
- type: bind
source: /home/stefan-mo/WsMeldestelle/Meldestelle/docker/services/keycloak
target: /opt/keycloak/data/import
bind:
create_host_path: true
- type: volume
source: keycloak-data
target: /opt/keycloak/data
volume: {}
postgres:
container_name: meldestelle-postgres
environment:
POSTGRES_DB: meldestelle
POSTGRES_PASSWORD: meldestelle
POSTGRES_USER: meldestelle
healthcheck:
test:
- CMD-SHELL
- pg_isready -U meldestelle -d meldestelle
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: postgres:16-alpine
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 5432
published: "5432"
protocol: tcp
restart: unless-stopped
volumes:
- type: volume
source: postgres-data
target: /var/lib/postgresql/data
volume: {}
- type: bind
source: /home/stefan-mo/WsMeldestelle/Meldestelle/docker/services/postgres
target: /docker-entrypoint-initdb.d
bind:
create_host_path: true
prometheus:
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=200h
- --web.enable-lifecycle
container_name: meldestelle-prometheus
healthcheck:
test:
- CMD
- wget
- --no-verbose
- --tries=1
- --spider
- http://localhost:9090/-/healthy
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: prom/prometheus:v2.54.1
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 9090
published: "9090"
protocol: tcp
restart: unless-stopped
volumes:
- type: volume
source: prometheus-data
target: /prometheus
volume: {}
- type: bind
source: /home/stefan-mo/WsMeldestelle/Meldestelle/docker/monitoring/prometheus
target: /etc/prometheus
read_only: true
bind:
create_host_path: true
redis:
command:
- redis-server
- --appendonly
- "yes"
container_name: meldestelle-redis
healthcheck:
test:
- CMD
- redis-cli
- ping
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: redis:7-alpine
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 6379
published: "6379"
protocol: tcp
restart: unless-stopped
volumes:
- type: volume
source: redis-data
target: /data
volume: {}
zookeeper:
container_name: meldestelle-zookeeper
environment:
ZOOKEEPER_CLIENT_PORT: "2181"
ZOOKEEPER_TICK_TIME: "2000"
healthcheck:
test:
- CMD
- bash
- -c
- echo 'ruok' | nc localhost 2181
timeout: 5s
interval: 10s
retries: 3
start_period: 20s
image: confluentinc/cp-zookeeper:7.4.0
networks:
meldestelle-network: null
ports:
- mode: ingress
target: 2181
published: "2181"
protocol: tcp
restart: unless-stopped
networks:
meldestelle-network:
name: meldestelle_meldestelle-network
driver: bridge
volumes:
api-gateway-gradle-cache:
name: meldestelle_api-gateway-gradle-cache
driver: local
grafana-data:
name: meldestelle_grafana-data
driver: local
keycloak-data:
name: meldestelle_keycloak-data
driver: local
postgres-data:
name: meldestelle_postgres-data
driver: local
prometheus-data:
name: meldestelle_prometheus-data
driver: local
redis-data:
name: meldestelle_redis-data
driver: local
@@ -0,0 +1,2 @@
# docker compose config output
open /home/stefan-mo/WsMeldestelle/Meldestelle/scripts/troubleshooting/docker-compose.yml: no such file or directory
@@ -0,0 +1,34 @@
package at.mocode.members.service.config
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.web.SecurityFilterChain
/**
* Security configuration for the Members Service.
* Enables method-level security for fine-grained authorization control.
*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
class SecurityConfiguration {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
return http
.csrf { it.disable() }
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
.authorizeHttpRequests { auth ->
auth
// Allow health check endpoints
.requestMatchers("/actuator/**", "/health/**").permitAll()
// All other endpoints require authentication (handled by method-level security)
.anyRequest().authenticated()
}
.build()
}
}