You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Compose中Kafka Broker的SSL握手失败问题排查与修复

终极目标

研究Kafka与OPA插件的集成方式,以及生产环境中OPA插件的使用便捷性。

操作步骤

遵循OPA官方教程配置,目前卡在Docker Compose环境下Broker无法正常工作,无法识别localhost。

我的docker-compose.yaml配置:

services:
  nginx:
    image: nginx:1.21.4
    volumes:
      - "./bundles:/usr/share/nginx/html"
    ports:
      - "80:80"
  opa:
    image: openpolicyagent/opa:0.51.0
    ports:
      - "8181:8181"
    command:
      - "run"
      - "--server"
      - "--set=decision_logs.console=true"
      - "--set=services.authz.url=http://nginx"
      - "--set=bundles.authz.service=authz"
      - "--set=bundles.authz.resource=bundle.tar.gz"
    depends_on:
      - nginx
  zookeeper:
    image: confluentinc/cp-zookeeper:6.2.1
    ports:
      - "2181:2181"
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
      - ZOOKEEPER_CLIENT_PORT=2181
  broker:
    image: confluentinc/cp-kafka:6.2.1
    ports:
      - "9093:9093"
    environment:
      # Set cache expiry to low value for development in order to see decisions
      KAFKA_OPA_AUTHORIZER_CACHE_EXPIRE_AFTER_SECONDS: 10
      KAFKA_OPA_AUTHORIZER_URL: http://opa:8181/v1/data/kafka/authz/allow
      KAFKA_AUTHORIZER_CLASS_NAME: org.openpolicyagent.kafka.OpaAuthorizer
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
      KAFKA_ADVERTISED_LISTENERS: SSL://localhost:9093
      KAFKA_SECURITY_INTER_BROKER_PROTOCOL: SSL
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
      KAFKA_SSL_KEYSTORE_FILENAME: server.keystore
      KAFKA_SSL_KEYSTORE_CREDENTIALS: credentials.txt
      KAFKA_SSL_KEY_CREDENTIALS: credentials.txt
      KAFKA_SSL_TRUSTSTORE_FILENAME: server.truststore
      KAFKA_SSL_TRUSTSTORE_CREDENTIALS: credentials.txt
      KAFKA_SSL_CLIENT_AUTH: required
      # KAFKA_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
      # KAFKA_PRODUCER_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
      # KAFKA_CONSUMER_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
      CLASSPATH: "/plugin/*"
    volumes:
      - "./plugin:/plugin"
      - "./cert/server:/etc/kafka/secrets"
    depends_on:
      - opa
      - zookeeper

文件夹结构与教程一致,已生成证书等文件。

错误信息

