Golang gRPC笔记02 TLS 证书认证
一、 证书生成
生成私钥
openssl genrsa -out server.key 2048
或者:
openssl ecparam -genkey -name secp384r1 -out server.key openssl genrsa:生成RSA私钥,命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512 openssl ecparam:生成ECC私钥,命令为椭圆曲线密钥参数生成及操作,本文中ECC曲线选择的是secp384r1
生成自签公钥
openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650
填写信息:
Country Name (2 letter code) [XX]:cn State or Province Name (full name) []:shanghai Locality Name (eg, city) [Default City]:shanghai Organization Name (eg, company) [Default Company Ltd]:hellokitty Organizational Unit Name (eg, section) []:hellokitty Common Name (eg, your name or your server's hostname) []:localhost Email Address []:
二、 完成项目编码
项目目录:
grpc_demo/ |—— demo02/ |—— client/ |—— client.go // 客户端 |—— conf/ |—— keys/ |—— server.key // 私钥 |—— server.pem // 公钥 |—— proto/ |—— prod/ |—— prod.proto |—— prod.pb.go |—— server/ |—— server.go // 服务端
.proto文件:prod.proto
无变动
server端:server.go
package main import ( "context" prodpb "grpc_demo/demo02/proto/prod" "log" "net" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) type ProdService struct{} func (p ProdService) GetProdStock(_ context.Context, prodReq *prodpb.ProdRequest) (*prodpb.ProdResponse, error) { log.Printf("请求参数:ProdRequest.ProdId=%d", prodReq.ProdId) return &prodpb.ProdResponse{ProdStock: 2008}, nil } // 生成ProdService func CreateProdService() ProdService { return ProdService{} } const ( // Address gRPC服务地址 Address = "127.0.0.1:8899" ) func main() { // 从输入证书文件和密钥文件为服务端构造TLS凭证 // 注意在goland中引入文件以项目根目录为相对路径, 命令行直接运行需正确填写文件路径 creds, err := credentials.NewServerTLSFromFile("demo02/conf/keys/server.pem", "demo02/conf/keys/server.key") if err != nil { log.Fatalf("credentials.NewServerTLSFromFile err: %v", err) } // 1. 创建 gRPC Server 的实例对象,并开启TLS认证 rpcServer := grpc.NewServer(grpc.Creds(creds)) // 2.gRPC Server 内部服务和路由的注册 prodpb.RegisterProdServiceServer(rpcServer, CreateProdService()) // 3. 监听指定 TCP 端口,用于接受客户端请求 listener, err := net.Listen("tcp", Address) if err != nil { panic("net.Listen err: " + err.Error()) } log.Printf("Listening on %s\n", Address) // 4. Serve() 调用服务器以执行阻塞等待,直到进程被终止或被 Stop() 调用 log.Fatal(rpcServer.Serve(listener)) }
credentials.NewServerTLSFromFile:根据服务端输入的证书文件和密钥构造 TLS 凭证
grpc.Creds: 返回一个 ServerOption,用于设置服务器连接的凭据
client端: client.go
package main import ( "context" prodpb "grpc_demo/demo02/proto/prod" "log" "google.golang.org/grpc/credentials" "google.golang.org/grpc" ) const ( // Address gRPC服务地址 Address = "127.0.0.1:8899" ) func main() { // 从输入的证书公钥文件 和 自签公钥时填写的域名参数(本次签名使用的是localhost) 为客户端构造TLS凭证 // 注意在goland中引入文件以项目根目录为相对路径, 命令行直接运行需正确填写文件路径 creds, err := credentials.NewClientTLSFromFile("demo02/conf/keys/server.pem", "localhost") if err != nil { log.Fatalf("credentials.NewClientTLSFromFile err: %v", err) } // 连接 rpc 服务器 conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds)) if err != nil { panic("grpc.Dial err: " + err.Error()) } defer conn.Close() // 初始化客户端 client := prodpb.NewProdServiceClient(conn) resp, err := client.GetProdStock(context.Background(), &prodpb.ProdRequest{ProdId: 2222}) if err != nil { log.Print("调用失败,err=", err) return } log.Printf("%+v \n", resp) }
credentials.NewClientTLSFromFile: 从输入的证书文件中为客户端构造TLS凭证,serverNameOverride 为自签公钥时填写的域名参数
grpc.WithTransportCredentials: 配置连接级别的安全凭证(例如,TLS/SSL),返回一个DialOption,用于 grpc.Dial(target string, opts …DialOption) 设置连接选项
验证:
启动 Server:
cd demo02/server go run server.go Listening on 127.0.0.1:8899
启动 Client:
cd demo02/client go run client.go prod_stock:2008
成功获取数据, 完成 TLS 安全认证