Veröffentlicht am

Kubernetes Air-Gapped: Cluster ohne Internet betreiben

Teilen:
Authors

Kubernetes Air-Gapped: Isolierte Container-Umgebungen aufbauen

TL;DR

  • Air-Gapped-Kubernetes-Cluster haben keinen Internetzugang. Alle Images, Charts und Pakete muessen vorab transferiert werden.
  • Eine Private Registry (Harbor, Nexus) ist die zentrale Komponente fuer Image-Verteilung im isolierten Netzwerk.
  • Helm Charts werden als OCI-Artefakte oder tar-Archive exportiert und offline in die Registry importiert.
  • Zertifikatsmanagement ohne Let's Encrypt erfordert eine interne CA mit automatisierter Rotation.
  • Update-Strategien nutzen Sneakernet (physische Medien) oder Daten-Dioden fuer den Transfer in die isolierte Zone.

Warum Air-Gapped Kubernetes

Nicht jede Umgebung darf mit dem Internet verbunden sein. Regulatorische Vorgaben und Sicherheitsanforderungen erzwingen den Betrieb in vollstaendig isolierten Netzwerken:

  • Verteidigung und Behoerden: Klassifizierte Systeme ohne jegliche externe Konnektivitaet.
  • Kritische Infrastruktur (KRITIS): Energieversorger, Wasserwerke, Verkehrsleitsysteme.
  • Finanzsektor: Trading-Systeme mit strengen Netzwerk-Regulierungen.
  • Industriesteuerung (OT): Produktionsanlagen mit Air-Gap zwischen IT und OT.

In all diesen Faellen braucht der Kubernetes-Cluster eine vollstaendig autarke Infrastruktur. Kein Pull von Docker Hub, kein Helm-Repository-Zugriff, keine Online-Updates.

Architektur einer Air-Gapped-Umgebung

Die Architektur besteht aus zwei getrennten Zonen mit einem kontrollierten Transfer-Mechanismus:

ZoneKomponentenKonnektivitaet
Online-Zone (Staging)Build-Server, Image-Scanner, Chart-RepoInternet-Zugang
Transfer-ZoneDaten-Diode, USB-Medium, Air-Gap-BridgeUnidirektional oder physisch
Offline-Zone (Production)K8s-Cluster, Private Registry, Internal CAKein Internet

Der Workflow:

  1. In der Online-Zone werden Images gebaut, gescannt und signiert.
  2. Images und Charts werden exportiert und ueber die Transfer-Zone geschleust.
  3. In der Offline-Zone werden sie in die Private Registry importiert.
  4. Der Kubernetes-Cluster pulled ausschliesslich aus der internen Registry.

Fuer die grundlegende Cluster-Haertung: Kubernetes Security Hardening.

Private Registry aufsetzen: Harbor

Harbor ist die meistgenutzte Registry fuer Air-Gapped-Umgebungen. Sie bietet Image-Scanning, Signatur-Verifizierung, RBAC und Replikation.

Harbor offline installieren

# Online-Zone: Harbor-Installer herunterladen
wget https://github.com/goharbor/harbor/releases/download/v2.11.0/harbor-offline-installer-v2.11.0.tgz
sha256sum harbor-offline-installer-v2.11.0.tgz
# Auf Transfer-Medium kopieren
cp harbor-offline-installer-v2.11.0.tgz /mnt/transfer/

In der Offline-Zone:

tar xzf /mnt/transfer/harbor-offline-installer-v2.11.0.tgz
cd harbor
cp harbor.yml.tmpl harbor.yml

Die wichtigsten Konfigurationsparameter:

# harbor.yml
hostname: registry.internal.example.com
https:
  port: 443
  certificate: /etc/harbor/certs/registry.crt
  private_key: /etc/harbor/certs/registry.key
harbor_admin_password: SICHERES_PASSWORT
storage_service:
  filesystem:
    maxthreads: 100
  redirect:
    disabled: true  # Wichtig fuer Air-Gapped
./install.sh --with-trivy --with-notary

Die Option redirect.disabled: true verhindert, dass Harbor Clients zu einem externen Storage-Backend redirecten will.

Images exportieren und importieren

Methode 1: docker save / load

