# 🐳 Docker Security Hardening — DAARION **Версія:** 1.0.0 **Принцип:** Майнінг можливий тільки там, де дозволений **outbound + CPU без контролю** --- ## 📋 Security Checklist ### Must-Have (Обов'язково) | Налаштування | docker-compose | Пояснення | |--------------|----------------|-----------| | Read-only filesystem | `read_only: true` | Запобігає запису malware | | Drop capabilities | `cap_drop: [ALL]` | Мінімальні привілеї | | No new privileges | `security_opt: [no-new-privileges:true]` | Блокує privilege escalation | | CPU limit | `cpus: '1.0'` | Обмежує crypto mining | | Memory limit | `memory: 512M` | Запобігає DoS | | Non-root user | `user: "1001:1001"` | Не root в контейнері | | No privileged | `privileged: false` | Завжди! | --- ## 🛡️ Secure docker-compose Template ```yaml version: '3.8' services: secure-service: image: your-image:tag container_name: secure-service # ============================================ # SECURITY HARDENING # ============================================ # 1. Restart policy (use "no" until verified) restart: "no" # Change to "unless-stopped" after verification # 2. Network binding (localhost only for internal services) ports: - "127.0.0.1:8080:8080" # 3. Read-only root filesystem read_only: true # 4. Temporary filesystems (for apps that need write) tmpfs: - /tmp:size=64M,mode=1777 - /app/cache:size=128M,mode=1777 # 5. Drop ALL capabilities cap_drop: - ALL # 6. Add only what's needed (rarely needed) # cap_add: # - NET_BIND_SERVICE # Only if port < 1024 # 7. Security options security_opt: - no-new-privileges:true # 8. Resource limits deploy: resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.25' memory: 128M # 9. Process limits pids_limit: 100 # 10. Disable privileged mode privileged: false # 11. Non-root user user: "1001:1001" # 12. Health check healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s # 13. Logging limits logging: driver: "json-file" options: max-size: "10m" max-file: "3" # 14. Labels for audit labels: - "security.hardened=true" - "security.reviewed=2026-01-09" networks: default: driver: bridge driver_opts: com.docker.network.bridge.enable_icc: "false" # Disable inter-container communication ``` --- ## 🔧 Secure Dockerfile Template ```dockerfile # ============================================ # Stage 1: Builder # ============================================ FROM node:20-alpine AS builder WORKDIR /app # Copy only package files first (cache optimization) COPY package*.json ./ RUN npm ci --only=production --ignore-scripts COPY . . RUN npm run build # ============================================ # Stage 2: Production (minimal) # ============================================ FROM node:20-alpine AS production # Security: Create non-root user RUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup WORKDIR /app # Security: Remove unnecessary tools RUN apk del --purge wget curl busybox-extras && \ rm -rf /var/cache/apk/* /tmp/* /var/tmp/* # Copy from builder COPY --from=builder --chown=appuser:appgroup /app/dist ./dist COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules COPY --from=builder --chown=appuser:appgroup /app/package.json ./ # Security: Restrictive permissions RUN chmod -R 500 /app && \ chmod 400 /app/package.json # Switch to non-root USER appuser # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ CMD node -e "require('http').get('http://localhost:8080/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))" EXPOSE 8080 CMD ["node", "dist/server.js"] ``` --- ## 🚫 Anti-Patterns (НЕ робіть) ```yaml # ❌ NEVER DO THIS: services: insecure: privileged: true # ❌ Full host access ports: - "8080:8080" # ❌ Binds to 0.0.0.0 (public) volumes: - /:/host # ❌ Full host filesystem - /var/run/docker.sock:/var/run/docker.sock # ❌ Docker escape cap_add: - SYS_ADMIN # ❌ Too powerful - NET_ADMIN # ❌ Network manipulation restart: unless-stopped # ❌ Without verification # No resource limits # ❌ Crypto mining possible # No read_only # ❌ Malware can persist # No user specification # ❌ Runs as root ``` --- ## 📊 Security Scanning ### Pre-deployment scan ```bash # Install Trivy brew install trivy # macOS apt install trivy # Ubuntu # Scan image for vulnerabilities trivy image --severity HIGH,CRITICAL your-image:tag # Scan with detailed output trivy image --format json -o scan-report.json your-image:tag # Scan Dockerfile trivy config Dockerfile ``` ### CI/CD Integration ```yaml # .github/workflows/security-scan.yml name: Security Scan on: [push, pull_request] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build image run: docker build -t app:${{ github.sha }} . - name: Run Trivy scan uses: aquasecurity/trivy-action@master with: image-ref: 'app:${{ github.sha }}' format: 'table' exit-code: '1' severity: 'HIGH,CRITICAL' ``` --- ## 🔍 Runtime Monitoring ### Container inspection ```bash # Check container security settings docker inspect --format=' Privileged: {{.HostConfig.Privileged}} ReadonlyRootfs: {{.HostConfig.ReadonlyRootfs}} User: {{.Config.User}} CapDrop: {{.HostConfig.CapDrop}} CapAdd: {{.HostConfig.CapAdd}} ' container_name ``` ### Resource monitoring ```bash # Real-time stats docker stats container_name # CPU limit check docker inspect --format='{{.HostConfig.NanoCpus}}' container_name # Memory limit check docker inspect --format='{{.HostConfig.Memory}}' container_name ``` --- ## 📝 DAARION-specific Rules ### Services that MUST have hardening: | Service | Priority | Notes | |---------|----------|-------| | daarion-web | 🔴 Critical | Post-incident, see Dockerfile.secure | | dagi-gateway | 🔴 Critical | Public-facing | | dagi-router | 🟡 High | Core routing | | All others | 🟡 High | Apply baseline | ### Network rules: ```yaml # Internal services: bind to localhost ports: - "127.0.0.1:PORT:PORT" # Public services: use Nginx reverse proxy # Never expose directly to 0.0.0.0 ``` --- ## ✅ Verification Checklist Before deploying any container: - [ ] Image scanned with Trivy (no HIGH/CRITICAL) - [ ] `read_only: true` set - [ ] `cap_drop: [ALL]` set - [ ] `security_opt: [no-new-privileges:true]` set - [ ] CPU/memory limits set - [ ] Non-root user configured - [ ] Health check defined - [ ] Restart policy is "no" for new deployments - [ ] Port bound to 127.0.0.1 (unless public) - [ ] No privileged mode - [ ] No dangerous volume mounts