Netzwerkisolation zwischen Compose-Stacks - Dienste gezielt absichern

Netzwerkisolation zwischen Compose-Stacks - Dienste gezielt absichern

Jeder Container, der im selben Docker-Netzwerk ist, kann alle anderen Container in diesem Netzwerk direkt ansprechen — das ist oft mehr Zugriff als nötig.

Das Standard-Verhalten

Ohne explizite Netzwerk-Konfiguration packt Compose alle Services eines Projekts in ein gemeinsames Netzwerk:

# Alle drei Container sind im selben Netzwerk
services:
  web:
    image: nginx
  app:
    image: myapp
  db:
    image: postgres:16

Ergebnis: web kann direkt db:5432 erreichen — obwohl das nie beabsichtigt war. Das Prinzip der geringsten Berechtigung wird verletzt.

Lösung: Mehrere Netzwerke

services:
  web:
    image: nginx
    networks:
      - frontend          # Web kann nur app erreichen

  app:
    image: myapp
    networks:
      - frontend          # Erreichbar für web
      - backend           # Kann db erreichen

  db:
    image: postgres:16
    networks:
      - backend           # Nur für app erreichbar, NICHT für web

networks:
  frontend:
  backend:

web und db sind in keinem gemeinsamen Netzwerk — direkte Verbindung ist unmöglich. app sitzt als Brücke zwischen beiden.

Erweitertes Beispiel mit Cache

services:
  web:
    image: nginx
    ports:
      - "443:443"
    networks:
      - frontend

  app:
    image: myapp
    networks:
      - frontend
      - backend

  cache:
    image: redis
    networks:
      - backend           # app → cache: ja; web → cache: nein

  db:
    image: postgres:16
    networks:
      - backend           # app → db: ja; web → db: nein; cache → db: nein

networks:
  frontend:               # Öffentliche Seite
  backend:                # Interne Dienste

Internes Netzwerk: kein Internet-Zugriff

networks:
  backend:
    internal: true        # Container in diesem Netz können NICHT ins Internet

Nützlich für Datenbanken, die niemals externe Verbindungen aufbauen sollen. Ein Angreifer, der den DB-Container kompromittiert, kann darüber keine Daten nach außen exfiltrieren.

Netzwerk-Zugriff prüfen

# Welche Netzwerke hat ein Container?
docker inspect --format='{{json .NetworkSettings.Networks}}' myapp | jq 'keys'

# Container im selben Netzwerk?
docker network inspect backend --format='{{range .Containers}}{{.Name}} {{end}}'

# Verbindung testen (aus Container heraus)
docker exec web curl -m 3 http://db:5432   # Sollte fehlschlagen
docker exec app curl -m 3 http://db:5432   # Sollte funktionieren

Netzwerk-Aliases

In manchen Fällen soll ein Container unter mehreren Namen erreichbar sein:

services:
  app:
    image: myapp
    networks:
      frontend:
        aliases:
          - api
          - backend-api
      backend:

Warum das wichtig ist

  • Ohne Isolation:
  • Web-Server kompromittiert → direkter Zugriff auf DB
  • SQL-Injection im Frontend → direkte DB-Verbindung möglich
  • Mit Isolation:
  • Web-Server kompromittiert → erreicht nur die App-API
  • App muss kompromittiert sein, um DB zu erreichen
  • Jede Stufe ist eine zusätzliche Barriere

Das ist kein Ersatz für starke Passwörter und Firewall-Regeln — aber es reduziert die Angriffsfläche deutlich, mit minimalem Konfigurationsaufwand.

Empfehlung für neue Projekte

Mindest-Setup für jede produktive Compose-Anwendung:

networks:
  public:     # Zwischen Proxy und App
  private:    # Zwischen App und Datenbank/Cache

Kein Service außer dem Proxy braucht Zugriff auf das public-Netzwerk. Kein Service außer der App braucht Zugriff auf das private-Netzwerk.