Skip to main content

IDIAL Kubernetes-Deployment: Interne PKI + interne Datenbank (SQLite)

Diese Anleitung beschreibt das Deployment von IDIAL Core, IDIAL App/UI und dem internen PKI-Stack (Nexus Certificate Manager) auf einem Kubernetes-Cluster mittels reiner kubectl apply -f-Manifeste. Sie richtet sich an Administratoren, die IDIAL in einer Testumgebung oder einem abgegrenzten Kunden-Cluster ohne externe Datenbank und ohne externe PKI betreiben wollen.

1. Übersicht

1.1 Was dieses Setup abdeckt

  • IDIAL Core — mit eingebetteter SQLite-Datenbank (kein externer Datenbankserver erforderlich).
  • IDIAL App/UI — Web-Frontend, kommuniziert ausschließlich mit Core.
  • Interner PKI-Stack (Nexus Certificate Manager) — PostgreSQL, Artefakt-/WebDAV-Server, cis-server, cf-server, pgw (Protocol Gateway). Vollständig im Cluster betrieben, keine externe Zertifizierungsstelle notwendig.

Für Umgebungen mit einer bereits vorhandenen, extern betriebenen PostgreSQL-Instanz und/oder einer externen PKI siehe das separate Setup "Externe PostgreSQL + externe PKI".

1.2 Architektur

Alle Komponenten laufen in einem einzigen Namespace (idial) und kommunizieren über Cluster-interne Kubernetes-Services (Standard-ClusterIP, kein Multus/macvlan, keine dedizierte OT-Netzwerksegmentierung):

KomponenteService-NamePortBeschreibung
IDIAL Coreidial5000REST-API
IDIAL App/UIidial-web-backend5555Web-Oberfläche
PKI-Postgresdb5432Datenbank des Nexus-CM-Stacks
PKI-Artefaktserverfiles8000WebDAV-Server für PKI-Bootstrap
Nexus CIScis-server1234Certificate Issuing Service
Nexus CFcf-server5009Certificate Factory
Protocol Gatewaypgw8080/8443/8444Geräte-Schnittstelle des PKI-Stacks

1.3 Cluster-Voraussetzungen

  • Kubernetes-Cluster mit containerd als Container-Runtime und Calico (oder einer vergleichbaren CNI) — getestet mit einem kubeadm-Cluster (1 Control-Plane, ≥1 Worker).
  • Kein Registry-Zugriff vorausgesetzt: alle Images werden per Tarball auf die Nodes importiert (siehe Abschnitt 2).
  • Ein bereits installierter ingress-nginx-Controller (IngressClass: nginx), falls externer Zugriff über einen Browser benötigt wird (Abschnitt 5). Ohne ingress-nginx ist IDIAL nur cluster-intern erreichbar.
  • Eine StorageClass mit dynamischer Provisionierung (z. B. local-path-provisioner). Bei node-lokalem Storage auf einem Multi-Node-Cluster: siehe Hinweis in Abschnitt 3.4 zu nodeSelector.

2. Vorbereitung

2.1 Benötigte Images

ImageVerwendung
docker.io/bxc2security/idial:v0.38.16-devIDIAL Core
docker.io/bxc2security/idial-web-backend:v0.42.8IDIAL App/UI
docker.io/bxc2security/idial-db-schema:1.7.0Schema-Install (initContainer auf Core)
docker.io/postgres:18-alpinePKI-Postgres (db) + SQL-Schema-Job
docker.io/bxc2security/files:latestInterner Artefakt-/WebDAV-Server
docker.io/bxc2security/nexus:cf-server-8.14.0cis-server + cf-server
docker.io/bxc2security/nexus:pgw-8.14.0pgw (Protocol Gateway)
docker.io/alpine:latestWait-Loop-InitContainer, Download-Schritte
docker.io/bxc2security/alpine:latestConfig-Editor (eigenes Rebuild mit openssl+keytool)

Die Versionen für Core/App/Schema/CM sind zentral in 02-configmap.yaml gepflegt. Bei einem Versionswechsel müssen zusätzlich die Image-Referenzen in den betroffenen Deployment-/Job-Manifesten (04-, 13-, 14-, 15-*.yaml) angepasst werden.

2.2 Image-Import ohne Registry-Zugriff

Auf einer Maschine mit Registry-Zugriff ("Docker-Host") jedes Image herunterladen und als Tarball exportieren:

