今天會接續 [Go] 用 Go 建立 gRPC 的 Server 與 Client 的範例,將 Server/Client 之間加入 TLS 加密通道。

在開始之前要先準備好憑證,建立憑證的方式可以參考 [Go] 使用 Go Tool 建立 SSL 自簽憑證

Server 端設定憑證

今天的目標是,用 grpc/credentials 建立 grpc credentials.TransportCredentials,便且將此憑證傳入grpc.NewServer()

可以參考下方的程式碼,設定 TLS 最重要的 2 行就是 creds, err := credentials.NewServerTLSFromFile("cert.pem", "key.pem")s := grpc.NewServer(grpc.Creds(creds))

Set TLS to 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
30
31
32
33
34
35
36
package main

import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"log"
"net"
"trygrpc/pb"
"trygrpc/service"
)

const (
port = ":50051"
)
func main() {
// Create gRPC Server
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

// Create tls based credential.
creds, err := credentials.NewServerTLSFromFile("cert.pem", "key.pem")

if err != nil {
log.Fatalf("failed to create credentials: %v", err)
}

s := grpc.NewServer(grpc.Creds(creds))

log.Println("gRPC server is running.")
pb.RegisterGreeterServer(s, &service.MessageService{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

Client 端設定憑證

Client 在讀取的時候,也要設定好憑證,這樣 Server 端在使用 key.pem 解密的時候才能夠正常運作。 而 Client 加入憑證的方式也很簡單。 最重要的 2 行是 creds, err := credentials.NewClientTLSFromFile("../cert.pem", "")conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds), grpc.WithBlock())。 其實跟 Server 大同小異。

Set TLS to Client
  • 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
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"log"
"time"
"trygrpc/pb"
)

const (
address = "localhost:50051"
)

func main() {
// Create tls based credential.
creds, err := credentials.NewClientTLSFromFile("../cert.pem", "")
if err != nil {
log.Fatalf("failed to load credentials: %v", err)
}

// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)

// Contact the server and print out its response.
name := "Miles"

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}

小結

最後可以參考此 commit ,比較使用 TLS 與不使用 TLS 的程式碼差異,就可以知道使用 TLS 並不會太難。

延伸閱讀

[grpc-go/examples/features/encryption]
[Enhancing Application Communication with gRPC]