上一篇文章我们讲解了怎么给 GRPC 配置添加单向证书认证,这一篇我接着分享,如何让 GRPC 服务加入双向证书认证。
双向的证书认证,相比单向的证书认证,使用的地方更多些。
因为客户端和服务端各自都自己的证书,相对来说会更安全。
生成相关证书
我们依旧使用 openSSL 来自签证书,下面下依次生成证书的步骤记录。
这里我的证书全部采用 pem 的格式,和单向的证书不一样。
1、生成私钥
代码语言:javascript复制openssl genrsa -out ca.key 2048
2、生成 pem证书
代码语言:javascript复制openssl req -new -x509 -days 3650 -key ca.key -out ca.pem -subj "/CN=go.kun.com"
/CN 我这里随便输入一个域名 go.kun.com 反正需要改 hosts 来模拟被 DNS 解析。
这里可以根据你的需要进行修改。
3、签发服务端证书
代码语言: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.pem
-CA ca.pem -CAkey ca.key -CAcreateserial
-extensions SAN
-extfile <(cat /etc/pki/tls/openssl.cnf <(printf "n[SAN]nsubjectAltName=DNS:*.kun.com,DNS:*.henjinet.com"))
这里我们需要传入 CA 证书的根证书和私钥进行来签发下一级证书。
4、签发客户端证书
代码语言:javascript复制openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.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 client.csr -out client.pem
-CA ca.pem -CAkey ca.key -CAcreateserial
-extensions SAN
-extfile <(cat /etc/pki/tls/openssl.cnf <(printf "n[SAN]nsubjectAltName=DNS:*.kun.com,DNS:*.henjinet.com"))
我们需要用的文件分别是:
代码语言:javascript复制ca.crt ca.key server.crt server.key
我们把这四个文件放到工程下面的 certs 文件夹下面。
服务端代码
证书生成完毕现在开始去调整我们的代码部分。
首先来调整服务端的代码,调整如下:
代码语言:javascript复制package main
import (
"crypto/tls"
"crypto/x509"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"io/ioutil"
"k_grpc/pbFiles"
"k_grpc/services"
"log"
"net"
)
func main() {
cert, _ := tls.LoadX509KeyPair("certs/server.pem","certs/server.key")
certPool := x509.NewCertPool()
ca,_ := ioutil.ReadFile("certs/ca.pem")
certPool.AppendCertsFromPEM(ca)
cred := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: certPool,
})
// 创建一个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)
}
}
这里我们使用 go 里面的 tls 库来加载一个证书池,再把证书池挂载到 GRPC 的服务上面。
这就是大致的思路。
客户端代码
下面来调整客户端的代码:
代码语言:javascript复制package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"io/ioutil"
"k_grpc/pbFiles"
"log"
)
func main() {
cert, err := tls.LoadX509KeyPair("certs/client.pem","certs/client.key")
if err != nil{
log.Fatalln(err)
}
certPool := x509.NewCertPool()
ca,err := ioutil.ReadFile("certs/ca.pem")
if err != nil{
log.Fatalln(err)
}
certPool.AppendCertsFromPEM(ca)
cred := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{cert},
ServerName: "go.kun.com",
RootCAs: certPool,
})
// 创建连接
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)
}
和服务端的基本一致,使用 go 里面的 tls 库来加载一个证书池。