当微服务所部署的服务器不在一个内网,或者内网不是很安全,担心dubbo的远程调用被中间人窃听,或者担心dubbo 远程接口被恶意调用。此时就需要Dubbo SSL/TLS双向认证,服务提供方需要校验消费方的身份,消费方也需要校验服务提供方的身份。

        dubbo的SSL/TLS的资料网上很少,在Dubbo官网上也很少相关的资料,可参考dubbo官网:TLS支持 | Apache Dubbo 

以下是官网的示例:

Provider 端

//这是dubbo官网文档的说明,加上一些注释:

SslConfig sslConfig = new SslConfig();
//设置服务端的证书
sslConfig.setServerKeyCertChainPath("path to cert");
//设置服务端密钥
sslConfig.setServerPrivateKeyPath(args[1]);
// 如果开启双向 cert 认证
if (mutualTls) {
//设置CA证书
  sslConfig.setServerTrustCertCollectionPath(args[2]);
}

ProtocolConfig protocolConfig = new ProtocolConfig("dubbo/grpc");
//开启ssl
protocolConfig.setSslEnabled(true);

Consumer 端

if (!mutualTls) {
    //设置客户端信任的CA证书
    sslConfig.setClientTrustCertCollectionPath(args[0]);
} else {
     //设置客户端信任的CA证书
    sslConfig.setClientTrustCertCollectionPath(args[0]);
    //设置客户端证书
    sslConfig.setClientKeyCertChainPath(args[1]);
    //设置客户端密钥
    sslConfig.setClientPrivateKeyPath(args[2]);
}

官网给出的示例源码:

https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl

 从示例里有以下几个文件:

ca.key //CA密钥
ca.pem //CA证书
client.key //客户端密钥
client.pem //客户端证书
server0.key //服务端密钥
server0.pem //服务端证书

也就是我们要在自己的项目中提供这几个密钥证书文件,然后配置上私钥和证书。可惜Demo里不是微服务架构,没办法直接拿去使用,也没有告诉我们应该如何创建自己的密钥和证书。

具体分2大步骤:

一:使用openssl工具生成相关的密钥和证书

openssl工具的安装和使用请自行学习,百度一大把教程。参考: window安装openssl

接下来我们就开始创建密钥和证书了,请按照步骤来,如果有错的可以地下评论留言一起研究讨论。

1.CA密钥和根证书

  • 生成CA私钥(.key)
    命令:openssl genrsa -out ca.key 1024
    
  • 生成CA证书请求(.csr)    
    命令:openssl req -new -key ca.key -out ca.csr
    参考以下的交互:输入相应的信息,例如公司组织名称等等。
    
    
  • 自签名得到根证书(.crt)(CA给自已颁发的证书)
    命令: openssl x509 -req -days 2000 -in ca.csr -signkey ca.key  -out ca.crt

 这样我就得到了CA根证书,接下来我们要基于根证书创建服务端和客户端的证书

