Files
microdao-daarion/security/hardening/docker.md
Apple cba2ff47f3 📚 docs(security): Add comprehensive Security chapter
## New Security Documentation Structure

/security/
├── README.md                    # Security overview & contacts
├── forensics-checklist.md       # Incident investigation guide
├── persistence-scan.sh          # Quick persistence detector
├── runtime-detector.sh          # Mining/suspicious process detector
└── hardening/
    ├── docker.md                # Docker security baseline
    ├── kubernetes.md            # K8s policies (future reference)
    └── cloud.md                 # Hetzner-specific hardening

## Key Components

### Forensics Checklist
- Process analysis commands
- Persistence mechanism detection
- Network connection analysis
- File system inspection
- Authentication audit
- Decision matrix for threat response

### Scripts
- persistence-scan.sh: Cron, systemd, executables, SSH keys
- runtime-detector.sh: Mining process detection with --kill option

### Hardening Guides
- Docker: Secure compose template, Dockerfile best practices
- Kubernetes: NetworkPolicy, PodSecurityStandard, Falco rules
- Cloud: Egress firewall, SSH hardening, fail2ban, monitoring

## Post-Incident Documentation
Based on lessons learned from Incidents #1 and #2 (Jan 2026)

Co-authored-by: Cursor Agent <agent@cursor.sh>
2026-01-09 02:08:13 -08:00

7.4 KiB
Raw Permalink Blame History

🐳 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

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

# ============================================
# 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 (НЕ робіть)

# ❌ 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

# 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

# .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

# 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

# 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:

# 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