7.0 KiB
7.0 KiB
Sicherheit
Sicherheitsrisiken und Gegenmassnahmen fuer den Container Spawner.
Inhaltsverzeichnis
- Docker Socket Risiko
- Container Isolation
- Session-Sicherheit
- Input-Validierung
- Secrets Management
- Netzwerksicherheit
- Sicherheits-Checkliste
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)
.envnicht 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
- Spawner stoppen:
docker-compose down - Alle User-Container stoppen:
docker stop $(docker ps -q --filter 'label=spawner.managed=true') - Logs sichern:
docker-compose logs > incident-logs.txt - Secrets rotieren: Neue SECRET_KEY generieren
- Analyse durchfuehren
- Behobene Version deployen
Kontakt
Bei Sicherheitsproblemen: Issue im Repository erstellen (privat falls sensibel)
Zurueck zur Dokumentations-Uebersicht