docker pull <image>
docker save -o <name>.tar <image>

Tarball auf jeden Worker-Node übertragen, auf dem IDIAL-Pods laufen können:

scp <name>.tar <user>@<worker>:~/

Auf jedem Worker-Node importieren:

sudo ctr -n k8s.io images import <name>.tar --base-name <image>

Import verifizieren:

sudo ctr -n k8s.io images ls | grep <name>

Alle Deployment-Manifeste verwenden imagePullPolicy: Never — ein Pod schlägt mit ErrImageNeverPull fehl, sobald ein Image auf dem Node, auf dem er geplant wurde, nicht per ctr import vorhanden ist. Images müssen daher auf allen Worker-Nodes importiert werden, nicht nur auf einem.

3. Deployment

3.1 Manifeste beziehen

git clone <repository-url>
cd <repository>/manifests/sqlite-internal-pki

3.2 Secrets erzeugen

Secret-Werte werden nie in einer Datei committet oder verteilt. Vor dem ersten Deployment einmalig:

./generate-secrets.sh

Das Skript ist idempotent — bereits vorhandene Secrets werden übersprungen, nicht überschrieben. Das ist notwendig: SECRET_KEY und IDIAL_APP_MASTER_KEY dürfen nach dem ersten erfolgreichen App-Start nie neu generiert werden, sonst werden aktive Web-Sessions ungültig bzw. bereits verschlüsselte App-Daten unlesbar. Erneutes Ausführen des Skripts (z. B. nach einem Redeploy, bei dem nur die Secrets fehlen) ist dadurch gefahrlos möglich.

01-secrets.yaml.example dokumentiert nur die Struktur (welche Secrets, welche Keys) und wird von kubectl apply -f <verzeichnis> nicht mitgenommen (Dateiendung .example).

3.3 Anwenden

kubectl apply -f .

Reihenfolge spielt keine Rolle — jedes Manifest trägt seine Abhängigkeiten über initContainer-Wartschleifen selbst (siehe 3.4).

3.4 Startreihenfolge & erwartetes Verhalten

  • Schema-Install läuft als initContainer auf dem idial-Deployment selbst, vor dem Hauptcontainer.
  • idial-web-backend wartet per initContainer, bis idial:5000 erreichbar ist.
  • Der PKI-Bootstrap (pki-copy-files-from-webdavpki-db-schema-sql / pki-config-editorcis-server/cf-server/pgw) läuft über eine Kette von initContainer-Wartschleifen auf reale Artefakte in gemeinsam gemounteten Volumes.
  • Erwartetes, unkritisches Verhalten: cis-server kann in den ersten 1–2 Minuten nach dem Deploy kurzzeitig in CrashLoopBackOff laufen, bis pki-db-schema-sql abgeschlossen ist — Kubernetes startet ihn danach automatisch neu, kein manueller Eingriff nötig.

Wichtig bei node-lokalem Storage (z. B. local-path-provisioner) auf einem Multi-Node-Cluster: mehrere ReadWriteOnce-PVCs im PKI-Stack werden von verschiedenen Jobs/Deployments gemeinsam gemountet. Da eine solche PVC beim ersten Gebrauch an genau einen Node bindet, müssen alle Objekte, die dieselben PVCs teilen, auf demselben Node landen. Die betroffenen sechs Objekte (13-pki-setup-jobs.yaml, 14-pki-cis-server.yaml, 15-pki-cf-server-pgw.yaml) tragen dafür nodeSelector: { kubernetes.io/hostname: k8s-worker } — den Hostnamen vor dem Deployment auf einen tatsächlich existierenden Node dieses Clusters anpassen, oder auf eine RWX-fähige StorageClass wechseln, um das Node-Pinning ganz zu entfernen.

4. Verifizierung

kubectl get pods -n idial -w

Erwarteter Endzustand (kann je nach Cluster-Geschwindigkeit 1–3 Minuten dauern): alle Deployments 1/1 Running, alle Jobs Completed.

kubectl get pods -n idial
kubectl get jobs -n idial
kubectl get pvc -n idial

Core-API-Erreichbarkeit cluster-intern prüfen:

kubectl -n idial run curl-test --rm -it --image=curlimages/curl --restart=Never \
-- curl -sk https://idial:5000/

5. Externer Zugriff

