Kroxylicious im Einsatz: Datenvalidierung und End-to-End-Verschlüsselung für Apache Kafka

Garbage In, Garbage Out ist in Kafka ein echtes Problem. Konsumenten stürzen ab, wenn Producer Müll senden. Und wie steht es um die Datensicherheit in der Cloud? In diesem Artikel zeige ich dir, wie du mit dem Kafka-Proxy Kroxylicious deine Daten validierst und verschlüsselst – ohne deinen Anwendungscode anfassen zu müssen.

Dieser Artikel ist eine bearbeitete Fassung meines Vortrags auf der Kafka Utrecht Meetup 2026. Danke an Axual für das Hosting des Meetups und die Aufnahme.

Kafka ist fantastisch. Es ist schnell, skalierbar und zuverlässig. Aber Kafka hat auch zwei Eigenschaften, die dir das Leben schwer machen können: Kafka ist faul und Kafka ist alles egal.

Kafka betrachtet Nachrichten als reine Byte-Arrays. Es kümmert sich nicht darum, was in diesen Bytes steht. Das ist gut für die Performance, aber schlecht für die Datenqualität. Wenn ein Producer Müll sendet, bekommen deine Consumer diesen Müll auch ausgeliefert. Das Ergebnis sind abstürzende Consumer und lange Debugging-Sessions.

Und dann ist da noch das Thema Sicherheit. Wenn du Kafka in einer Public Cloud betreibst oder sensible Daten verarbeitest, reicht die Transportverschlüsselung oft nicht aus. Oft musst du sicherstellen, dass die Daten sauber verschlüsselt sind – und zwar so, dass nicht einmal der Cloud-Provider die Daten lesen kann.

Kroxylicious ist ein Kafka-Proxy
Figure 1. Kroxylicious ist ein Kafka-Proxy, der sich zwischen deine Clients und den Kafka-Cluster klemmt.

Hier kommt Kroxylicious ins Spiel. Kroxylicious ist ein Open-Source Kafka-Proxy, der sich zwischen deine Clients und den Kafka-Cluster klemmt. Er versteht das Kafka-Protokoll und kann Nachrichten analysieren, validieren und verändern.

In diesem Artikel schauen wir uns zwei konkrete Use Cases an:

  1. Record Validation: Wie du verhinderst, dass ungültige Daten überhaupt erst in deinen Cluster gelangen.

  2. Record Encryption: Wie du Daten transparent verschlüsselst, ohne dass deine Anwendungen komplexes Key Management implementieren müssen.

Kroxylicious installieren und starten

Bevor wir tief eintauchen, setzen wir uns eine kleine Testumgebung auf. Wenn du noch keine Kafka-Umgebung hast, lies unseren Kafka-Testumgebung einrichten Artikel.

Zuerst laden wir Kroxylicious herunter (wir verwenden hier Version 0.18.0, aber schau gerne auf auf der Projektseite nach der neuesten Version):

wget https://github.com/kroxylicious/kroxylicious/releases/download/v0.18.0/kroxylicious-app-0.18.0-bin.tar.gz
tar -xzf kroxylicious-app-0.18.0-bin.tar.gz
mv kroxylicious-app-0.18.0 kroxylicious
cd kroxylicious

Als Nächstes erstellen wir eine Konfigurationsdatei. Wir sagen Kroxylicious, dass es auf Port 9292 lauschen und alle Anfragen an unseren lokalen Kafka-Broker auf 9092 weiterleiten soll.

config.yaml
virtualClusters:
  - name: demo
    targetCluster:
      bootstrapServers: localhost:9092
    gateways:
    - name: mygateway
      portIdentifiesNode:
        bootstrapAddress: localhost:9292
        nodeIdRanges:
        - name: brokers
          start: 0
          end: 3
filterDefinitions: []

Achte darauf, dass deine nodeIdRanges zu deiner Kafka-Konfiguration passen. Wenn deine Broker-IDs bei 1 anfangen, passe start entsprechend an.

Jetzt starten wir den Proxy:

./bin/kroxylicious-start.sh --config config.yaml

Wenn alles geklappt hat, hast du jetzt einen Proxy laufen. Deine Kafka-Clients können sich nun entscheiden: Verbinden sie sich direkt mit Kafka (localhost:9092) oder gehen sie über Kroxylicious (localhost:9292).

Use Case 1: Nie wieder Poison Pills

Wenn du Müll produzierst
Figure 2. Wenn du Müll produzierst, bekommt der Consumer auch Müll.

Stell dir vor, du hast einen Producer, der JSON-Daten sendet. Ein anderes Team (Du ja nicht 😉) macht einen Fehler und der Producer sendet plötzlich invalides JSON.