# Online-Zone: Images exportieren
docker pull nginx:1.27 && docker pull postgres:16 && docker pull redis:7
docker save nginx:1.27 postgres:16 redis:7 | gzip -9 > images-batch.tar.gz

In der Offline-Zone:

docker load -i /mnt/transfer/images-batch.tar.gz
docker tag nginx:1.27 registry.internal.example.com/library/nginx:1.27
docker push registry.internal.example.com/library/nginx:1.27

Methode 2: Skopeo fuer Bulk-Transfer

Skopeo ist effizienter, weil es direkt mit OCI-Verzeichnissen arbeitet:

# Online-Zone
skopeo copy docker://nginx:1.27 dir:/mnt/transfer/images/nginx-1.27

# Offline-Zone
skopeo copy dir:/mnt/transfer/images/nginx-1.27 \
  docker://registry.internal.example.com/library/nginx:1.27

Automatisiertes Image-Mirroring

Fuer regelmaessige Transfers empfiehlt sich ein Skript mit einer Image-Liste:

#!/bin/bash
IMAGE_LIST="image-manifest.txt"
EXPORT_DIR="/mnt/transfer/images"

while IFS= read -r image; do
  name=$(echo "$image" | tr '/:' '-')
  skopeo copy "docker://$image" "dir:${EXPORT_DIR}/${name}"
done < "$IMAGE_LIST"

Die image-manifest.txt listet alle benoetigten Images:

nginx:1.27
postgres:16-alpine
quay.io/prometheus/prometheus:v2.53.0
grafana/grafana:11.0.0

Offline Helm Charts

Charts als tar-Archive exportieren

# Online-Zone
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm pull prometheus-community/kube-prometheus-stack --version 65.0.0

Charts in der Offline-Zone installieren

helm install monitoring /mnt/transfer/charts/kube-prometheus-stack-65.0.0.tgz \
  --namespace monitoring --create-namespace \
  --set global.imageRegistry=registry.internal.example.com \
  --values values-airgap.yaml

Die values-airgap.yaml ueberschreibt alle Image-Referenzen:

global:
  imageRegistry: registry.internal.example.com
prometheus:
  prometheusSpec:
    image:
      registry: registry.internal.example.com
      repository: prometheus/prometheus
      tag: v2.53.0
grafana:
  image:
    registry: registry.internal.example.com
    repository: grafana/grafana
    tag: "11.0.0"

Harbor unterstuetzt auch OCI-Artefakte nativ, sodass Charts direkt gepusht und gepullt werden koennen:

helm push kube-prometheus-stack-65.0.0.tgz oci://registry.internal.example.com/charts/
helm install monitoring oci://registry.internal.example.com/charts/kube-prometheus-stack \
  --version 65.0.0 --namespace monitoring

Zertifikatsmanagement ohne Let's Encrypt

Ohne Internetzugang funktioniert Let's Encrypt nicht. Air-Gapped-Umgebungen brauchen eine interne CA.

Interne CA mit cert-manager

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: internal-ca-issuer
spec:
  ca:
    secretName: internal-ca-root
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: internal-ca-root
  namespace: cert-manager
spec:
  isCA: true
  commonName: "Internal Root CA"
  duration: 87600h  # 10 Jahre
  secretName: internal-ca-root
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
    group: cert-manager.io

Cert-manager erneuert Service-Zertifikate automatisch vor Ablauf. Die Root-CA hat eine laengere Laufzeit, muss aber ebenfalls geplant rotiert werden.

CA-Bundle an alle Nodes verteilen

Alle Nodes muessen dem Root-CA-Zertifikat vertrauen, damit kubelet Images aus der internen Registry pullen kann:

# Auf jedem Node
cp internal-ca.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust
systemctl restart containerd

Die Containerd-Konfiguration muss ebenfalls auf das CA-Zertifikat verweisen, damit Image-Pulls ueber TLS funktionieren.

Update-Strategien ohne Internet

Sneakernet: Physischer Transfer

# Online-Zone: Update-Paket erstellen
mkdir update-2026-02 && cd update-2026-02
curl -LO "https://dl.k8s.io/release/v1.31.4/bin/linux/amd64/kubeadm"
curl -LO "https://dl.k8s.io/release/v1.31.4/bin/linux/amd64/kubelet"
curl -LO "https://dl.k8s.io/release/v1.31.4/bin/linux/amd64/kubectl"
kubeadm config images list --kubernetes-version v1.31.4 > system-images.txt
sha256sum * > SHA256SUMS && gpg --sign SHA256SUMS

