
Apache Kafka 4.1.0 (KRaft) Keycloak OAuth2 प्रमाणीकरण के साथ Strimzi का उपयोग करते हुए - CVE-2025-27817 URL अनुमति-सूची प्रतिबंध को बायपास करता है
प्रोडक्शन-रेडी Apache Kafka 4.1.0 (KRaft मोड) Keycloak 26.1.1 OAuth2/OIDC प्रमाणीकरण के साथ, Strimzi Kafka इमेज का उपयोग करते हुए।
यह पिछले POC का विकास है जिसमें महत्वपूर्ण सुधार हैं:
Apache Kafka 4.0.0+ ने SSRF/मनमाना फ़ाइल पढ़ने की भेद्यता को ठीक करने के लिए URL allowlist (org.apache.kafka.sasl.oauthbearer.allowed.urls) को JVM सिस्टम प्रॉपर्टी के रूप में पेश किया। यह नेटिव Apache Kafka क्लाइंट में मानक OAuth उपयोग को तोड़ देता है।
समाधान: Strimzi Kafka OAuth लाइब्रेरी इस प्रतिबंध को लागू नहीं करती है, जिससे Kafka 4.1.0 के साथ OAuth कार्यक्षमता सक्षम होती है।
# SSL प्रमाणपत्र उत्पन्न करें
cd kafka-security
./generate-certs.sh
cd ..
# सेवाएँ प्रारंभ करें
docker compose up -d
# Keycloak सत्यापित करें
curl http://localhost:8080/health/ready
# Keycloak realm और क्लाइंट सेटअप करें
./scripts/setup-keycloak.sh
# OAuth प्रोड्यूसर का परीक्षण करें
source ~/.venv/bin/activate
uv pip install confluent-kafka
python tests/quick_test.py
keycloak:8080 (HTTP) ←→ kafka-broker:9093 (SASL_SSL/OAuth)
↔ kafka-broker:19092 (PLAINTEXT/inter-broker)
↔ kafka-broker:29093 (PLAINTEXT/KRaft controller)
kafka-security/ca-cert + ca-keykafka-security/broker/kafka.server.keystore.jks (सर्वर प्रमाणपत्र + निजी कुंजी शामिल)kafka-security/broker/kafka.server.truststore.jks (CA प्रमाणपत्र शामिल)changeit (सभी keystores/truststores)# Broker प्रमाणपत्र
CN=kafka-broker
SAN=DNS:kafka-broker,DNS:localhost,IP:127.0.0.1
# वैधता: 3650 दिन
# कुंजी एल्गोरिथ्म: RSA 2048-बिट
# हस्ताक्षर एल्गोरिथ्म: SHA256withRSA
kafka-broker (confidential)
kafka-brokersetup-keycloak.sh द्वारा स्वतः-जनितaud दावे में kafka-broker जोड़ता हैpreferred_username शामिल करता हैkafka-producer (confidential)
kafka-producerclient_credentialskafka-consumer (confidential)
kafka-consumerclient_credentialsPOST 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
{
"aud": ["kafka-broker", "account"],
"iss": "http://localhost:8080/realms/kafka-realm",
"azp": "kafka-producer",
"preferred_username": "service-account-kafka-producer",
"scope": "profile email"
}
# नोड पहचान
node.id=1
process.roles=broker,controller
controller.quorum.voters=1@kafka-broker:29093
# Listeners
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
# SASL तंत्र
sasl.enabled.mechanisms=OAUTHBEARER
# Strimzi OAuth हैंडलर (SASL_SSL के लिए प्रति-listener)
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
# JAAS के माध्यम से OAuth कॉन्फ़िगरेशन
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";
oauth.client.id: टोकन अधिग्रहण के लिए क्लाइंट पहचानकर्ताoauth.client.secret: टोकन अधिग्रहण के लिए क्लाइंट सीक्रेटoauth.token.endpoint.uri: Keycloak टोकन एंडपॉइंट (broker आंतरिक होस्टनाम keycloak:8080 का उपयोग करता है)oauth.valid.issuer.uri: अपेक्षित JWT issuer (टोकन iss दावे से मेल खाना चाहिए, बाहरी localhost:8080 का उपयोग करता है)oauth.jwks.endpoint.uri: JWT हस्ताक्षर सत्यापन के लिए JWKS एंडपॉइंटoauth.username.claim: principal निष्कर्षण के लिए JWT दावाauthorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
super.users=User:kafka-broker;User:ANONYMOUS
allow.everyone.if.no.acl.found=true
नोट: वर्तमान में परीक्षण के लिए अनुमेय। प्रोडक्शन को ACL का उपयोग करना चाहिए।
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()
from confluent_kafka import Consumer