2.服务器密钥和用CA根证书生成的书

  • 生成私钥(.key)
    命令: openssl genrsa  -out server.key 1024
      以下是交互过程:
     Enter PEM pass phrase:Viangz1234567890
     Verifying - Enter PEM pass phrase:Viangz1234567890
  • 生成证书请求(.csr)
    
    命令:openssl req -new -key server.key -out server.csr
    
    以下是交互过程:
    Enter pass phrase for server.key:
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
     -----
    Country Name (2 letter code) [AU]:CN
    State or Province Name (full name) [Some-State]:guangdong
    Locality Name (eg, city) []:guangzhou
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:vian
    Organizational Unit Name (eg, section) []:vian
    Common Name (e.g. server FQDN or YOUR name) []:vian
    Email Address []:support@vianstats.com
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:Viangz1234567890
     An optional company name []:vian
    命令:openssl ca -in server.csr -out server.crt   -cert ca.crt -keyfile ca.key
    会报以下错误,是个大坑,需要修改配置配置文件或者自己创建文件夹。
    
     Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
     ca: ./demoCA/newcerts is not a directory
    ./demoCA/newcerts: No error
    
    上面的错误意思是找不到/demoCA/newcerts文件夹,因为证书要存储在该文件夹下,
    可以去修改C:\Program Files\Common Files\SSL/openssl.cnf里的配置文件,也可以按照配置文件配置的默认存储路径,创建文件夹。
    本人是修改openssl.cnf配置文件,将./demoCA改为 .
    
     [ CA_default ]
    
    dir     = ./demoCA 改为:.   # Where everything is kept
    certs       = $dir/certs      # Where the issued certs are kept
    crl_dir     = $dir/crl    # Where the issued crl are kept
    database = $dir/index.txt   # database index file.
     #unique_subject  = no         # Set to 'no' to allow creation of
    
     继续执行  C:\Program Files\Common Files\SSL/openssl.cnf ,又报以下错误:
    
     Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
     C05E0000:error:80000002:system library:BIO_new_file:No such file or directory:crypto\bio\bss_file.c:67:calling fopen(./index.txt, r)
     C05E0000:error:10000080:BIO routines:BIO_new_file:no such file:crypto\bio\bss_file.c:75:
    Problem with index file: ./index.txt (could not load/parse file)
    
    找不到index.txt文件,那就在当前目录下创建一个index.txt空文件
    接着执行上面命令,结果又出现以下错误:
    
    ./serial: No such file or directory
    88260000:error:80000002:system library:BIO_new_file:No such file or directory:crypto\bio\bss_file.c:67:calling fopen(./serial, r)
     88260000:error:10000080:BIO routines:BIO_new_file:no such file:crypto\bio\bss_file.c:75:
    error while loading serial number
    
    提示找不到serial文件,那就再手动在当前目录下创建一个serial文件,文件里随便写上数字,这里写01,注意不是文件夹
    继续执行原来的命令,连续输入y就成功创建了。
  • 用CA根证书签名得到证书(.crt)
    命令:openssl ca -in server.csr -out server.crt   -cert ca.crt -keyfile ca.key

3.客户端密钥和用CA根证书生成的客户端证书

  • 生成私钥(.key)
命令:openssl genrsa -out client.key 1024
以下交互,输入密码:Viangz12***
Enter PEM pass phrase: Viangz1234***
Verifying - Enter PEM pass phrase: Viangz1234***
  • 生成证书请求(.csr )
命令:openssl req -new -key client.key -out client.csr

具体的操作请参考服务端的第二步,这里不再重复。

  • 用CA根证书签名得到证书(.crt)
命令:openssl ca -in client.csr -out client.crt -cert ca.crt -keyfile ca.key

以上就是证书生成的过程,最易出错的是生成证书请求(.csr)这步,如果之前没有修改过openssl配置文件,没有在当前文件创建过newcerts文件夹、index.txt、serial文件的需要按照上面的步骤一个完善,最终的效果如下图所示:

  上图中就已经创建好我们需要的几个文件。

二:在SpringCloud配置TLS双向认证

证书已经准备好了,那么我们就可以在微服务里配置了,微服务里的rpc选择的是dubbo,dubbo的底层是使用netty来实现数据通信的,在微服务里很多时候会存在相互调用的,因此就不分服务端和客户端的,存在A服务调B服务,B服务也会调A服务的情况,因此每一个微服务都需要设置服务端和客户端的配置,全部配置。

因此单独将服务拆出来放到common公共依赖包里,所有的服务都依赖这个公共服务。

创建一个配置DubboConfig:

package com.vianstats.capp.commom.dubbo.auth.filter.config;

import org.apache.dubbo.config.SslConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.validation.Valid;
@Configuration
public class DubboConfig {




    @Value("${dubbo.protocol.ssl.server-key-cert-chain-path}")
    private String serverKeyCertChainPath;