Was passiert ohne Validierung?

  1. Kafka nimmt die Nachricht an (ist ja nur ein Byte-Array).

  2. Dein Consumer liest die Nachricht.

  3. Der JSON-Parser im Consumer wirft eine Exception.

  4. Der Consumer stürzt ab und bleibt in einer Retry-Schleife hängen.

Schema Registries sind eigentlich dazu da, dieses Problem zu lösen. Aber die Prüfungen passieren lediglich auf der Client-Seite. Ein fehlkonfigurierter Producer kann immer noch Müll produzieren.

Mit Kroxylicious können wir das verhindern. Wir konfigurieren einen Record Validation Filter, der sicherstellt, dass nur syntaktisch korrektes JSON im Topic wind-turbine-data landet.

Dazu passen wir die config.yaml an und fügen die Filter-Definition hinzu:

config.yaml
filterDefinitions:
- name: record-validation
  type: RecordValidation
  config:
    rules:
    - topicNames:
        - wind-turbine-data
      valueRule:
        syntacticallyCorrectJson:
          validateObjectKeysUnique: true
        allowNulls: true
        allowEmpty: false
defaultFilters:
- record-validation

Um das Beispiel einfach zu halten, prüfen wir lediglich ob das JSON syntaktisch korrekt ist. Natürlich unterstützt Kroxylicious auch Schema Validation. Aber dafür müssten wir eine Schema Registry einrichten und das wäre zu komplex für dieses Beispiel.

Kroxylicious kann fehlerhafte Schemas erkennen und weist schlechte Nachrichten zurück.
Figure 3. Kroxylicious kann fehlerhafte Schemas erkennen und weist schlechte Nachrichten zurück.

Nach einem Neustart von Kroxylicious passiert Folgendes, wenn ein Producer versucht, fehlerhaftes JSON zu senden:

echo "I am not a valid JSON" | kafka-console-producer.sh \
--bootstrap-server localhost:9292 --topic wind-turbine-data

Ergebnis:

org.apache.kafka.common.InvalidRecordException:
Value was invalid: value was not syntactically correct JSON:
Unrecognized token 'I': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')

Spannend: Das Kafka Protokoll kennt diese Fehlermeldung nicht. Aber es unterstützt das Zurückgeben von Text-Fehlermeldungen. Kroxylicious nutzt diese Möglichkeit.

Der Producer bekommt sofort eine Fehlermeldung (InvalidRecordException). Die Nachricht landet niemals im Kafka-Log. Dein Consumer läuft friedlich weiter, weil er nur saubere Daten bekommt.

Use Case 2: Verschlüsselung leicht gemacht

Verschlüsselung ist oft ein Albtraum. Client-seitige Verschlüsselung bedeutet, dass du dich um Key-Management, Rotation und die Verteilung von Schlüsseln an alle Teams kümmern musst. Wenn du das falsch machst, sind deine Daten entweder unsicher oder für immer verloren.

Kroxylicious kann als Encryption-Gateway fungieren. Es nutzt Envelope Encryption und integriert sich mit Key Management Systemen wie HashiCorp Vault, AWS KMS oder Azure Key Vault.

Für dieses Beispiel nutzen wir HashiCorp Vault im Dev-Modus (bitte nicht in Produktion so machen!).

Vault starten

wget https://releases.hashicorp.com/vault/1.18.0/vault_1.18.0_linux_amd64.zip
unzip vault_1.18.0_linux_amd64.zip
./vault server -dev

Transit Engine aktivieren und Keys erstellen

Wir müssen Vault so konfigurieren, dass Kroxylicious Schlüssel erstellen und nutzen darf. (Die genauen Policies und Befehle findest du in der Kroxylicious-Dokumentation, aber im Wesentlichen erlauben wir Operationen auf dem Pfad transit/keys/KEK_*).

Transit Engine aktivieren
export VAULT_ADDR='http://127.0.0.1:8200'
./vault secrets enable transit

Dann erstellen wir eine Policy (Berechtigungen) für Kroxylicious:

kroxylicious_encryption_filter_policy.hcl
path "transit/keys/KEK_*" {
  capabilities = ["read"]
}
path "/transit/datakey/plaintext/KEK_*" {
  capabilities = ["update"]
}
path "transit/decrypt/KEK_*" {
  capabilities = ["update"]
}

Und wenden wir die Policy an:

./vault policy write kroxylicious_encryption_filter_policy kroxylicious_encryption_filter_policy.hcl

Und schlussendlich erstellen wir einen Token für Kroxylicious:

