Skip to content

grpc

3 posts with the tag “grpc”

grpc SSL/TLS

gRPC提供了内置的授权机制(Authorization),也提供接口用于扩展自定义授权验证。gRPC旨在和多种身份验证(Authentication)机制配合使用,可以轻松安全的使用gRPC同其他系统进行通信。

gRPC支持下面几种机制:

  • SSL/TLS:gRPC集成了SSL/TLS,并促进使用SSL/TLS对服务进行身份验证,并对客户端和服务端之间交互的所有数据进行加密
  • ALTS
  • Token-based authentication with Google

同时,也支持扩展自定义认证机制。

如下面一个最基本的Hello grpc程序中, 请求和响应都是明文传输,容易造成敏感信息、伪造篡改等问题。

server.go

package main
import (
"context"
"log"
"net"
"google.golang.org/grpc"
pb "xwxwgo.com/hello-grpc/lib/protos"
)
type Server struct {
pb.UnimplementedHelloServiceServer
}
func (s *Server) SayHello(ctx context.Context, req *pb.HelloReq) (*pb.HelloRsp, error) {
return &pb.HelloRsp{Reply: req.Greeting}, nil
}
func main() {
lis, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
server := grpc.NewServer()
pb.RegisterHelloServiceServer(server, &Server{})
server.Serve(lis)
}

client/main.go

package main
import (
"context"
"log"
"google.golang.org/grpc"
pb "xwxwgo.com/hello-grpc/lib/protos"
)
func main() {
conn, err := grpc.Dial(":8080", grpc.WithInsecure())
if err != nil {
log.Fatalf("dail field: %v", err)
}
defer conn.Close()
client := pb.NewHelloServiceClient(conn)
rsp, err := client.SayHello(context.Background(), &pb.HelloReq{Greeting: "Hello grpc"})
if err != nil {
log.Fatalf("call server failed: %v", err)
}
log.Printf("SayHello: %+v", rsp)
}

通过Wireshark本地gRPC抓包,可以看到请求具体信息:

image-20211019163046195

通过SSL/TLS对服务进行身份认证,可以客户端和服务端之间交互的所有数据进行加密。

Terminal window
# 私钥
$ openssl ecparam -genkey -name secp384r1 -out server.key
# 自签公钥
$ openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

Client:

credentials.NewClientTLSFromFile:通过服务端的自签公钥和服务名称,来构造TLS凭证

creds, _ := credentials.NewClientTLSFromFile(certFile, "hello-grpc")
conn, _ := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(creds))
// error handling omitted
client := pb.NewHelloServiceClient(conn)
// ...

Server:

credentials.NewServerTLSFromFile:服务端证书文件和密钥构造 TLS 凭证

creds, _ := credentials.NewServerTLSFromFile(certFile, keyFile)
s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterHelloServiceServer(s, &server.HelloServer{})
lis, _ := net.Listen("tcp", "localhost:50051")
// error handling omitted
s.Serve(lis)

再次进行抓包:

image-20211019164650896

  1. Analyzing gRPC messages using Wireshark
  2. Loopback capture

GRPC系列 简述

gRPC是可以在任何环境中运行的现代开源高性能RPC框架。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

图1

  • 在微服务风格架构中有效连接多种服务
  • 将移动设备,浏览器客户端连接到后端服务
  • 生效高效的客户端
  • 十种常用语言的客户端库
  • 高效的连接和简单的服务定义框架
  • 双向流和基于http/2的传输
  • 可插拔身份验证,跟踪,负债均衡和运行状况检查

gRPC默认使用Protocol Buffers序列化协议,用于序列化结构化数据。当然也可以使用json。

定义一个服务, 指定其可以被远程调用的方法及其参数和返回类型。gRPC 默认使用 protocol buffers 作为接口定义语言,来描述服务接口和有效载荷消息结构。

service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
required string greeting = 1;
}
message HelloResponse {
required string reply = 1;
}

gRPC支持的四种服务方法:

客户端发送一个请求给服务端,从服务端获取一个应答,就像一次简单的服务调用。

rpc SayHello(HelloRequest) returns (HelloResponse){
}

5.2、服务端流式RPC(Server-side streaming RPC

Section titled “5.2、服务端流式RPC(Server-side streaming RPC)”

客户端发送一个请求给服务端,可获得一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。gRPC保证单个RPC调用中的消息顺序。

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}

5.3、客户端流式RPC**(Client-side streaming RPC)**

Section titled “5.3、客户端流式RPC**(Client-side streaming RPC)**”

客户端用提供的一个数据流写人并发送一系列消息给服务端。一旦客户端完成消息写入,就等服务端读取这些消息并返回应答。gRPC保证单个RPC调用中的消息顺序。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}

5.4、双向流式RPC**(Bidirectional streaming RPC)**

Section titled “5.4、双向流式RPC**(Bidirectional streaming RPC)**”

双方都使用读写流发送一系列消息。这两个数据流是独立的,所以服务端和客户端可以按其期望的任意顺序读写,如:服务端可以在写响应之前等待接收所有客户端消息,或者可以先读消息再写消息,或者其他一些读写组合。每个流中的消息顺序都会保留。

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}

gRPC提供protocol buffer 编译插件,能够从一个定义服务的.proto文件生成客户端和服务端代码。通常gRPC用户可以在服务端实现这些API,并从客户端调用:

  • 在服务端,服务器实现服务声明的方法,并运行gRPC服务器处理客户端调用。gRPC底层架构会解码传入的请求,执行服务方法,编码服务应答。
  • 在客户端,客户端有一个存根实现了服务端相同的方法。客户端可以在本地存根调用这些方法,用合适的protocol buffer消息类型封装这些参数,gRPC来负债发送请求给服务端并返回服务端protocol buff响应。s

gRPC系列-开端

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

过去一段时间,基于gRPC框架进行开发后端服务接口。接下来,将计划一个系列,记录和继续深入研究和更好的使用gRPC。