gRPC提供了内置的授权机制(Authorization),也提供接口用于扩展自定义授权验证。gRPC旨在和多种身份验证(Authentication)机制配合使用,可以轻松安全的使用gRPC同其他系统进行通信。
gRPC支持下面几种机制:
- SSL/TLS:gRPC集成了SSL/TLS,并促进使用SSL/TLS对服务进行身份验证,并对客户端和服务端之间交互的所有数据进行加密
- ALTS
- Token-based authentication with Google
同时,也支持扩展自定义认证机制。
1. 前言
如下面一个最基本的Hello grpc程序中, 请求和响应都是明文传输,容易造成敏感信息、伪造篡改等问题。
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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抓包,可以看到请求具体信息:
通过SSL/TLS对服务进行身份认证,可以客户端和服务端之间交互的所有数据进行加密。
2. SSL/TLS认证
证书制作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 私钥
$ 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凭证
1
2
3
4
5
|
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 凭证
1
2
3
4
5
6
|
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)
|
再次进行抓包:
附录:
- Analyzing gRPC messages using Wireshark
- Loopback capture