Grpc | 通过SSL/TLS建立安全连接
使用golang的grpc库作为例子
grpc使用TLS建立安全连接需要有SAN证书, go 1.15
版本开始废弃 CommonName。
什么是SAN证书
SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展。使用了 SAN 字段的 SSL 证书,可以扩展此证书支持的域名,使得一个证书可以支持多个不同域名的解析。
制作SAN证书
一条指令生成ca证书
$ openssl req \
-x509 \
-nodes \
-newkey rsa:2048 \
-keyout keys/ca.key \
-out keys/ca.crt \
-days 3650 \
-subj "/C=CN/ST=ZheJiang/L=ZheJiang/O=Global/CN=servername Security/OU=IT"
-sub 后面参数的意义; C => Country; ST => State; L => City; O => Organization; OU => Organization Unit; CN => Common Name (证书所请求的域名); emailAddress => main administrative point of contact for the certificate ;
生成私钥 & 根据私钥server.key生成证书请求文件server.csr:
$ openssl genpkey -algorithm RSA -out server.key
$ openssl req -new -nodes -key server.key -out server.csr -days 3650 \
-subj "/C=CN/OU=IT/O=Global/CN=servername/L=ZheJiang" \
-config openssl.cnf -extensions v3_req
验证证书CSR的扩展属性(可选)
$ openssl req -noout -text -in server.csr
生成san证书
$ openssl x509 -req -days 365 -in server.csr -out server.pem \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile openssl.cnf -extensions v3_req
- server.csr是前面步骤生成的证书请求文件。
- ca.crt & ca.key 是CA证书文件和key,用来对server.csr进行签名认证。
查看SAN信息在证书内容(可选)
$ openssl x509 -noout -text -in server.pem
现在证书已经生成完毕, server.pem 和 server.key正式我们需要的证书和密钥
Grpc 使用SAN证书建立安全通道
proto文件
proto
//Hello.proto
syntax = "proto3";
option go_package = "./pb;pb";
package hello;
message HelloWorld {
string msg = 1;
}
service Hello {
rpc SayHello(HelloWorld) returns(HelloWorld) {}
}
生成*.pb.go文件
$ protoc -I. --go_out=. --go-grpc_out=. ./*proto
server端
golang
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"log"
"net"
"pro2d/protos/pb"
)
type Server struct {
pb.UnimplementedHelloServer
}
func (s *Server) SayHello(ctx context.Context, in *pb.HelloWorld) (*pb.HelloWorld, error) {
return in, nil
}
func main() {
// 监听本地端口
listener, err := net.Listen("tcp", ":8948")
if err != nil {
log.Fatalf("net.Listen err: %v", err)
}
var opts []grpc.ServerOption
// 从输入证书文件和密钥文件为服务端构造TLS凭证
creds, err := credentials.NewServerTLSFromFile("keys/server.pem", "keys/server.key")
if err != nil {
log.Fatalf("Failed to generate credentials %v", err)
}
opts = append(opts, grpc.Creds(creds))
// 新建gRPC服务器实例,并开启TLS认证
grpcServer := grpc.NewServer(opts...)
// 在gRPC服务器注册我们的服务
pb.RegisterHelloServer(grpcServer, &Server{})
log.Println(" net.Listing whth TLS")
//用服务器 Serve() 方法以及我们的端口信息区实现阻塞等待,直到进程被杀死或者 Stop() 被调用
err = grpcServer.Serve(listener)
if err != nil {
log.Fatalf("grpcServer.Serve err: %v", err)
}
}
client端
golang
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"log"
"pro2d/protos/pb"
)
func main() {
var opts []grpc.DialOption
creds, err := credentials.NewClientTLSFromFile("keys/server.pem", "servername")
if err != nil {
log.Fatal(err)
return
}
opts = append(opts, grpc.WithTransportCredentials(creds))
conn, err := grpc.Dial("localhost:8948", opts...)
helloClient := pb.NewHelloClient(conn)
rsp, err := helloClient.SayHello(context.TODO(), &pb.HelloWorld{Msg: "hello world"})
if err != nil {
log.Fatal(err)
}
log.Printf("sayhello rsp: %v", rsp)
}
注意
creds, err := credentials.NewClientTLSFromFile("keys/server.pem", "servername")
这里的servernaem
参数要与证书申请的一致
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2022/02/san/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接