Zookeeper 實現 ssl 雙向認證


本文為博主原創,未經允許不得轉載:

  zookeeper 作為注冊中心或服務發現協調中心的時候,zookeeper 默認與其他服務通過 http 進行通信。

  zookeeper 與協調服務配置 ssl 雙向認證,即 client 端驗證 server 端證書,server 端驗證 client 端證書,

  

  1. ssl 雙向認證過程

                             

 

 

 

  1、客戶端向服務器發送連接請求(SSL協議版本號、加密算法種類、隨機數等信息)

  2、服務器給客戶端返回服務器端的證書,即公鑰證書,同時也返回證書相關信息(SSL協議版本號、加密算法種類、隨機數等信息)

  3、客戶端使用服務端返回的信息驗證服務器的合法性(首先檢查服務器發送過來的證書是否是由自己信賴的CA中心所簽發的,再比較證書里的消息,例如域名和公鑰,與服務器剛剛發送的相關消息是否一致,如果是一致的,客戶端認可這個服務端的合法身份),驗證通過后,則繼續進行通信,否則終止通信,具體驗證內容包括:

       a、證書是否過期
       b、發行服務器證書的CA是否可靠
       c、返回的公鑰是否能正確解開返回證書中的數字簽名
       d、服務器證書上的域名是否和服務器的實際域名相匹配

  4、服務端要求客戶端發送客戶端的證書,客戶端會將自己的證書發送至服務端

  5、驗證客戶端的證書,通過驗證后,會獲得客戶端的公鑰

  6、客戶端向服務器發送自己所能支持的對稱加密方案,供服務器端進行選擇

  7、服務器端在客戶端提供的加密方案中選擇加密程度最高的加密方式

  8、將加密方式通過使用之前獲取到的公鑰(客戶的公鑰)進行加密,返回給客戶端

  9、客戶端收到服務端返回的加密方案密文后,使用自己的私鑰進行解密,獲取具體加密方式,而后獲取該加密方式的隨機碼,用作加密過程中的密鑰,使用之前從服務端證書中獲取到的公鑰進行加密后,發送給服務端

  10、服務端收到客戶端發送的消息后,使用自己的私鑰進行解密,獲取對稱加密的密鑰,在接下來的會話中,服務器和客戶端將會使用該密碼進行對稱加密,保證通信過程中信息的安全

  

2. Zookeeper 配置雙向認證:

  bin/zkServer.sh 配置:

export SERVER_JVMFLAGS=-Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory
-Dzookeeper.ssl.keyStore.location=/root/zookeeper/ssl/testKeyStore.jks
-Dzookeeper.ssl.keyStore.password=testpass
-Dzookeeper.ssl.trustStore.location=/root/zookeeper/ssl/testTrustStore.jks
-Dzookeeper.ssl.trustStore.password=testpass”

  在 “zoo.cfg”中增加:

secureClientPort=2281

  “bin/zkCli.sh”的配置為:

export CLIENT_JVMFLAGS=-Dzookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty
-Dzookeeper.client.secure=true
-Dzookeeper.ssl.keyStore.location=/root/zookeeper/ssl/testKeyStore.jks
-Dzookeeper.ssl.keyStore.password=testpass
-Dzookeeper.ssl.trustStore.location=/root/zookeeper/ssl/testTrustStore.jks
-Dzookeeper.ssl.trustStore.password=testpass”

  

  zookeeper 通過 netty 進行服務通信。通過  -Dzookeeper.clientCnxnSocket=org.apache.zookeeper.ClientCnxnSocketNetty 指定 netty 通信。

  上面是通過在  bin/zkCli.sh 客戶端 指定通信的安全訪問配置。

  如果是 java 客戶端時,可以在 java 服務啟動類中添加 以上的 系統環境變量配置,即可配置生效。

  

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {

    public static void main(String[] args) {
        System.setProperty("zookeeper.clientCnxnSocket","org.apache.zookeeper.ClientCnxnSocketNetty");
        System.setProperty("zookeeper.client.secure","true");
        System.setProperty("zookeeper.ssl.keyStore.location","/root/zookeeper/ssl/testKeyStore.jks");
        System.setProperty("zookeeper.ssl.keyStore.password","testpass");
        System.setProperty("zookeeper.ssl.trustStore.location","/root/zookeeper/ssl/testTrustStore.jks");
        System.setProperty("zookeeper.ssl.trustStore.password","testpass");

        SpringApplication.run(DemoApplication.class, args);
    }
}

 

3. zookeeper 客戶端認證源碼:

  NettyServerCnxnFactory 類中:

  

private synchronized void initSSL(ChannelPipeline p, boolean supportPlaintext) throws X509Exception, KeyManagementException, NoSuchAlgorithmException {
        String authProviderProp = System.getProperty(this.x509Util.getSslAuthProviderProperty());
        SslContext nettySslContext;
        if (authProviderProp == null) {
            SSLContextAndOptions sslContextAndOptions = this.x509Util.getDefaultSSLContextAndOptions();
            nettySslContext = sslContextAndOptions.createNettyJdkSslContext(sslContextAndOptions.getSSLContext(), false);
        } else {
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            X509AuthenticationProvider authProvider = (X509AuthenticationProvider)ProviderRegistry.getProvider(System.getProperty(this.x509Util.getSslAuthProviderProperty(), "x509"));
            if (authProvider == null) {
                LOG.error("Auth provider not found: {}", authProviderProp);
                throw new SSLContextException("Could not create SSLContext with specified auth provider: " + authProviderProp);
            }

            sslContext.init(new X509KeyManager[]{authProvider.getKeyManager()}, new X509TrustManager[]{authProvider.getTrustManager()}, (SecureRandom)null);
            nettySslContext = this.x509Util.getDefaultSSLContextAndOptions().createNettyJdkSslContext(sslContext, false);
        }

        if (supportPlaintext) {
            p.addLast("ssl", new NettyServerCnxnFactory.DualModeSslHandler(nettySslContext));
            LOG.debug("dual mode SSL handler added for channel: {}", p.channel());
        } else {
            p.addLast("ssl", nettySslContext.newHandler(p.channel().alloc()));
            LOG.debug("SSL handler added for channel: {}", p.channel());
        }

    }

 

  初始化 ssl 通信配置,並加載 X509Util 進行校驗: 

private synchronized void initSSL(ChannelPipeline pipeline) throws SSLContextException {
            if (this.sslContext == null || this.sslEngine == null) {
                X509Util x509Util = new ClientX509Util();
                Throwable var3 = null;

                try {
                    this.sslContext = x509Util.createSSLContext(ClientCnxnSocketNetty.this.clientConfig);
                    this.sslEngine = this.sslContext.createSSLEngine(this.host, this.port);
                    this.sslEngine.setUseClientMode(true);
                } catch (Throwable var12) {
                    var3 = var12;
                    throw var12;
                } finally {
                    if (x509Util != null) {
                        if (var3 != null) {
                            try {
                                x509Util.close();
                            } catch (Throwable var11) {
                                var3.addSuppressed(var11);
                            }
                        } else {
                            x509Util.close();
                        }
                    }

                }
            }

            pipeline.addLast("ssl", new SslHandler(this.sslEngine));
            ClientCnxnSocketNetty.LOG.info("SSL handler added for channel: {}", pipeline.channel());
        }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM