Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
kafka-keycloak-oauth — Apache Kafka 4.1.0 (KRaft) avec authentification Keycloak OAuth2 utilisant Strimzi - contourne la restriction de la liste blanche d'URL CVE-2025-27817 | Kitploit
Outils/GitHubGitHub/oriolrius/kafka-keycloak-oauth
Sécurité de l'Infrastructure CloudAnalyse des VulnérabilitésAudit de ConfigurationDevSecOpsAuthentificationApprentissage et Éducation
GitHuboriolrius/kafka-keycloak-oauth

kafka-keycloak-oauth

Apache Kafka 4.1.0 (KRaft) avec authentification Keycloak OAuth2 utilisant Strimzi - contourne la restriction de la liste blanche d'URL CVE-2025-27817

Voir le dépôt
53il y a 10 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Apache Kafka 4.1.0 avec authentification OAuth2 Keycloak

Apache Kafka 4.1.0 prêt pour la production (mode KRaft) avec authentification OAuth2/OIDC Keycloak 26.1.1 utilisant l'image Kafka Strimzi.

Pourquoi ce projet vs kafka-oauth-keycloak-tls-demo

Il s'agit d'une évolution du POC précédent avec des améliorations significatives :

  • Strimzi OAuth 0.17.0 (vs 1.0.0) - version de production stable incluse dans l'image Strimzi Kafka 0.48.0
  • Aucune construction Docker personnalisée requise - utilise l'image Strimzi officielle avec OAuth pré-installé, élimine la complexité du Dockerfile
  • Conscience de CVE-2025-27817 - documente la restriction de la liste blanche d'URL et pourquoi Strimzi OAuth la contourne
  • Architecture simplifiée - mode combiné KRaft unique (broker+controller), pas d'architecture divisée
  • Focus client librdkafka - testé avec confluent-kafka-python (fonctionne sans problèmes de liste blanche d'URL), pas les clients Java natifs
  • Documentation technique complète - liste de contrôle de production, dépannage, réglage des performances, détails du mappage principal
  • Gestion des certificats plus propre - certificats d'exemple inclus pour des tests immédiats
  • Configuration Keycloak automatisée - création scriptée du realm/client/mapper avec configuration d'audience
  • Suite de tests Python fonctionnelle - valide la livraison de messages OAuth de bout en bout
  • Gestion explicite de l'URL de l'émetteur - documente la dualité URL interne vs externe pour le point de terminaison du jeton vs la validation de l'émetteur
  • Architecture

    • Distribution Kafka : Image Strimzi Kafka 0.48.0 (inclut Apache Kafka 4.1.0 + Strimzi OAuth 0.17.0 pré-inclus)
    • Version Kafka : Apache Kafka 4.1.0 (KRaft combiné broker+controller)
    • Bibliothèque OAuth : Strimzi Kafka OAuth 0.17.0 (inclus dans l'image, contourne la restriction de liste blanche d'URL CVE-2025-27817)
    • Fournisseur OAuth : Keycloak 26.1.1
    • Sécurité : SASL_SSL (OAuth) pour les clients externes, PLAINTEXT pour inter-broker, SSL avec CA auto-signé

    Contexte CVE-2025-27817

    Apache Kafka 4.0.0+ a introduit une liste blanche d'URL (org.apache.kafka.sasl.oauthbearer.allowed.urls) comme propriété système JVM pour corriger la vulnérabilité SSRF/lecture de fichier arbitraire. Cela casse l'utilisation OAuth standard dans les clients Apache Kafka natifs.

    Solution : La bibliothèque Strimzi Kafka OAuth n'implémente pas cette restriction, permettant la fonctionnalité OAuth avec Kafka 4.1.0.

    Prérequis

    • Docker Compose
    • Python 3.x avec uv (pour les tests)
    • OpenSSL (pour la génération de certificats)

    Démarrage rapide

    root@kitploit:~
    # Générer les certificats SSL
    cd kafka-security
    ./generate-certs.sh
    cd ..
    
    # Démarrer les services
    docker compose up -d
    
    # Vérifier Keycloak
    curl http://localhost:8080/health/ready
    
    # Configurer le realm et les clients Keycloak
    ./scripts/setup-keycloak.sh
    
    # Tester le producteur OAuth
    source ~/.venv/bin/activate
    uv pip install confluent-kafka
    python tests/quick_test.py
    

    Topologie réseau

    root@kitploit:~
    keycloak:8080 (HTTP) ←→ kafka-broker:9093 (SASL_SSL/OAuth)
                          ↔ kafka-broker:19092 (PLAINTEXT/inter-broker)
                          ↔ kafka-broker:29093 (PLAINTEXT/contrôleur KRaft)
    

    Configuration SSL

    Structure CA

    • CA racine : kafka-security/ca-cert + ca-key
    • Keystore du broker : kafka-security/broker/kafka.server.keystore.jks (contient le certificat serveur + la clé privée)
    • Truststore du broker : kafka-security/broker/kafka.server.truststore.jks (contient le certificat CA)
    • Mot de passe : changeit (tous les keystores/truststores)

    Détails du certificat

    root@kitploit:~
    # Certificat du broker
    CN=kafka-broker
    SAN=DNS:kafka-broker,DNS:localhost,IP:127.0.0.1
    
    # Validité : 3650 jours
    # Algorithme de clé : RSA 2048 bits
    # Algorithme de signature : SHA256withRSA
    

    Configuration OAuth Keycloak

    Realm : kafka-realm

    Clients

    kafka-broker (confidentiel)

    • ID client : kafka-broker
    • Secret client : Généré automatiquement par setup-keycloak.sh
    • Objectif : Authentification OAuth inter-broker
    • Mappers :
      • Mapper d'audience : ajoute kafka-broker à la revendication aud du JWT
      • Mapper de nom d'utilisateur : inclut preferred_username dans le jeton

    kafka-producer (confidentiel)

    • ID client : kafka-producer
    • Secret client : Généré automatiquement
    • Objectif : Clients producteurs externes
    • Grant : client_credentials
    • Mappers : Identiques à kafka-broker

    kafka-consumer (confidentiel)

    • ID client : kafka-consumer
    • Secret client : Généré automatiquement
    • Objectif : Clients consommateurs externes
    • Grant : client_credentials
    • Mappers : Identiques à kafka-broker

    Point de terminaison du jeton

    root@kitploit:~
    POST http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials
    &client_id=kafka-producer
    &client_secret=<secret>
    &scope=profile email
    

    Structure du jeton JWT

    root@kitploit:~
    {
      "aud": ["kafka-broker", "account"],
      "iss": "http://localhost:8080/realms/kafka-realm",
      "azp": "kafka-producer",
      "preferred_username": "service-account-kafka-producer",
      "scope": "profile email"
    }
    

    Configuration Kafka

    Mode KRaft (kraft-config.properties)

    root@kitploit:~
    # Identité du nœud
    node.id=1
    process.roles=broker,controller
    controller.quorum.voters=1@kafka-broker:29093
    
    # Écouteurs
    listeners=SASL_SSL://0.0.0.0:9093,PLAINTEXT://0.0.0.0:19092,CONTROLLER://0.0.0.0:29093
    advertised.listeners=SASL_SSL://localhost:9093,PLAINTEXT://kafka-broker:19092
    listener.security.protocol.map=SASL_SSL:SASL_SSL,PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
    inter.broker.listener.name=PLAINTEXT
    controller.listener.names=CONTROLLER
    
    # Mécanisme SASL
    sasl.enabled.mechanisms=OAUTHBEARER
    
    # Gestionnaires Strimzi OAuth (par écouteur pour SASL_SSL)
    listener.name.sasl_ssl.oauthbearer.sasl.login.callback.handler.class=io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler
    listener.name.sasl_ssl.oauthbearer.sasl.server.callback.handler.class=io.strimzi.kafka.oauth.server.JaasServerOauthValidatorCallbackHandler
    
    # Configuration OAuth via JAAS
    listener.name.sasl_ssl.oauthbearer.sasl.jaas.config=org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \
      oauth.client.id="kafka-broker" \
      oauth.client.secret="<secret>" \
      oauth.token.endpoint.uri="http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/token" \
      oauth.valid.issuer.uri="http://localhost:8080/realms/kafka-realm" \
      oauth.jwks.endpoint.uri="http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/certs" \
      oauth.username.claim="preferred_username";
    

    Paramètres clés Strimzi OAuth

    • oauth.client.id : Identifiant client pour l'acquisition de jeton
    • oauth.client.secret : Secret client pour l'acquisition de jeton
    • oauth.token.endpoint.uri : Point de terminaison du jeton Keycloak (le broker utilise le nom d'hôte interne keycloak:8080)
    • oauth.valid.issuer.uri : Émetteur JWT attendu (doit correspondre à la revendication iss du jeton, utilise localhost:8080 externe)
    • oauth.jwks.endpoint.uri : Point de terminaison JWKS pour la validation de signature JWT
    • oauth.username.claim : Revendication JWT pour l'extraction du principal

    Autorisation

    root@kitploit:~
    authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
    super.users=User:kafka-broker;User:ANONYMOUS
    allow.everyone.if.no.acl.found=true
    

    Remarque : Actuellement permissif pour les tests. La production devrait utiliser des ACL.

    Configuration client

    Producteur Python (confluent-kafka)

    root@kitploit:~
    from confluent_kafka import Producer
    
    conf = {
        'bootstrap.servers': 'localhost:9093',
        'security.protocol': 'SASL_SSL',
        'sasl.mechanisms': 'OAUTHBEARER',
        'sasl.oauthbearer.method': 'oidc',
        'sasl.oauthbearer.client.id': 'kafka-producer',
        'sasl.oauthbearer.client.secret': '<secret>',
        'sasl.oauthbearer.token.endpoint.url': 'http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token',
        'ssl.ca.location': 'kafka-security/ca-cert',
        'ssl.endpoint.identification.algorithm': 'none',
    }
    
    producer = Producer(conf)
    producer.produce('topic', b'message')
    producer.flush()
    

    Consommateur Python (confluent-kafka)

    root@kitploit:~
    from confluent_kafka import Consumer
    
    conf = {
        'bootstrap.servers': 'localhost:9093',
        'group.id': 'test-group',
        'security.protocol': 'SASL_SSL',
        'sasl.mechanisms': 'OAUTHBEARER',
        'sasl.oauthbearer.method': 'oidc',
        'sasl.oauthbearer.client.id': 'kafka-consumer',
        'sasl.oauthbearer.client.secret': '<secret>',
        'sasl.oauthbearer.token.endpoint.url': 'http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token',
        'ssl.ca.location': 'kafka-security/ca-cert',
        'ssl.endpoint.identification.algorithm': 'none',
        'auto.offset.reset': 'earliest',
    }
    
    consumer = Consumer(conf)
    consumer.subscribe(['topic'])
    while True:
        msg = consumer.poll(1.0)
        if msg: print(msg.value())
    

    Pourquoi librdkafka fonctionne

    confluent-kafka-python utilise librdkafka (bibliothèque C) qui implémente OAuth via sasl.oauthbearer.method=oidc. Cette implémentation ne vérifie pas la propriété système org.apache.kafka.sasl.oauthbearer.allowed.urls qui bloque les clients Java Apache Kafka natifs.

    Dépannage

    Vérifier le jeton OAuth

    root@kitploit:~
    TOKEN=$(curl -s -X POST http://localhost:8080/realms/kafka-realm/protocol/openid-connect/token \
      -d "grant_type=client_credentials" \
      -d "client_id=kafka-producer" \
      -d "client_secret=<secret>" | jq -r .access_token)
    
    echo $TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | jq .
    

    Revendications attendues :

    root@kitploit:~
    {
      "aud": ["kafka-broker", "account"],
      "iss": "http://localhost:8080/realms/kafka-realm",
      "azp": "kafka-producer",
      "preferred_username": "service-account-kafka-producer"
    }
    

    Vérifier les journaux OAuth du broker

    root@kitploit:~
    docker logs kafka-broker 2>&1 | grep -E "Strimzi|JWTSignatureValidator|OAUTHBEARER"
    

    Attendu :

    root@kitploit:~
    [io.strimzi.kafka.oauth.validator.JWTSignatureValidator] JWKS keys change detected
    

    Vérifier les écouteurs du broker

    root@kitploit:~
    docker exec kafka-broker netstat -tlnp | grep java
    

    Attendu :

    root@kitploit:~
    tcp6  0.0.0.0:9093   LISTEN  (SASL_SSL)
    tcp6  0.0.0.0:19092  LISTEN  (PLAINTEXT)
    tcp6  0.0.0.0:29093  LISTEN  (CONTROLLER)
    

    Vérifier les métadonnées KRaft

    root@kitploit:~
    docker exec kafka-broker cat /var/lib/kafka/data/meta.properties
    

    Attendu :

    root@kitploit:~
    version=1
    cluster.id=kafka-cluster-01
    node.id=1
    

    Problèmes courants

    Problème : {"status":"invalid_token"}

    • Cause : Échec de validation de signature JWT
    • Correctif : Vérifier que oauth.jwks.endpoint.uri est accessible depuis le conteneur du broker
    • Vérification : docker exec kafka-broker curl http://keycloak:8080/realms/kafka-realm/protocol/openid-connect/certs

    Problème : Token audience mismatch

    • Cause : La revendication aud du JWT ne contient pas kafka-broker
    • Correctif : Exécuter ./scripts/setup-keycloak.sh pour ajouter le mapper d'audience
    • Vérification : Décoder le jeton et vérifier que la revendication aud inclut kafka-broker

    Problème : Token issuer mismatch

    • Cause : Le iss du JWT ne correspond pas à oauth.valid.issuer.uri
    • Correctif : S'assurer que oauth.valid.issuer.uri=http://localhost:8080/realms/kafka-realm (nom d'hôte externe)
    • Remarque : Le broker utilise http://keycloak:8080 pour le point de terminaison du jeton mais valide contre l'émetteur http://localhost:8080

    Problème : Les clients Java Kafka natifs échouent avec une erreur de liste blanche d'URL

    • Cause : Correctif CVE-2025-27817 dans Apache Kafka 4.1.0
    • Correctif : Utiliser des clients basés sur librdkafka (confluent-kafka-python) ou Strimzi OAuth côté broker (déjà configuré)

    Réglage des performances

    Actualisation du jeton

    Les jetons JWT de Keycloak ont une expiration de 5 minutes. Strimzi OAuth gère automatiquement l'actualisation :

    • oauth.refresh.token : Non utilisé (grant client_credentials)
    • Jeton mis en cache et actualisé 30 s avant l'expiration

    Mise en cache JWKS

    root@kitploit:~
    sasl.oauthbearer.jwks.endpoint.refresh.ms=3600000  # 1 heure
    sasl.oauthbearer.jwks.endpoint.retry.backoff.ms=100
    sasl.oauthbearer.jwks.endpoint.retry.backoff.max.ms=10000
    

    Paramètres de connexion

    root@kitploit:~
    connections.max.idle.ms=600000
    connection.failed.authentication.delay.ms=1000
    

    Liste de contrôle de production

    • Remplacer les certificats auto-signés par des certificats signés par une CA
    • Mettre à jour ssl.endpoint.identification.algorithm=https (supprimer none)
    • Configurer des ACL appropriées (supprimer allow.everyone.if.no.acl.found=true)
    • Configurer les ACL :
      root@kitploit:~
      kafka-acls --bootstrap-server localhost:9093 \
        --command-config admin.properties \
        --add --allow-principal User:kafka-producer \
        --operation Write --topic '*'
      
    • Faire pivoter les secrets des clients Keycloak
    • Activer HTTPS Keycloak
    • Mettre à jour oauth.token.endpoint.uri et oauth.jwks.endpoint.uri vers des URL HTTPS
    • Configurer la surveillance Kafka (JMX, Prometheus)
    • Configurer l'agrégation de journaux pour la piste d'audit OAuth
    • Tester les scénarios de basculement
    • Documenter les procédures de rotation des secrets
    • Activer la fédération d'utilisateurs Keycloak (LDAP/AD) si nécessaire

    Structure du répertoire

    root@kitploit:~
    .
    ├── docker-compose.yml              # Orchestration
    ├── .env                            # Secrets (gitignored)
    ├── kafka-config/
    │   ├── kraft-config.properties     # Configuration du broker Kafka
    │   ├── producer.properties         # Config OAuth producteur (pour outils CLI)
    │   └── consumer.properties         # Config OAuth consommateur (pour outils CLI)
    ├── kafka-security/
    │   ├── generate-certs.sh           # Générateur de certificats SSL
    │   ├── ca-cert                     # Certificat CA racine
    │   ├── ca-key                      # Clé privée CA racine
    │   └── broker/
    │       ├── kafka.server.keystore.jks
    │       └── kafka.server.truststore.jks
    ├── scripts/
    │   └── setup-keycloak.sh           # Configuration realm/client Keycloak
    └── tests/
        └── quick_test.py               # Test de validation OAuth
    
    

    Notes techniques

    Pourquoi l'image Strimzi Kafka au lieu de l'image officielle Apache Kafka

    L'image Strimzi Kafka (quay.io/strimzi/kafka:0.48.0-kafka-4.1.0) est utilisée au lieu de l'image officielle Apache Kafka car :

    1. Support OAuth intégré : Inclut la bibliothèque Strimzi OAuth 0.17.0 pré-installée (classes : io.strimzi.kafka.oauth.*)
    2. Contournement CVE-2025-27817 : La bibliothèque Strimzi OAuth n'implémente pas la restriction de liste blanche d'URL qui casse l'OAuth Kafka natif
    3. Prêt pour la production : Éprouvé dans les environnements Kubernetes via l'opérateur Strimzi
    4. Image unique : Pas besoin de télécharger et monter manuellement les fichiers JAR OAuth

    Décomposition de l'image :

    • Strimzi Kafka 0.48.0 = Version/version de l'image Docker
    • Apache Kafka 4.1.0 = Version du broker Kafka inclus à l'intérieur
    • Strimzi OAuth 0.17.0 = Version de la bibliothèque OAuth incluse à l'intérieur

    Dualité de l'URL de l'émetteur

    La configuration du broker a deux URL :

    • oauth.token.endpoint.uri=http://keycloak:8080/... (réseau Docker interne)
    • oauth.valid.issuer.uri=http://localhost:8080/... (externe, correspond à la revendication iss du JWT)

    Cela est dû au fait que :

    • Le broker récupère les jetons en utilisant le nom DNS interne
    • Keycloak émet des jetons avec l'URL de l'émetteur externe (configurée dans les paramètres du realm)
    • La validation JWT nécessite une correspondance exacte de l'émetteur

    Mappage du principal

    Le broker extrait le principal de la revendication preferred_username du JWT :

    root@kitploit:~
    service-account-kafka-producer → User:service-account-kafka-producer
    

    Les ACL référencent ce principal pour l'autorisation.

    Compatibilité des versions

    ComposantVersionRemarques
    Apache Kafka4.1.0Mode KRaft (pas de ZooKeeper)
    Image Strimzi Kafka0.48.0Image Docker : quay.io/strimzi/kafka:0.48.0-kafka-4.1.0
    Bibliothèque Strimzi OAuth0.17.0Pré-incluse dans l'image Strimzi Kafka 0.48.0
    Keycloak26.1.1Dernière LTS
    librdkafka2.12.0+Support OAuth OIDC
    confluent-kafka-python2.12.0+Correspond à la version librdkafka

    Références

    • Strimzi Kafka OAuth
    • Sécurité Apache Kafka
    • Keycloak OIDC
    • CVE-2025-27817
    • Mode KRaft
    Télécharger l’outil