    @Value("${dubbo.protocol.ssl.server-private-key-path}")
    private String serverPrivateKeyPath;

    @Value("${dubbo.protocol.ssl.server-trust-cert-collection-path}")
    private String serverTrustCertCollectionPath;

    @Value("${dubbo.protocol.ssl.client-key-cert-chain-path}")
    private String clientKeyCertChainPath;

    @Value("${dubbo.protocol.ssl.client-private-key-path}")
    private String clientPrivateKeyPath;

    @Value("${dubbo.protocol.ssl.client-trust-cert-collection-path}")
    private String clientTrustCertCollectionPath;



    /**
     *
     *
     *
     * 以下的配置文件是绝对路径,如果想在本地运行的需要改成自己本地openssl工具生成的证书
     * 生产环境的证书路径配置在application配置文件上,证书放在服务器的某个安全目录下,不要使用resources下的证书

     * @return
     */
    @Bean
    public SslConfig sslConfig(){

        /**
         *
         * 参考示例,路径使用绝对路径,请按照自己本地存放的证书路径修改配置文件路径
         *  //服务端证书
         *  sslConfig.setServerKeyCertChainPath("D:/ssl/zs/server.crt");
         *  //服务端私钥
         *  sslConfig.setServerPrivateKeyPath("D:/ssl/zs/server.key");
         *  //CA根证书
         *  sslConfig.setServerTrustCertCollectionPath("D:/ssl/zs/ca.crt");
         *  //客户端证书
         *  sslConfig.setClientKeyCertChainPath("D:/ssl/zs/client.crt");
         *  //客户端私钥
         *  sslConfig.setClientPrivateKeyPath("D:/ssl/zs/client.key");
         *  //CA根证书
         *  sslConfig.setClientTrustCertCollectionPath("D:/ssl/zs/ca.crt");
         */


        SslConfig sslConfig = new SslConfig();
        //服务端证书
        sslConfig.setServerKeyCertChainPath(serverKeyCertChainPath);
        //服务端私钥
        sslConfig.setServerPrivateKeyPath(serverPrivateKeyPath);
        //CA根证书
        sslConfig.setServerTrustCertCollectionPath(serverTrustCertCollectionPath);
        //客户端证书
        sslConfig.setClientKeyCertChainPath(clientKeyCertChainPath);
        //客户端私钥
        sslConfig.setClientPrivateKeyPath(clientPrivateKeyPath);
        //CA根证书
        sslConfig.setClientTrustCertCollectionPath(clientTrustCertCollectionPath);

        return sslConfig;

    }


}

然后将该maven依赖加到需要dubbo ssl的服务。在启动类加上该公共包的扫描

@ComponentScan(basePackages = {"com.vianstats.capp.commom.dubbo.auth",})

并在application.properties的文件上加上ssl开启的配置,也将证书的路径配置到application.properties上

# dubbo 协议
dubbo.protocol.id=dubbo
dubbo.protocol.name=dubbo
# dubbo 协议端口( -1 表示自增端口,从 20880 开始)
dubbo.protocol.port=-1
#开启ssl
dubbo.protocol.sslEnabled=true

#以下的配置地址都是绝对地址,上线部署时请根据证书存放的位置修改该路径,本地开发的时候也需要修改证书的位置
dubbo.protocol.ssl.server-key-cert-chain-path=D:/ssl/zs/server.crt
dubbo.protocol.ssl.server-private-key-path=D:/ssl/zs/server.key
dubbo.protocol.ssl.server-trust-cert-collection-path=D:/ssl/zs/ca.crt
dubbo.protocol.ssl.client-key-cert-chain-path=D:/ssl/zs/client.crt
dubbo.protocol.ssl.client-private-key-path=D:/ssl/zs/client.key
dubbo.protocol.ssl.client-trust-cert-collection-path=D:/ssl/zs/ca.crt

大功告成,测试了没问题。有问题欢迎指出,一起沟通学习。

更多推荐