← Alle Artikel

TECHNIK · AI VM SETUP BLUEPRINT

So funktioniert die Ingress-Trennung: zwei Traefik-Controller und WireGuard

Öffentliche Websites und interne Tools können dieselbe VM nutzen und trotzdem über getrennte Ingress-Controller erreichbar sein. Dieser Artikel zeigt den Aufbau im GCP/k3s-Scaffold, den Weg einer Anfrage durch WireGuard und die Prüfungen der Zugriffsgrenzen.

WIREGUARD + TRAEFIK

Eine VM. Zwei Zugangswege.

Die private HTTPS-Verbindung läuft im WireGuard-Tunnel bis zur VM.

ÖFFENTLICH

Website-Besucherwww.example.com
Internet · HTTPS
Öffentliche VM-AdresseTCP 80 / 443 · ServiceLB
Öffentlicher Service-Pfad
Traefik · publicingressClassName: traefik
Service → endpoints
Öffentliche Appwww.example.com

PRIVAT · NUR ÜBER VPN

Interner Nutzercrm.int.example.com → VPN IP
Verschlüsselter WireGuard-Tunnel · UDP
WireGuard · VMEntschlüsselt → Tunnel-IP:443
externalIPs → pod :8443
Traefik · privateingressClassName: internal
Service → endpoints
Private Appcrm.int.example.com

Auf der VM: getrennte Controller und Klassen, ergänzt durch Firewall und NetworkPolicies. Keine öffentliche Anwendungsroute zum privaten Backend.

Der konkrete Aufbau

Dieser Artikel beschreibt das mitgelieferte GCP/k3s-Scaffold, keine universelle Anleitung für jedes Kubernetes-Netzwerk. Öffentlich wird der mit k3s gelieferte Traefik genutzt. Für den privaten Weg wird ein separater Traefik-Helm-Release mit festgelegter Version in einem eigenen Namespace installiert. In den Beispielen heißen die Ingress-Klassen traefik und internal.

Beide Controller beobachten die benötigten Namespaces, wählen aber unterschiedliche Ingress-Klassen aus. Erreichbarkeit und Backend-Policies ergänzen diese Konfiguration. Eine private IP oder ein Klassenname allein ist keine Berechtigungsgrenze.

Den öffentlichen Controller konfigurieren

Eine HelmChartConfig namens traefik im Namespace kube-system überschreibt die Werte des mitgelieferten Charts. So bleibt die Paketverwaltung bei k3s. Die öffentliche Klasse ist explizit und nicht als Standard gesetzt. Der Kubernetes-Ingress-Provider wählt traefik; CRD- und Gateway-Provider sind in diesem Aufbau deaktiviert.

Die Weiterleitung von HTTP zu HTTPS steht unter ports.web.http.redirections.entryPoint. Die zusätzliche Ebene http ist für das verwendete Chart entscheidend. Dass Helm die Werte akzeptiert, belegt die Weiterleitung noch nicht: Der Verifier kontrolliert die tatsächlichen Container-Argumente. Der öffentliche Service nutzt den ServiceLB-Pfad von k3s; der genaue Paketweg hängt vom Host- und Provider-Netzwerk ab.

Konfigurationsauszug, kein vollständiges Deployment. Platzhalter und Chart-Version an die Umgebung anpassen.

# HelmChartConfig: kube-system/traefik — valuesContent excerpt
ingressClass:
  enabled: true
  isDefaultClass: false
  name: traefik
providers:
  kubernetesIngress:
    enabled: true
    ingressClass: traefik
    allowExternalNameServices: false
    allowEmptyServices: false
  kubernetesCRD:
    enabled: false
  kubernetesGateway:
    enabled: false

Einen eigenen privaten Helm-Release installieren

Der private Release verwendet einen eigenen Namespace und die Klasse internal, ebenfalls ohne Standardmarkierung. Aktiv ist der normale Ingress-Provider; CRD- und Gateway-Provider sind deaktiviert. ExternalName-Backends und leere Services sind im Scaffold bei beiden Controllern abgeschaltet.

Der private Service hat den Typ ClusterIP und führt unter externalIPs die Tunnel-Adresse des WireGuard-Servers. Die Service-Ports 80 und 443 führen zu den Container-Ports 8000 und 8443. Zusätzlich setzt das Scaffold svccontroller.k3s.cattle.io/enablelb auf false. Die Prüfung muss bestätigen, dass weder ein unerwarteter privater ServiceLB noch ein öffentlicher NodePort entsteht.

externalIPs vergibt keine IP-Adresse und richtet WireGuard nicht ein. Die Tunnel-Adresse muss bereits auf dem Host existieren und für freigegebene Peers erreichbar sein. Im erwarteten iptables-Pfad verarbeitet kube-proxys KUBE-SERVICES-Regel dieses Ziel vor CNI-HOSTPORT-DNAT. Diese Reihenfolge wird geprüft. Ein anderes Netzwerk-Dataplane braucht einen separat validierten Aufbau.

Konfigurationsauszug, kein vollständiges Deployment. Platzhalter und Chart-Version an die Umgebung anpassen.

