背景
- 因為應用服務用到了Dubbo,Dubbo 依賴了 Zookeeper作為注冊中心。
- 應用服務同時還需要連接到KAFKA,且Kafka開啟了SASL認證。
問題
對於一個開源中間件來說,集群安全是很重要的,但是在實現上,認證方式就那么幾種:
- GSSAPI (唯一實現:Kerberos,Java可以使用JAAS對其進行支持)
- SASL (Java可以使用JAAS對其進行支持)
- PLAIN_TEXT (沒認證)
- SSL
那么如果全局指定了JAAS,訪問兩個SASL配置賬戶不同的集群,就會必然有一個失敗。
分析
對於Zookeeper,它使用了JAAS,它僅僅簡單粗暴的通過讀取zookeeper.sasl.client
和java.security.auth.login.config
這兩個全局環境變量來判斷要不要使用SASL認證,無法通過其他方式來改變這種行為。
對於Kafka,它巧妙地實現了javax.security.auth.login.Configuration
,也就是org.apache.kafka.common.security.JaasConfig
。可以通過代碼中直接指定 sasl.jaas.config
(slankka:0715.2020) 來表示此Topic的連接認證方式,十分靈活。
此外,Apache Flume 也收益於此,Flume如果同時連接加密和不加密的 多套Kafka集群,可以按照單個Kafka Source/Sink 進行Topic級別細粒度的配置認證方式,而不是通過JVM參數直接全局固定。
那么解決方案就有好幾種:
- 修改使用Zookeeper的客戶端連接器。
- 修改Zookeeper源碼。
- 運行時指定Jaas,啟動時不指定。
- 通過創建單獨的進程指定JAAS參數
- 通過Java調用Linux命令,訪問Kafka/Zookeeper配置好的客戶端來執行某些操作。
額外技術細節
Zookeeper 本身的連接是極為困難的,現在開源社區總共有兩種Zookeeper Java Client(暫且稱為Zookeeper連接器):
- zkclient(zk101tec)
- Curator
具體區別不在這里詳述。
對於 Dubbo 2.7.1 以后的版本,我通過檢查源碼,發現 Dubbo已經去除 zkclient(zk101tec)依賴,已經完全切換到 Apache Curator。
如果修改 Zookeeper連接器,那就要確定項目中,引入的框架使用的是哪一種連接器。
解決方案
解決辦法正如前文指出,有三種,最便宜實用的方法就是方案三: 在運行時指定jaas配置。運行完畢再恢復上次的配置。在切換期間可能會存在幾毫秒的其他Zookeeper集群訪問的問題,但是這已經是極小的影響了。
另外,Zookeeper社區,有人指出這種設計的不足:
ZOOKEEPER-2139:Support multiple ZooKeeper client, with different configurations, in a single JVM
通過查看提交記錄發現,社區已經針對Zookeeper的構造函數提供了 ZkClientConfig這個參數類,可以實現自定義的配置。
Github 2139 Commit
可以看出,這些版本以后才能支持:release-3.6.1 release-3.6.1-1 release-3.6.1-0 release-3.6.0 release-3.6.0-4 release-3.6.0-3 release-3.6.0-2 release-3.6.0-1 release-3.6.0-0
當Zookeeper支持了以后,就可以用方案1,或者類似於Kafka的方式來更好的解決。
總結
Kafka的這種設計值得我們學習,減少具體配置對環境變量的依賴。
涉及到的技術有:JAAS,Kafka, Zookeeper