./vault token create -display-name "kroxylicious record encryption" \
-policy=kroxylicious_encryption_filter_policy \
-period=768h \
-no-default-policy \
-orphan \
-format=json | jq -r .auth.client_token > kroxylicious-encryption-token

Key Encryption Key erstellen

Für jedes Topic, das wir verschlüsseln wollen, müssen wir einen Key Encryption Key (KEK) erstellen:

./vault write -f transit/keys/KEK_my_encrypted_topic type=aes256-gcm96 auto_rotate_period=90d

Kroxylicious konfigurieren

Wir fügen den RecordEncryption Filter hinzu.

config.yaml
filterDefinitions:
- type: RecordEncryption
  name: record-encryption
  config:
    kms: VaultKmsService
    kmsConfig:
      vaultTransitEngineUrl: http://localhost:8200/v1/transit
      vaultToken:
        passwordFile: /path/to/kroxylicious-encryption-token
    selector: TemplateKekSelector
    selectorConfig:
      template: "KEK_${topicName}" # Wenn das Topic `my_encrypted_topic` heißt, wollen wir den KEK `KEK_my_encrypted_topic` benennen.
defaultFilters:
  - record-encryption
Nachrichtenverschlüsselung an einen Proxy auszulagern hilft uns unseren Code einfach zu halten.
Figure 4. Nachrichtenverschlüsselung an einen Proxy auszulagern hilft uns unseren Code einfach zu halten.

Was passiert jetzt?

  • Dein Producer sendet Klartext an Kroxylicious (localhost:9292).

  • Kroxylicious verschlüsselt den Inhalt der Nachricht (Value), bevor er sie an Kafka (localhost:9092) weiterleitet.

  • Dein Consumer, der über Kroxylicious liest, bekommt die Daten automatisch entschlüsselt zurück.

Der Clou: Wenn du (oder ein Angreifer) direkt auf dem Kafka-Broker (localhost:9092) lauschst, siehst du nur Datensalat:

kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my_encrypted_topic --from-beginning
CAC_my_encrypted_topic......

Damit sind deine Daten At Rest im Kafka-Cluster sicher verschlüsselt. Der Kafka-Broker selbst sieht nie den Klartext.

Ist das nun Ende-zu-Ende Verschlüsselung oder nicht?

Das kommt drauf an. Wenn Kroxylicious unter der Kontrolle des Producers steht, würde ich es als Ende-zu-Ende Verschlüsselung bezeichnen. Wenn Kroxylicious vom Kafka Team betrieben wird, ist das lediglich at-rest Verschlüsselung, denn das Kafka-Team könnte die Daten entschlüsseln, wenn es wöllte, aber wenn Kafka in der Cloud betrieben würde, könnte der Cloud-Provider die Daten nicht lesen.

Fazit

Kroxylicious erlaubt uns serverseitige Funktionen zu benutzen und zu implementieren, die Apache Kafka selbst nicht unterstützt. Der Preis dafür ist ein zusätzlicher Hop im Netzwerk und ein potenzieller Single Point of Failure.

Insbesondere bei erhöhten Sicherheitsanforderungen ist es sinnvoll, Verschlüsselung nicht selbst zu implementieren, sondern diese Funktionalität an eine getestete Software auszulagern.

Auch für die Kommunikation mit externen Partnern kann Kroxylicious eine sinnvolle Lösung sein. So können wir sicherstellen, dass die Daten immer im korrekten Format bei uns ankommen.

Tipp: Bevor du Kroxylicious einsetzt, prüfe bitte, ob du es wirklich benötigst. Es ist keine Lösung für alle Probleme.

Über Anatoly Zelenin
Hallo, ich bin Anatoly! Ich liebe es, bei Menschen das Funkeln in den Augen zu wecken. Als Apache Kafka Experte und Buchautor bringe ich seit über einem Jahrzehnt IT zum Leben - mit Leidenschaft statt Langeweile, mit Erlebnissen statt endlosen Folien.

Weiterlesen

article-image
Kafka: Wie du Datenverlust beim Produzieren garantiert vermeidest

Du willst sicherstellen, dass keine einzige Kafka-Nachricht verloren geht? In diesem Guide zeige ich dir, wie du mit den richtigen Konfigurationen eine maximale Zuverlässigkeit beim Produzieren erreichst und was du im Fehlerfall tun musst.

Mehr lesen
article-image
Schema Management in Kafka

In diesem Post erfährst du, wie explizite Schemas, dir dabei helfen, ein mögliches Chaos in Kafka zu vermeiden und wie die Schema Registries dabei unterstützen.

Mehr lesen