zoukankan      html  css  js  c++  java
  • 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());
            }
  • 相关阅读:
    Maven跳过测试
    Maven教程
    使用订单号加锁
    SpringMVC重定向路径中带中文参数
    并发文章
    maven clean插件使用进阶
    线程池基础
    Session中短信验证码设置有效时间
    Linux命令
    下载并安装Cent OS 6.5
  • 原文地址:https://www.cnblogs.com/zjdxr-up/p/15126227.html
Copyright © 2011-2022 走看看