Zum Hauptinhalt springen

IDIAL Kubernetes-Deployment: Externe PostgreSQL-Datenbank und externe PKI

Diese Anleitung beschreibt das Deployment von IDIAL Core und IDIAL App/UI auf einem Kubernetes-Cluster, wenn sowohl die Datenbank als auch die PKI (Nexus Certificate Manager oder eine vergleichbare Lösung) bereits bei euch vorhanden sind und selbst betrieben werden. IDIAL selbst installiert oder verwaltet in diesem Setup keine Datenbank und keine PKI. Es verbindet sich lediglich mit euren bestehenden Systemen.

1. Übersicht

1.1 Was dieses Setup abdeckt

IDIAL Core verbindet sich mit einer bereits laufenden PostgreSQL-Instanz und mit einem bereits laufenden PKI-Gateway. Beide Systeme werden von euch betrieben und administriert. Kubernetes bekommt dafür lediglich die Adressen genannt, unter denen diese Systeme erreichbar sind.

Enthalten sind:

  • IDIAL Core, konfiguriert auf externe PostgreSQL-Anbindung
  • IDIAL App/UI, das Web-Frontend, das ausschließlich mit Core spricht

Nicht enthalten, weil bei euch bereits vorhanden:

  • Eine PostgreSQL-Datenbank
  • Eine Zertifizierungsstelle beziehungsweise ein PKI-Gateway

1.2 Architektur

IDIAL läuft in einem eigenen Namespace (idial). Core und App kommunizieren über einen normalen Kubernetes-Service miteinander. Für die Verbindung zu eurer externen Datenbank und eurem externen PKI-Gateway werden zwei zusätzliche Service-Objekte angelegt, die auf eure echte Infrastruktur verweisen.

KomponenteService-NamePortBeschreibung
IDIAL Coreidial5000REST-API
IDIAL App/UIidial-web-backend5555Web-Oberfläche
Eure PostgreSQLidial-db-external5432Verweis auf eure Datenbank
Euer PKI-Gatewaypgw8080/8443/8444Verweis auf euer Gateway

1.3 Voraussetzungen

  • Ein Kubernetes-Cluster mit containerd als Container-Runtime. Die Wahl der CNI (Calico, Cilium und so weiter) spielt für dieses Setup keine Rolle, solange Pods innerhalb des Clusters miteinander und mit externen Adressen kommunizieren können.
  • Netzwerkverbindung vom Cluster zu eurer PostgreSQL-Instanz (Port 5432 oder der von euch konfigurierte Port) und zu eurem PKI-Gateway (Standard 8080, 8443, 8444). Prüft eure Firewall-Regeln, bevor ihr deployt.
  • Eine bereits existierende PostgreSQL-Datenbank und ein Benutzer mit Schreibrechten darauf. Das Schema wird beim ersten Start automatisch angelegt.
  • Optional ein bereits installierter ingress-nginx-Controller, falls IDIAL über einen Browser von außerhalb des Clusters erreichbar sein soll.

2. Vorbereitung

2.1 Benötigte Images

ImageVerwendung
docker.io/bxc2security/idial:v0.38.7-devIDIAL Core
docker.io/bxc2security/idial-web-backend:v0.42.0IDIAL App/UI
docker.io/bxc2security/idial-db-schema:1.7.0Schema-Install (läuft beim Start von Core mit)
docker.io/alpine:latestWartet beim Start darauf, dass Datenbank und Core erreichbar sind

Wenn euer Cluster Zugriff auf eine Container-Registry hat, könnt ihr die Images ganz normal per imagePullPolicy beziehen. Falls nicht, im nächsten Abschnitt der Weg über einen Tarball-Import.

2.2 Image-Import ohne Registry-Zugriff

Auf einer Maschine mit Registry-Zugriff jedes Image herunterladen und als Tarball exportieren:

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

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

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

Import verifizieren:

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

Die Manifeste in diesem Setup verwenden standardmäßig imagePullPolicy: Never, weil dieses Verfahren für unsere eigenen Testumgebungen ohne Registry-Zugriff gedacht ist. Wenn euer Cluster eine Registry erreichen kann, ändert das Feld einfach auf IfNotPresent und lasst den Import-Schritt weg.

3. Externe Infrastruktur anbinden

Bevor IDIAL deployt wird, müssen die beiden externen Systeme im Cluster bekannt gemacht werden. Dafür verwenden wir das Kubernetes-Standardmuster "Service ohne Selector plus passendes Endpoints-Objekt". Andere Pods sprechen den Service ganz normal über seinen Namen an, ohne zu wissen, dass dahinter kein echter Pod im Cluster steckt.