In der Offline-Zone:

gpg --verify SHA256SUMS.gpg && sha256sum -c SHA256SUMS
cp kubeadm kubelet kubectl /usr/local/bin/
chmod +x /usr/local/bin/kube*
kubeadm upgrade plan && kubeadm upgrade apply v1.31.4

Transfer-Methoden im Vergleich

Transfer-MethodeSicherheitsstufeBandbreiteAutomatisierbar
USB / DVDHochNiedrigNein
Daten-DiodeSehr hochMittelJa
Air-Gap-Bridge (zeitgesteuert)MittelHochJa
Cross-Domain-SolutionHochHochJa

GitOps in Air-Gapped-Umgebungen

Flux und ArgoCD funktionieren offline, wenn das Git-Repository intern gehostet wird:

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: production-apps
  namespace: flux-system
spec:
  interval: 5m
  url: https://git.internal.example.com/platform/k8s-production
  ref:
    branch: main
  secretRef:
    name: git-credentials

Das interne Git-Repository wird ueber den gleichen Transfer-Mechanismus aktualisiert wie Images und Charts. Fuer eine vollstaendige GitOps-Einfuehrung: GitOps mit Flux.

Kubernetes-Installation offline: kubeadm

# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.31.4
imageRepository: registry.internal.example.com/kubernetes
networking:
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
apiServer:
  certSANs:
    - "api.internal.example.com"
    - "10.0.1.100"
# Offline-Pakete installieren (RHEL/Rocky)
yum localinstall /mnt/transfer/rpms/containerd.io-1.7.*.rpm
yum localinstall /mnt/transfer/rpms/kubeadm-1.31.*.rpm
yum localinstall /mnt/transfer/rpms/kubelet-1.31.*.rpm

# Cluster initialisieren
kubeadm init --config kubeadm-config.yaml

Sicherheits-Checkliste fuer Air-Gapped Kubernetes

BereichMassnahmePrioritaet
RegistryHarbor mit TLS und RBACKritisch
ImagesSignatur-Verifizierung (Cosign/Notary)Kritisch
ImagesTrivy-Scan vor ImportHoch
TransferChecksummen und GPG-SignaturenKritisch
ZertifikateInterne CA mit cert-managerKritisch
ZertifikateAutomatische RotationHoch
UpdatesDokumentierter Update-ProzessHoch
BackupVelero mit lokalem StorageKritisch
DNSInterner DNS-ServerKritisch
NTPInterner NTP-ServerKritisch

Fuer die Backup-Strategie: Kubernetes Backup und Disaster Recovery.

Haeufige Fehler in Air-Gapped-Umgebungen

ImagePullBackOff wegen fehlender Images. Jedes Image im Cluster muss vorab importiert werden -- auch Init-Container, Sidecars und Operator-Images. Eine vollstaendige Image-Inventur vor dem Deployment ist Pflicht.

Zertifikatsfehler bei der Registry. Alle Nodes muessen dem CA-Zertifikat vertrauen. Fehlende CA-Konfiguration in containerd fuehrt zu TLS-Handshake-Fehlern.

Veraltete Images ohne Update-Prozess. Air-Gapped bedeutet nicht "nie updaten". Ein regelmaessiger Update-Zyklus (monatlich oder quartalsweise) ist Pflicht.

DNS-Aufloesung schlaegt fehl. Ohne externen DNS muessen alle internen Hostnamen ueber einen internen DNS-Server aufgeloest werden.

NTP-Drift. Ohne Internet-NTP-Server driften die Uhren der Nodes auseinander. Das fuehrt zu TLS-Fehlern und Problemen bei Zertifikatsvalidierung.

Fuer Security-Audits in isolierten Umgebungen: Kubernetes Security Audit.

Weitergehende Themen


Wenn Sie Unterstuetzung beim Aufbau einer Air-Gapped-Kubernetes-Umgebung benoetigen -- von der Architektur bis zum laufenden Betrieb -- melden Sie sich gerne fuer ein unverbindliches Gespraech unter /kontakt.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen