spawner/docs/security
2026-01-30 18:00:41 +01:00
..
README.md Initial project structure with documentation 2026-01-30 18:00:41 +01:00

Sicherheit

Sicherheitsrisiken und Gegenmassnahmen fuer den Container Spawner.

Inhaltsverzeichnis


Docker Socket Risiko

Problem

Der Spawner benoetigt Zugriff auf /var/run/docker.sock um Container zu erstellen. Dies entspricht Root-Privilegien auf dem Host-System.

Risiken

  • Ein kompromittierter Spawner kann alle Container kontrollieren
  • Potenzieller Container-Escape moeglich
  • Zugriff auf Host-Dateisystem via Volume-Mounts

Gegenmassnahmen

Option 1: Docker Socket Proxy (Empfohlen fuer Produktion)

services:
  docker-proxy:
    image: tecnativa/docker-socket-proxy
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      CONTAINERS: 1    # Container-Operationen erlauben
      NETWORKS: 1      # Netzwerk-Operationen erlauben
      SERVICES: 0      # Swarm-Services blockieren
      SWARM: 0         # Swarm-Operationen blockieren
      VOLUMES: 0       # Volume-Operationen blockieren
      IMAGES: 1        # Image-Operationen erlauben
    networks:
      - internal

  spawner:
    environment:
      DOCKER_HOST: tcp://docker-proxy:2375
    networks:
      - internal
      - web

networks:
  internal:
    internal: true  # Kein externer Zugriff

Option 2: Minimale Permissions

# User-Namespace aktivieren (in /etc/docker/daemon.json)
{
  "userns-remap": "default"
}

Container Isolation

Aktuelle Massnahmen

Massnahme Status Beschreibung
Memory-Limit Aktiv Standard 512m pro Container
CPU-Quota Aktiv Standard 0.5 CPU pro Container
Restart-Policy Aktiv unless-stopped
Network-Isolation Teilweise Alle im gleichen Traefik-Netzwerk

Empfehlungen

Read-Only Filesystem

# In container_manager.py
container = client.containers.run(
    read_only=True,
    tmpfs={'/tmp': 'size=100M,noexec'}
)

Security Options

container = client.containers.run(
    security_opt=['no-new-privileges:true'],
    cap_drop=['ALL'],
    cap_add=['NET_BIND_SERVICE']  # Nur wenn noetig
)

Separate Netzwerke pro User (Fuer hohe Isolation)

# Dediziertes Netzwerk pro User
user_network = f"user-{username}-network"
client.networks.create(user_network, driver='bridge', internal=True)

Session-Sicherheit

Aktuelle Konfiguration

SESSION_COOKIE_SECURE = True       # Nur HTTPS (Produktion)
SESSION_COOKIE_HTTPONLY = True     # Kein JavaScript-Zugriff
SESSION_COOKIE_SAMESITE = 'Lax'    # CSRF-Schutz
PERMANENT_SESSION_LIFETIME = 3600  # 1h Timeout

Empfehlungen

  • SECRET_KEY: Mindestens 32 Bytes, zufaellig generiert
  • HTTPS erzwingen: Immer in Produktion
  • Session-Rotation: Nach Login neue Session-ID
# Session-Rotation nach Login
from flask import session
session.regenerate()

Input-Validierung

Aktuelle Risiken

  • Username wird direkt in Container-Namen verwendet
  • Minimale Validierung bei Registrierung

Empfohlene Validierung

import re

def validate_username(username):
    """Validiert Username gegen Injection-Angriffe"""
    if not username:
        return False, "Username erforderlich"

    if len(username) < 3 or len(username) > 20:
        return False, "Username muss 3-20 Zeichen lang sein"

    if not re.match(r'^[a-zA-Z0-9_]+$', username):
        return False, "Nur Buchstaben, Zahlen und Unterstriche erlaubt"

    # Reservierte Namen
    reserved = ['admin', 'root', 'system', 'spawner', 'traefik']
    if username.lower() in reserved:
        return False, "Dieser Username ist reserviert"

    return True, None

# Container-Name sicher erstellen
def safe_container_name(username, user_id):
    """Erstellt sicheren Container-Namen"""
    safe_name = re.sub(r'[^a-zA-Z0-9_-]', '', username)
    return f"user-{safe_name}-{user_id}"

Secrets Management

Entwicklung vs. Produktion

Umgebung Methode
Entwicklung .env Datei (nie committen!)
Produktion Docker Secrets oder Vault

Docker Secrets (Produktion)

# Secret erstellen
echo "supersecretkey" | docker secret create flask_secret -

# In docker-compose.yml
services:
  spawner:
    secrets:
      - flask_secret
    environment:
      SECRET_KEY_FILE: /run/secrets/flask_secret

secrets:
  flask_secret:
    external: true

Environment-Variable Sicherheit

# .env NIEMALS committen
echo ".env" >> .gitignore

# Sensible Werte nicht in Logs
LOG_LEVEL=INFO  # Nicht DEBUG in Produktion

Netzwerksicherheit

Traefik-Konfiguration

HTTPS erzwingen

# In container_manager.py Labels
labels={
    'traefik.http.routers.user{id}.entrypoints': 'websecure',
    'traefik.http.routers.user{id}.tls': 'true',
    'traefik.http.routers.user{id}.tls.certresolver': 'letsencrypt',

    # HTTP zu HTTPS Redirect
    'traefik.http.middlewares.redirect-https.redirectscheme.scheme': 'https',
    'traefik.http.routers.user{id}-http.middlewares': 'redirect-https'
}

Rate-Limiting via Traefik

labels={
    'traefik.http.middlewares.ratelimit.ratelimit.average': '100',
    'traefik.http.middlewares.ratelimit.ratelimit.burst': '50',
    'traefik.http.routers.spawner.middlewares': 'ratelimit'
}

Firewall-Empfehlungen

# Nur Traefik-Ports oeffentlich
ufw allow 80/tcp
ufw allow 443/tcp

# Docker-Socket NIE oeffentlich!
# Port 5000 nur intern (ueber Traefik)

Sicherheits-Checkliste

Vor Go-Live

  • SECRET_KEY generiert (32+ Bytes)
  • .env nicht im Repository
  • HTTPS konfiguriert und getestet
  • Docker Socket Proxy aktiviert (Produktion)
  • Resource-Limits angemessen
  • Input-Validierung implementiert
  • Rate-Limiting aktiv
  • Logs auf sensible Daten geprueft
  • Backup-Strategie implementiert

Regelmaessig pruefen

  • Container auf Vulnerabilities scannen
  • Dependencies aktualisieren
  • Logs auf verdaechtige Aktivitaeten pruefen
  • Unbefugte Container entfernen

Vulnerability Scanning

# Mit Trivy scannen
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    aquasec/trivy image spawner:latest

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    aquasec/trivy image user-service-template:latest

Incident Response

Bei Verdacht auf Kompromittierung

  1. Spawner stoppen: docker-compose down
  2. Alle User-Container stoppen: docker stop $(docker ps -q --filter 'label=spawner.managed=true')
  3. Logs sichern: docker-compose logs > incident-logs.txt
  4. Secrets rotieren: Neue SECRET_KEY generieren
  5. Analyse durchfuehren
  6. Behobene Version deployen

Kontakt

Bei Sicherheitsproblemen: Issue im Repository erstellen (privat falls sensibel)


Zurueck zur Dokumentations-Uebersicht