3.1 Externe PostgreSQL-Datenbank

In 06-external-endpoints.yaml steht ein Service namens idial-db-external. Tragt dort in der Endpoints-Ressource die Adresse eurer echten PostgreSQL-Instanz ein:

apiVersion: v1
kind: Endpoints
metadata:
name: idial-db-external
namespace: idial
subsets:
- addresses:
- ip: <eure Postgres-IP>
ports:
- name: postgres
port: 5432

Wichtig dabei: die eingetragene Adresse muss ein direkt erreichbares Ziel sein, also eine echte Server-IP oder die IP eines Load Balancers davor. Sie darf nicht die ClusterIP eines anderen Kubernetes-Services sein, auch nicht aus demselben Cluster. Kube-proxy leitet Datenverkehr zu einer ClusterIP nur um, wenn diese das ursprüngliche Verbindungsziel eines Pods war, nicht wenn sie selbst als Endpoint-Adresse für einen anderen Service eingetragen wird. In diesem Fall bleibt die Verbindung stehen und läuft irgendwann in einen Timeout.

Falls eure Datenbank stattdessen über einen DNS-Namen erreichbar ist, könnt ihr auf einen ExternalName-Service wechseln, dann braucht ihr kein separates Endpoints-Objekt:

apiVersion: v1
kind: Service
metadata:
name: idial-db-external
namespace: idial
spec:
type: ExternalName
externalName: postgres.euer-unternehmen.example.com

3.2 Externes PKI-Gateway

Genauso für euer PKI-Gateway, im selben File unter dem Namen pgw. Core erwartet das Gateway grundsätzlich unter diesem Namen, unabhängig davon, welche PKI ihr einsetzt. Tragt hier die Adresse eures Gateways ein und prüft, welche der drei Ports (HTTP 8080, HTTPS 8443, mTLS 8444) eure Installation tatsächlich anbietet:

apiVersion: v1
kind: Endpoints
metadata:
name: pgw
namespace: idial
subsets:
- addresses:
- ip: <eure PKI-Gateway-IP>
ports:
- name: http
port: 8080
- name: https
port: 8443
- name: mtls
port: 8444

Es gelten dieselben Hinweise wie oben: eine echte, direkt erreichbare Adresse eintragen, keine ClusterIP eines anderen Services.

4. Deployment

4.1 Manifeste beziehen

git clone <repository-url>
cd <repository>/manifests/postgres-external-pki

4.2 Konfiguration anpassen

In 02-configmap.yaml die Datenbank-Zugangsdaten an eure Umgebung anpassen, sofern ihr nicht die Standardwerte (idial/idial) verwendet:

IDIAL_DB_NAME: "idial"
IDIAL_DB_USER: "idial"

Der Host wird nicht direkt hier eingetragen, sondern zeigt bereits auf den Service aus Abschnitt 3.1 (idial-db-external). Ändert das nur, wenn ihr den Service anders benannt habt.

4.3 Secrets anlegen

Drei Secrets werden benötigt. Keines davon sollte als Klartextdatei in einem Repository landen.

Zunächst den Namespace anlegen, falls noch nicht vorhanden:

kubectl create namespace idial

Danach die Secrets direkt per kubectl create secret:

kubectl create secret generic idial-core-secret -n idial \
--from-literal=pkcs8_pwd="$(openssl rand -base64 24 | tr -d '=+/')"

kubectl create secret generic idial-app-secret -n idial \
--from-literal=SECRET_KEY="$(openssl rand -base64 32)" \
--from-literal=IDIAL_APP_MASTER_KEY="$(openssl rand -base64 32)"

kubectl create secret generic idial-db-secret -n idial \
--from-literal=IDIAL_DB_PASSWORD='<das echte Passwort eures Postgres-Users>'

Zwei Dinge sind hier wichtig. Erstens muss IDIAL_APP_MASTER_KEY mit openssl rand -base64 32 erzeugt werden, nicht mit -hex. Die App dekodiert den Wert selbst und erwartet danach genau 32 Bytes. Ein Hex-String ergibt beim Dekodieren die falsche Länge, und die App verweigert dann den Start mit einer Fehlermeldung zur Schlüssellänge.

Zweitens dürfen SECRET_KEY und IDIAL_APP_MASTER_KEY nach dem ersten erfolgreichen Start von IDIAL App nie wieder neu erzeugt werden. Sonst werden alle aktiven Sitzungen ungültig und bereits verschlüsselte Daten lassen sich nicht mehr entschlüsseln. Bewahrt diese Werte entsprechend sorgfältig auf.

4.4 Anwenden

kubectl apply -f .

Die Reihenfolge der Dateien spielt keine Rolle. Core wartet beim Start selbst darauf, dass die Datenbank erreichbar ist, bevor es das Schema installiert und danach hochfährt. App wartet ihrerseits darauf, dass Core erreichbar ist.

5. Verifizierung

kubectl get pods -n idial -w

Beide Deployments sollten nach kurzer Zeit 1/1 Running zeigen. Falls idial länger als eine Minute in Init hängen bleibt, mit den Logs des Wartecontainers prüfen, ob die Verbindung zur Datenbank überhaupt zustande kommt:

kubectl logs -n idial deploy/idial -c wait-for-db

6. Externer Zugriff

Falls IDIAL über einen Browser erreichbar sein soll und bereits ein ingress-nginx-Controller im Cluster läuft, legt 07-ingress.yaml zwei Ingress-Objekte an:

PfadServicePortHinweis
/idial-web-backend5555UI, beansprucht die gesamte URL
/core-apiidial5000Core-REST-API

Verwendet für die Core-API ausschließlich /core-api, nicht /api. App besitzt eigene interne Routen unter /api/..., die vom Browser direkt aufgerufen werden. Ein Ingress-Pfad /api für Core würde mit diesen Routen kollidieren, und Anfragen der App würden fälschlich bei Core statt beim eigentlichen Ziel landen.

Core und App terminieren TLS intern selbst mit einem selbstsignierten Zertifikat. Der Ingress ist deshalb mit nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" und nginx.ingress.kubernetes.io/proxy-ssl-verify: "off" konfiguriert. Wenn ihr für den Ingress selbst ein eigenes Zertifikat verwenden wollt, ergänzt einen tls-Block mit einem passenden Secret.

7. Fehlerbehebung

SymptomWahrscheinliche UrsacheLösung
wait-for-db läuft dauerhaft in eine Schleife, ohne durchzukommenDatenbank nicht erreichbar oder falsche Adresse in 06-external-endpoints.yaml eingetragenAdresse prüfen, Firewall zwischen Cluster und Datenbank prüfen, testen ob die Adresse ein echtes Ziel und keine Kubernetes-ClusterIP ist
schema-install schlägt fehl oder bricht mit einem Berechtigungsfehler abDer konfigurierte Datenbankbenutzer hat keine Rechte, das Schema anzulegenBenutzer mit Schreibrechten auf die Zieldatenbank verwenden
idial-web-backend: Fehlermeldung zur Schlüssellänge beim StartIDIAL_APP_MASTER_KEY wurde mit -hex statt -base64 erzeugtSecret mit openssl rand -base64 32 neu erzeugen, nur vor dem allerersten Start
ErrImageNeverPullImage auf diesem Node nicht importiertImport auf dem betroffenen Node nachholen, oder imagePullPolicy anpassen, falls eine Registry erreichbar ist
CreateContainerConfigErrorEines der drei Secrets fehlt nochSecrets aus Abschnitt 4.3 anlegen
Ingress liefert 502 Bad GatewayBackend-Protocol-Annotationen fehlen oder wurden entferntAnnotationen aus Abschnitt 6 prüfen
Browser zeigt eine Meldung zu einem fehlenden oder ungültigen API-KeyCore-API unter /api statt /core-api aufgerufenAusschließlich /core-api verwenden

8. Bekannte Einschränkungen

  • Nur eine Core-Instanz. Das Schema-Setup läuft als Teil des Core-Starts und ist nicht für parallele Ausführung mehrerer Instanzen gegen dieselbe Datenbank ausgelegt. Wenn ihr Core horizontal skalieren wollt, sprecht uns vorher an, dann lösen wir das Schema-Setup als eigenen vorgelagerten Schritt.
  • Keine automatische Erreichbarkeitsprüfung zwischen Cluster und euren externen Systemen vor dem Deployment. Firewall- und Routing-Fragen zwischen Cluster und eurer Infrastruktur liegen in eurer Verantwortung.
  • Cores eigener REST-API-Schlüssel wird beim ersten Start automatisch erzeugt und liegt als Datei im Core-Pod, nicht als Kubernetes-Secret. Abrufbar per:
    kubectl exec -n idial deploy/idial -- cat /app/secrets/idial_api_key.txt