5.1 Ingress-Voraussetzung

16-ingress.yaml setzt einen bereits installierten ingress-nginx (IngressClass: nginx) voraus — der Controller selbst wird von diesem Manifest-Satz nicht mit installiert.

5.2 Pfad-Übersicht

PfadServicePortHinweis
/idial-web-backend5555UI, beansprucht die gesamte URL
/core-apiidial5000Core-REST-API
/pgwpgw8080Protocol Gateway (HTTP)
/filesfiles8000Interner PKI-Artefaktserver

Wichtig: für die Core-API ausschließlich /core-api verwenden, nicht /apiidial-web-backend besitzt eigene interne Routen unter /api/... (vom Browser-JS aufgerufen). Ein Ingress-Pfad /api für Core würde mit diesen Routen kollidieren.

5.3 Zugriff testen

http://<node-ip>:<ingress-http-nodeport>/
https://<node-ip>:<ingress-https-nodeport>/

idial und idial-web-backend terminieren TLS intern selbst (selbstsigniertes Zertifikat) — der Ingress ist entsprechend mit nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" und nginx.ingress.kubernetes.io/proxy-ssl-verify: "off" konfiguriert.

6. Fehlerbehebung

SymptomWahrscheinliche UrsacheLösung
ErrImageNeverPullImage auf diesem Node nicht importiertctr -n k8s.io images import auf dem betroffenen Node nachholen (Abschnitt 2.2)
Pod bleibt dauerhaft Pending, FailedScheduling: node(s) didn't match PersistentVolume's node affinityGemeinsam genutzte PVCs sind auf unterschiedliche Nodes gebundennodeSelector in den betroffenen Manifesten prüfen/anpassen (Abschnitt 3.4)
Pod bleibt Pending, Events zeigen untolerated taint {node.kubernetes.io/unreachable}Ein oder mehrere Nodes sind aktuell nicht erreichbarkubectl get nodes prüfen; Kubelet/Netzwerk auf dem betroffenen Node untersuchen — kein Deployment-Problem
cis-server kurz nach dem Deploy in CrashLoopBackOffErwartet, siehe Abschnitt 3.4Kein Eingriff nötig, löst sich automatisch sobald pki-db-schema-sql fertig ist
idial-web-backend: CRITICAL ERROR: Master key has incorrect length: 48 bytes (expected: 32)IDIAL_APP_MASTER_KEY wurde mit openssl rand -hex statt -base64 erzeugtSecret mit openssl rand -base64 32 neu erzeugen (nur vor dem ersten produktiven Start — siehe Warnung in 3.2)
Ingress liefert 502 Bad GatewayBackend terminiert TLS selbst, Ingress spricht per Default HTTPbackend-protocol/proxy-ssl-verify-Annotationen prüfen (bereits Standard in 16-ingress.yaml)
Browser zeigt {"message":"Missing or invalid API key"}Core-API unter /api statt /core-api aufgerufenAusschließlich /core-api für Core verwenden (Abschnitt 5.2)
CreateContainerConfigError bei mehreren DeploymentsSecrets fehlen./generate-secrets.sh ausführen (Abschnitt 3.2)
error validating ... dial tcp <ip>:6443: connect: connection refusedAPI-Server auf dem Master nicht erreichbarKubelet/containerd-Status auf dem Master prüfen (systemctl status kubelet, journalctl -u kubelet) — unabhängig von diesen Manifesten

7. Bekannte Einschränkungen

  • Nur eine Core-Instanz (replicas: 1). SQLite erzwingt dies. Für horizontale Skalierung ist die Variante "Externe PostgreSQL" notwendig.
  • EXTERNAL_HOST in 02-configmap.yaml ist ein Platzhalter (idial.idial.svc.cluster.local) ohne Aussagekraft außerhalb des Clusters — vor produktivem Gerätebetrieb durch eine tatsächlich erreichbare Adresse ersetzen.
  • Cores eigener REST-API-Key wird von Core selbst beim ersten Start generiert und als Datei im idial-api-key-PVC abgelegt (kein Kubernetes-Secret). Abrufbar per:
    kubectl exec -n idial deploy/idial -- cat /app/secrets/idial_api_key.txt
  • Kein TLS auf Ingress-Ebene konfiguriert — bei Bedarf einen eigenen tls:-Block mit Zertifikat/Secret ergänzen.