broker_1     | [2023-04-27 08:40:46,391] INFO [Controller id=1, targetBrokerId=1] Failed authentication with localhost/127.0.0.1 (SSL handshake failed) (org.apache.kafka.common.network.Selector)
broker_1     | [2023-04-27 08:40:46,392] ERROR [Controller id=1, targetBrokerId=1] Connection to node 1 (localhost/127.0.0.1:9093) failed authentication due to: SSL handshake failed (org.apache.kafka.clients.NetworkClient)
broker_1     | [2023-04-27 08:40:46,393] WARN [RequestSendThread controllerId=1] Controller 1's connection to broker localhost:9093 (id: 1 rack: null) was unsuccessful (kafka.controller.RequestSendThread)
broker_1     | org.apache.kafka.common.errors.SslAuthenticationException: SSL handshake failed
broker_1     | Caused by: javax.net.ssl.SSLHandshakeException: No name matching localhost found
broker_1     |  at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
broker_1     |  at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:349)
broker_1     |  at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
broker_1     |  at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:287)
broker_1     |  at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357)
broker_1     |  at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232)
broker_1     |  at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175)
broker_1     |  at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
broker_1     |  at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
broker_1     |  at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
broker_1     |  at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
broker_1     |  at java.base/java.security.AccessController.doPrivileged(Native Method)
broker_1     |  at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
broker_1     |  at org.apache.kafka.common.network.SslTransportLayer.runDelegatedTasks(SslTransportLayer.java:430)
broker_1     |  at org.apache.kafka.common.network.SslTransportLayer.handshakeUnwrap(SslTransportLayer.java:514)
broker_1     |  at org.apache.kafka.common.network.SslTransportLayer.doHandshake(SslTransportLayer.java:368)
broker_1     |  at org.apache.kafka.common.network.SslTransportLayer.handshake(SslTransportLayer.java:291)
broker_1     |  at org.apache.kafka.common.network.KafkaChannel.prepare(KafkaChannel.java:178)
broker_1     |  at org.apache.kafka.common.network.Selector.pollSelectionKeys(Selector.java:543)
broker_1     |  at org.apache.kafka.common.network.Selector.poll(Selector.java:481)
broker_1     |  at org.apache.kafka.clients.NetworkClient.poll(NetworkClient.java:561)
broker_1     |  at org.apache.kafka.clients.NetworkClientUtils.awaitReady(NetworkClientUtils.java:74)
broker_1     |  at kafka.controller.RequestSendThread.brokerReady(ControllerChannelManager.scala:292)
broker_1     |  at kafka.controller.RequestSendThread.doWork(ControllerChannelManager.scala:246)
broker_1     |  at kafka.utils.ShutdownableThread.run(ShutdownableThread.scala:96)
broker_1     | Caused by: java.security.cert.CertificateException: No name matching localhost found
broker_1     |  at java.base/sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:234)
broker_1     |  at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:103)
broker_1     |  at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
broker_1     |  at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:429)
broker_1     |  at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:283)
broker_1     |  at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141)
broker_1     |  at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1335)
broker_1     |  ... 20 more

调试步骤

  • 尝试禁用SSL端点识别配置:
    KAFKA_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
    KAFKA_PRODUCER_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
    KAFKA_CONSUMER_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""
    
    结果:消息无法确认,Broker无法访问。
  • 尝试将localhost替换为internal.docker.host和0.0.0.0:
    • 使用internal.docker.host时出现相同错误
    • 使用0.0.0.0无法路由

已查找其他解决方案,可用信息有限,多集中在上述两种方法;版本变更也无济于事,Kafka新版本的Docker Compose配置需调整(如Zookeeper已被弃用)。

机器信息

  • Docker引擎:colima(Docker官方引擎替代方案)
  • 操作系统:MacOS

问题

如何修复当前问题?是否有其他更常见、易修复的方案?


解决方案

1. 修复Kafka证书的主机名匹配问题

错误核心是SSL证书中未包含localhost和容器内部服务名broker的标识。重新生成证书时,需在证书的**Subject Alternative Name (SAN)**中添加这两个主机名:

  • 生成证书请求时,添加-ext SAN=DNS:localhost,DNS:broker参数(具体命令根据证书生成工具调整)
  • 确保证书的Common Name (CN)至少包含其中一个主机名,优先用SAN覆盖多场景

2. 调整Kafka监听配置,区分内部/外部通信

当前KAFKA_ADVERTISED_LISTENERS仅配置了localhost,导致Broker内部控制器通信也尝试用localhost访问,而容器内部localhost指向自身,引发证书匹配冲突。修改为双监听配置:

KAFKA_LISTENERS: SSL://0.0.0.0:9093,SSL://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: SSL://localhost:9093,SSL://broker:9092
KAFKA_SECURITY_INTER_BROKER_PROTOCOL: SSL
  • 9093端口用于外部(Mac主机)访问,对应localhost
  • 9092端口用于容器内部(控制器、OPA等组件)访问,对应服务名broker
  • 内部通信将使用broker主机名,与证书中的SAN匹配,避免localhost的证书验证问题

3. 正确配置SSL端点识别(可选)

若暂时无法重新生成证书,可启用禁用SSL端点识别的配置,但需保证所有相关组件配置一致:

KAFKA_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM: ""

注意:仅建议在开发环境使用此配置,生产环境必须保证证书与主机名严格匹配。

4. 验证证书内容

生成新证书后,可使用以下命令检查证书中的SAN和CN:

keytool -printcert -v -file server.crt

确认输出中包含DNS:localhost和DNS:broker。


内容的提问来源于stack exchange,提问作者Dmytro Chasovskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:47:35