Docker-Netzwerkisolation
Die Swiss AI Hub-Plattform implementiert Netzwerksegmentierung, um Sicherheitsgrenzen zwischen Services durchzusetzen. Dieser Defence-in-Depth-Ansatz begrenzt den Auswirkungsbereich potenzieller Sicherheitsverletzungen und erzwingt das Prinzip der geringsten Rechte auf der Netzwerkebene.
Netzwerkzonen
Die Plattform verwendet sieben isolierte Docker-Netzwerke:
| Netzwerk | Zweck | Externer Zugriff | ICC aktiviert |
|---|---|---|---|
proxy | Externer Traffic über Traefik | Ingress + Egress | Ja |
backend | Interne Anwendungs-Services | Nein | Ja |
data | Datenbanken und Message Broker | Nein | Ja |
storage | SeaweedFS Objekt-Speicher | Nein | Ja |
egress | Nur ausgehender Internetzugriff | Nur Egress | Nein |
code-sandbox | Code-Execution-Sandbox + ihre Caller | Nein | Ja |
browser | Playwright-Browser + seine Caller | Nein | Ja |
pii-detection | PII-Erkennung + ihre Caller | Nein | Ja |
Das egress-Netzwerk ist für Services konzipiert, die das Internet erreichen müssen (ausgehend), aber nicht aus dem Internet erreichbar sein sollten (kein Ingress). Die Inter-Container-Kommunikation (ICC) ist in diesem Netzwerk deaktiviert, was bedeutet, dass Container über dieses Netzwerk nicht miteinander kommunizieren können – sie können es nur für den ausgehenden Internetzugriff nutzen.
Das code-sandbox-Netzwerk ist eine Single-Tenant-Zone für die open-terminal Code-Execution-Sandbox, die beliebigen, von Benutzern übermittelten Code ausführt. Ihre Mitglieder sind die Sandbox plus genau ihre Caller (open-webui, universal-agent, der einzige AI-Hub Agent, der Code ausführt, und api, das die eigenen Dateien jedes Benutzers ausliefert). Da Docker-Netzwerke bidirektional sind, verhindert der Ausschluss der Sandbox aus backend, dass ein Sandbox-Breakout lateral litellm, vLLM, mineru, presidio, speaches oder otel-collector erreichen kann. ICC bleibt aktiviert (die Caller müssen open-terminal:8000 erreichen), und internal: true in Nicht-Dev-Stages verwehrt der Sandbox zusätzlich jeden ausgehenden Internetzugriff.
Das browser-Netzwerk wendet dasselbe Muster auf playwright an, den Headless-Browser, der die von Benutzern verlinkten Webseiten lädt (siehe Verlinkte Webseiten). Seine Mitglieder sind der Browser plus genau seine Caller: open-webui (dessen Web Loader) und die Agents, die verlinkte Seiten lesen. Die Agents prüfen jede URL, bevor der Browser sie lädt, aber der Browser löst den Namen erneut auf, sodass ein Name, der zuerst mit einer öffentlichen und dann mit einer internen Adresse antwortet (DNS-Rebinding), durchrutschen würde. Durch den Ausschluss des Browsers aus backend hat das Laden einer solchen Seite keinen Netzwerkpfad zu litellm, langfuse, mineru oder dem Docker-Socket-Proxy. Der Browser erreicht das Internet über egress.
Das pii-detection-Netzwerk enthält den presidio-analyzer, der die Personendaten erhält, die die Plattform anonymisiert, plus genau seine Caller (litellm und universal-agent). Seine Modelle sind im Image enthalten und der Hugging-Face-Hub ist zur Laufzeit offline, daher verwehrt internal: true in Nicht-Dev-Stages den ausgehenden Internetzugriff, ohne ihn zu beeinträchtigen. Jede Anfrage ausser dem Health-Check benötigt den API-Key des Analyzers.
Service-Netzwerkzuweisungen
Jeder Service wird nur den Netzwerken zugewiesen, die er für den Betrieb benötigt:
Proxy-Netzwerk-Services
Services, die von außerhalb des Docker-Netzwerks zugänglich sind:
- traefik: Reverse Proxy und API-Gateway
- api: REST API und WebSocket-Endpunkte
- web: Admin UI Frontend
- open-webui: Chat-Oberfläche
- bot: MS Teams/Slack-Integration
- seaweedfs-s3: S3-kompatible Speicher-API
- oauth2proxy-*: Authentifizierungs-Proxys
Backend-Netzwerk-Services
Interne Anwendungs- und Verarbeitungs-Services:
- litellm: LLM-Gateway und Request-Routing
- mineru-api: Dokumenten-Parsing und -Extraktion
- presidio-anonymizer: PII-Anonymisierung
- vLLM: Lokale LLM-Inferenz (Chat, Embedding, Reranking) – nur GPU Deployments
- speaches: Spracherkennung und Text-zu-Sprache
- agents: Alle Agent Workers (RAG, Expert, Wrapping)
- pipelines: Datenverarbeitungs-Pipelines
- dagster-*: Pipeline-Orchestrierung
- langfuse: KI-Observability
- otel-collector: Telemetrie-Aggregation
Daten-Netzwerk-Services
Persistenz- und Messaging-Infrastruktur:
- postgres: Primäre PostgreSQL-Datenbank
- pgbouncer: Connection Pooler für Dagster
- postgres-ferretdb: PostgreSQL-Backend für FerretDB
- ferretdb: MongoDB-kompatibler Dokumentenspeicher
- neo4j: Graphdatenbank für Mem0-Speicher
- milvus-standalone: Vektordatenbank
- etcd: Verteilter Key-Value-Speicher (Milvus-Metadaten)
- valkey: Redis-kompatibler In-Memory-Cache
- nats: Message Broker für ereignisgesteuerte Kommunikation
Speicher-Netzwerk-Services
Verteilter Objektspeicher-Cluster:
- seaweedfs-master: Cluster-Koordinator
- seaweedfs-volume: Datenspeicherknoten
- seaweedfs-filer: Dateisystem-Schnittstelle
- seaweedfs-s3: S3-API-Gateway
- etcd: Filer-Metadaten-Backend
Egress-Netzwerk-Services
Services, die ausgehenden Internetzugriff, aber keinen eingehenden Zugriff benötigen:
- playwright: Headless-Browser, der die von Benutzern verlinkten Webseiten lädt (muss Webseiten abrufen)
- searxng: Websuche (fragt externe Suchmaschinen ab)
- rclone: Der Daemon, den die rclone-Source-Pipeline steuert (erreicht den Cloud-Speicher, aus dem sie synchronisiert)
- structured_pipeline: Die Structured-Source-Pipeline (ruft APIs von Geschäftsanwendungen wie Jira auf)
- imap_agent, email_classification_agent: Lesen E-Mails auf externen IMAP-Servern und legen sie ab
- release_notes_agent: Liest die Tickets einer Fix-Version aus Jira Cloud oder einem On-Premise-Jira-Data-Center
- otel-collector: Exportiert Telemetrie an externe Backends
Dieses Netzwerk hat die ICC (Inter-Container Communication) deaktiviert, was die laterale Bewegung zwischen Containern in diesem Netzwerk verhindert. Services nutzen egress ausschließlich für den ausgehenden Internetzugriff und müssen andere Netzwerke (z.B. browser für playwright) für die Inter-Service-Kommunikation verwenden.
Code-Sandbox-Netzwerk-Services
Die Single-Tenant-Zone für die Code-Execution-Sandbox:
- open-terminal: Code-Execution-Sandbox für OpenWebUI (einfache LLM-Modelle; Home-Isolation pro Benutzer – siehe ADR
docs/arc42/decisions/2026_06_22_openwebui_code_execution_open_terminal.md)
Die Sandbox ist der einzige Bewohner; ihre Caller treten diesem Netzwerk zusätzlich zu ihren eigenen bei. open-webui ist an code-sandbox angebunden (neben proxy/backend/data/storage), damit es open-terminal:8000 erreichen kann, und universal-agent tritt ihm bei (neben backend/data/storage), um Code im Sandbox-Home des anfragenden Benutzers auszuführen, und api tritt ihm bei, um die eigenen Dateien jedes Benutzers von dort auszuliefern. Der sandbox-mirror-Sidecar, der die Homes nach S3 kopiert, liest das Homes-Volume und befindet sich ausschließlich in backend, nie in code-sandbox. Da die Sandbox ein Netzwerk nur mit ihren Callern teilt, hat ein Breakout keinen Netzwerkpfad zu den backend- oder data-Tiers. Im Dev-Stage verwendet open-webuinetwork_mode: host und die Agents laufen lokal außerhalb von Docker, sodass beide die Sandbox stattdessen über den veröffentlichten Port localhost:8200 erreichen.
Browser-Netzwerk-Services
Die Zone für den Headless-Browser:
- playwright: Lädt die von Benutzern verlinkten Webseiten für den Web Loader von Open WebUI und den Webseitenabruf der Agents (siehe ADR
docs/arc42/decisions/2026_10_20_agents_read_linked_web_pages_through_playwright.md)
Der Browser ist der einzige Bewohner; für das Internet befindet er sich außerdem in egress. Seine Caller treten browser zusätzlich zu ihren eigenen Netzwerken bei: open-webui und die Agents, die verlinkte Seiten lesen (llm-wrapping-agent, web-fetch-agent, rag-agent, expert-rag-agent und universal-agent). Ein neuer Agent, der Webseiten liest, muss ebenfalls beitreten, sonst kann er ws://playwright:3000 nicht erreichen. Im Dev-Stage erreichen Open WebUI und die Agents den Browser stattdessen über den veröffentlichten Port localhost:3036.
Netzwerk-Topologie
Sicherheitsimplikationen
Was jede Netzwerkgrenze schützt
Proxy → Backend-Grenze
- Externe Benutzer können nicht direkt auf interne Verarbeitungs-Services zugreifen
- Kompromittiertes Traefik kann Datenbanken nicht erreichen, ohne die API zu durchlaufen
Backend → Daten-Grenze
- Verarbeitungs-Services greifen über definierte Schnittstellen auf Datenbanken zu
- Kompromittierter KI-Service kann andere Datenbanken nicht direkt manipulieren
Daten → Speicher-Grenze
- Die interne Cluster-Kommunikation von SeaweedFS ist isoliert
- Datenbank-Services können Speicheroperationen nicht beeinträchtigen
- Der Filer hängt an
storageunddata(für etcd) und meldet dem Master deshalb seinen Service-Namen (-ip=seaweedfs-filer). Das S3-Gateway findet den Filer über den Master und erreicht keine Adresse imdata-Netz. - Auch das S3-Gateway registriert sich beim Master und hängt an
storageundbackend, daher meldet es auf die gleiche Weise seinen Service-Namen (-ip=seaweedfs-s3).
Service-Sichtbarkeitsmatrix
| Von \ Nach | proxy | backend | data | storage | egress | code-sandbox | browser | Internet |
|---|---|---|---|---|---|---|---|---|
| External | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | - |
| proxy | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ |
| backend | ✗ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
| data | ✗ | ✗ | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
| storage | ✗ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ | ✗ |
| egress | ✗ | ✗ | ✗ | ✗ | ✗* | ✗ | ✗ | ✓ |
| code-sandbox | ✗ | ✗ | ✗ | ✗ | ✗ | ✓** | ✗ | ✗*** |
| browser | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✓**** | ✗*** |
*ICC im Egress-Netzwerk deaktiviert – Container können über dieses Netzwerk nicht miteinander kommunizieren.
**Nur open-terminal und seine Caller (open-webui, universal-agent, api) befinden sich in code-sandbox, sodass die Sandbox ihre Caller, aber keinen anderen Tier erreichen kann.
***internal: true in Nicht-Dev-Stages blockiert ausgehenden Internetzugriff über dieses Netzwerk; im dev-Stage ist das Netzwerk nicht-internal (localhost-Zugriff), sodass diese Garantie nur für local/build/nightly/latest gilt. playwright erreicht das Internet stattdessen über egress.
****Nur playwright und seine Caller (open-webui und die Agents, die verlinkte Seiten lesen) befinden sich in browser, sodass der Browser seine Caller, aber keinen anderen Tier erreichen kann.
Betriebliche Überlegungen
Neue Services hinzufügen
Wenn Sie einen neuen Service hinzufügen, bestimmen Sie, welche Netzwerke dieser benötigt:
- Benötigt externen Zugriff (Ingress)? → Zum
proxyhinzufügen - Ist es ein Anwendungs-Service? → Zum
backendhinzufügen - Benötigt Datenbankzugriff? → Zum
datahinzufügen - Benötigt Objektspeicher? → Zum
storagehinzufügen - Benötigt nur ausgehenden Internetzugriff (kein Ingress)? → Zum
egresshinzufügen - Ruft die Code-Sandbox oder den Browser auf? → Den Caller zu
code-sandboxbzw.browserhinzufügen; die Sandbox und der Browser treten nie den anderen Zonen des Callers bei
Hinweis: Das egress-Netzwerk ist speziell für Services gedacht, die externe Websites/APIs erreichen müssen, aber nicht von außen erreichbar sein sollten. Es hat ICC deaktiviert, sodass Services auf egress nicht miteinander kommunizieren können – verwenden Sie backend für die Inter-Service-Kommunikation.
Netzwerkprobleme debuggen
Wenn ein Service einen anderen Service nicht erreichen kann:
- Überprüfen Sie, ob beide Services in einem gemeinsamen Netzwerk sind
- Überprüfen Sie, ob das Zielnetzwerk als
internal: truemarkiert ist - Verwenden Sie
docker network inspect <network>, um verbundene Container anzuzeigen - Überprüfen Sie, ob die Service-Namen den DNS-Erwartungen entsprechen (container_name)
Befehle zur Netzwerkprüfung
# List all networks
docker network ls
# Inspect a specific network
docker network inspect backend
# See which networks a container is connected to
docker inspect <container> --format '{{json .NetworkSettings.Networks}}'