为GRPC证书加入双向证书认证如此简单

2022-05-10 08:27:29 浏览数 (1)

上一篇文章我们讲解了怎么给 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 库来加载一个证书池。

0 人点赞