# Private Helm release — valuesContent excerpt
ingressClass:
  enabled: true
  isDefaultClass: false
  name: internal
providers:
  kubernetesIngress:
    enabled: true
    ingressClass: internal
    allowExternalNameServices: false
    allowEmptyServices: false
  kubernetesCRD:
    enabled: false
  kubernetesGateway:
    enabled: false
service:
  annotations:
    svccontroller.k3s.cattle.io/enablelb: "false"
  spec:
    type: ClusterIP
    externalIPs:
      - <WIREGUARD_SERVER_IP>
ports:
  web:
    port: 8000
    exposedPort: 80
    expose: {default: true}
  websecure:
    port: 8443
    exposedPort: 443
    expose: {default: true}

Der Weg einer privaten HTTPS-Anfrage

Der Nutzer öffnet https://crm.int.example.com. Eine auf int.example.com begrenzte Resolver-Regel liefert die Tunnel-Adresse des WireGuard-Servers. Routen und AllowedIPs des Peers müssen dieses Ziel abdecken. Der HTTPS-Verkehr des Browsers läuft im verschlüsselten UDP-Tunnel zur VM.

WireGuard entschlüsselt das Paket auf der VM. Sein Ziel bleibt die Tunnel-Adresse auf Port 443. Die Service-Regeln leiten es zum privaten Traefik-Pod auf Port 8443. Traefik wählt die private Host-Regel, terminiert TLS mit dem referenzierten Secret und leitet die Anfrage an die Endpunkte des Backend-Service weiter.

Im gezeigten Aufbau verwendet der Backend-Hop HTTP auf dem gewählten Backend-Port. HTTPS im Browser bedeutet also nicht automatisch TLS zwischen allen Pods. Die Anwendung bleibt für Anmeldung und Benutzerrechte verantwortlich. WireGuard authentifiziert Peers, die Anwendung autorisiert ihre Nutzer.

Die Anwendungsroute eindeutig zuordnen

Der private Ingress setzt spec.ingressClassName auf internal und wählt den EntryPoint websecure. tls.secretName verweist auf ein Zertifikats-Secret im selben Namespace. Die Ausstellung kann über den getrennten öffentlichen HTTP-01-Weg erfolgen, den der begleitende Artikel beschreibt. Eine öffentliche Anwendungsroute ist dafür nicht nötig.

Auf dem öffentlichen Controller darf keine passende Anwendungsroute existieren. Eine falsche Klasse kann ein Backend veröffentlichen, wenn andere Policies das zulassen. Deshalb wird das Routenmanifest geprüft. Keine Klasse ist Standard; außerdem prüft der Verifier, ob jeder Ingress eine explizite Klasse hat.

Konfigurationsauszug, kein vollständiges Deployment. Platzhalter und Chart-Version an die Umgebung anpassen.

# Private Ingress — excerpt, same namespace as its TLS Secret
metadata:
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
  ingressClassName: internal
  tls:
    - hosts: [crm.int.example.com]
      secretName: crm-tls
  rules:
    - host: crm.int.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: crm
                port: {number: 80}

Controller-Verkehr in beide Richtungen begrenzen

Im Namespace des privaten Controllers gilt zunächst Default-Deny für Ingress und Egress. Eine begrenzte Ingress-Regel erlaubt den Tunnel-Peer-Adressbereich auf den Pod-Ports 8000 und 8443, ausgenommen die Tunnel-Adresse des Servers selbst. Entscheidend ist die Quelladresse, die die NetworkPolicy tatsächlich sieht; NAT-Verhalten muss in der gewählten Umgebung getestet werden.

Egress erlaubt DNS, die Kubernetes-API sowie den gewählten Backend-Namespace und Port. Backend-Regeln wählen sowohl den Namespace des privaten Controllers als auch dessen Traefik-Pods aus. Der mitgelieferte Validierungs-Namespace enthält synthetische Probes. Seine gemeinsamen Testregeln ersetzen keine anwendungsspezifischen Policies für spätere Workloads. Alle additiven Regeln müssen zusammen betrachtet werden.

Die Grenze von außen nachweisen

Über WireGuard werden die Identität der privaten Probe und ein gültiges Zertifikat geprüft. Außerhalb des Tunnels werden derselbe Host-Header und TLS-SNI gezielt an jede öffentliche Adresse gesendet. Dort darf die private Probe nie antworten. Eine allgemeine 404 muss vom öffentlichen Catch-all kommen. Gefälschte X-Forwarded-For- oder X-Real-IP-Header dürfen daran nichts ändern.

Geprüft werden Provider-Argumente, Service-Adressen, Ingress-Klassen, Ports, Firewall-Verhalten und alternative NodePort-Wege. Ein temporärer unberechtigter Pod testet die Cluster-Seite. Nach Controller-Upgrades, Policy-Änderungen und Wiederherstellung werden die Prüfungen wiederholt. Zwei Controller auf einer VM teilen weiterhin Host und Cluster; die Trennung ersetzt keine Isolation durch separate Maschinen.

Weiterlesen: Zertifikate für private Apps mit HTTP-01 oder DNS-01 →

Technische Referenzen