一个上生产的 GRPC 服务肯定是少不了证书验证这个环节的。
为了安全,你可以去购买收费的证书或者免费证书也行,这里演示我们使用 OpenSSL 自生成的证书。
OpenSSL安装
如果你使用的是 Windows 系统,可以在:
http://slproweb.com/products/Win32OpenSSL.html
这个地址里面下载到对应的版本,至于怎么安装。
如果是使用的 Mac 系统一般都自带此服务。
这里建议使用 Centos 来处理,安装命令:
代码语言:javascript复制yum install openssl openssl-devel -y
下面的内容也是在服务器 Centos7 上面操作的。
生成相关证书
不要问为什么要这样生成证书,一问就是固定搭配[坏笑]。
你只需要按照下面的步骤,一步一步的生成证书就好了。
1、生成私钥
代码语言:javascript复制openssl genrsa -out ca.key 2048
2、生成 CSR(证书签名请求)
代码语言:javascript复制openssl req -new -key ca.key -out ca.csr -subj "/CN=go.kun.com"
/CN 我这里随便输入一个域名 go.kun.com 反正需要改 hosts 来模拟被 DNS 解析。
3、生成自签名SSL证书
代码语言:javascript复制openssl req -new -x509 -days 3650 -out ca.crt -key ca.key -subj "/CN=go.kun.com"
4、签发服务端证书
代码语言:javascript复制openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=go.kun.com"
-reqexts SAN
-config <(cat /etc/pki/tls/openssl.cnf <(printf "n[SAN]nsubjectAltName=DNS:*.kun.com,DNS:*.henjinet.com"))
# 注意
openssl x509 -req -days 3650
-in server.csr -out server.crt
-CA ca.crt -CAkey ca.key -CAcreateserial
-extensions SAN
-extfile <(cat /etc/pki/tls/openssl.cnf <(printf "n[SAN]nsubjectAltName=DNS:*.kun.com,DNS:*.henjinet.com"))
可以通过下面的命令查看 csr 的信息是否有写入成功
代码语言:javascript复制openssl req -noout -text -in ca.csr
我们需要用的文件分别是:
代码语言:javascript复制ca.crt ca.key server.crt server.key
我们把这四个文件放到工程下面的 certs 文件夹下面。
让整个服务单向验证
修改 server.go 文件里面的方法,修改如下:
代码语言:javascript复制func main() {
// 创建证书
cred,err := credentials.NewServerTLSFromFile("certs/server.crt","certs/server.key")
if err != nil {
log.Fatalln(err)
}
// 创建一个GRPC服务
srv := grpc.NewServer(grpc.Creds(cred))
// 注册需要挂载的服务
pbFiles.RegisterStudentServiceServer(srv, services.NewStudentService())
// 启一个监听服务
lis,_ := net.Listen("tcp",":8080")
// 启动 GRPC 服务
if err := srv.Serve(lis);err != nil{
log.Fatalln(err)
}
}
我们只需要使用 credentials 来创建证书配置,然后挂载 GRPC 里面即可。
修改后我们重新启动我们的 server 服务。
客户端如果不修改代码的情况下,请求就会报错了。
现在我们修改下客户端的代码:
代码语言:javascript复制func main() {
// 创建证书
cred,err := credentials.NewClientTLSFromFile("certs/server.crt", "go.kun.com")
if err != nil {
log.Fatalln(err)
}
// 创建连接
client,err := grpc.Dial(":8080",grpc.WithTransportCredentials(cred))
if err != nil {
log.Fatalln(err)
}
// 定义请求体
req := &pbFiles.GetStudentRequest{
SId: 3333,
}
// 定义返回体
rsv := &pbFiles.GetStudentResponse{}
// 正式请求
err = client.Invoke(
context.Background(),
"/StudentService/GetStudent",
req,
rsv)
if err != nil {
log.Fatalln(err)
}
// 打印输出
fmt.Println(rsv.Result)
}
这里我们是采用的单向验证,所以客户端挂载的证书也是服务端的证书。
在某些场景下这种单向证书也是有需要的,但是大多数场景下,一般都是双向验证。
因为双向验证的证书生成方式和单向验证的有一定区别,所以我们将在下一篇文章中介绍。