はじめに
Cloudflare で gRPC を通すテストをしたので紹介します。
2020年の Blog に記載がありましたが、試していませんでした。
サポートドキュメントもあります。
Cloudflare の特性を活かし、gRPC サービスに対して
を順に試していこうかと思います。
できることを見るため、有償版の機能も一部使っています。
特に明示してないのですが、ご容赦ください。
第1回として、まずプロキシで動くようにします。
プロキシ + Full TLS 化
gRPC クライアント ←--(TLS)--→ Cloudflare
Cloudflare ←-(TLS)-→ gRPC サーバ
どちらも TLS 化します。
(mTLS はやってないです)
Cloudflare を使うので、プロキシ部分はなるだけ近道するのを目指します。
gRPC サーバ
gRPC プロキシ時の前提事項
Cloudflare で gRPC を通す場合、要求事項が下記になっています。
Your gRPC endpoint must listen on port 443.
Your gRPC endpoint must support TLS and HTTP/2.
HTTP/2 must be advertised over ALPN.
Use application/grpc or application/grpc+<message type (for example: application/grpc+proto) for the Content-Type header of gRPC requests.
gRPC サーバはポート 443 で TLS をリッスンする必要があります。
ALPN 対応で、content-type の指定も守る必要があります。
TLS サーバ証明書の準備 (gRPC サーバ用)
gRPC サーバを TLS 化するので証明書が必要になります。
OpenSSL とかで作るのもいいですけど、
Cloudflare の SSL/TLS Origin Certificates から作るとワンクリックで簡単なので、Cloudflare を通す場合はこちらを使うと楽です。
API でも管理できるので、自動化にも使えます。
gRPC サーバ (greeter_server/main.go) TLS 化
gRPC サーバは Go/Quick start を拝借します。
ポート 443
で TLS
をリッスンさせるため、サーバ greeter_server/main.go
を変更します。
greeter_server/cert/
を作り、 Cloudflare の Origin Certificates で作成した公開鍵を cert.pem
、秘密鍵を key.pem
で配置します。
greeter_server/main.go
を編集します。
--- greeter_server/main.go 2023-01-28 07:48:37.736281676 +0000
+++ greeter_server/main.tls.go 2023-01-29 03:07:17.779105810 +0000
@@ -27,11 +27,12 @@
"net"
"google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
var (
- port = flag.Int("port", 50051, "The server port")
+ port = flag.Int("port", 443, "The server port")
)
// server is used to implement helloworld.GreeterServer.
@@ -51,7 +52,16 @@
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
- s := grpc.NewServer()
+ creds, err := credentials.NewServerTLSFromFile(
+ "/home/ubuntu/grpc-go/examples/helloworld/greeter_server/cert/cert.pem",
+ "/home/ubuntu/grpc-go/examples/helloworld/greeter_server/cert/key.pem",
+ )
+ if err != nil {
+ log.Fatal("Failed to generate credentials: %v", err)
+ }
+ s := grpc.NewServer(
+ grpc.Creds(creds),
+ )
pb.RegisterGreeterServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
サーバを起動します。
ubuntu@vm1:~/grpc-go/examples/helloworld$ sudo go run greeter_server/main.tls.go
2023/01/29 03:07:23 server listening at [::]:443
Cloudflare プロキシ
Cloudflare で gRPC プロキシの準備をします。
gRPC 有効化
gRPC を有効にします。
HTTP/2 to Origin というスイッチがありますが、こちらは無効のままでも gRPC さえ有効にしておけばよかったです。
権威 DNS 設定
ホスト名でアクセスするので DNS の設定をします。
gRPC のパブリック IP (今回は GCP ) を A レコードで指定しています。
オレンジ雲に倒すとプロキシさせることになります。
プロキシ中はオリジンの IP の代わりに、Cloudflare の IP が返ります。
$ dig rpc.example.com +short
104.18.xxx.xx
104.18.xxx.xx
TLS 設定
gRPC サーバの TLS 設定は終わってます。
プロキシサーバの TLS はどうしましょう、というところですが、こちらはすでに自動で適用されていると思います。
こういうところも楽ですね。
前提として、TLS のモードは Full あるいは Full Strict にしておきます。上記のように Cloudflare の Origin Certificate を発行した場合は Full Strict が使えて安心です。
全体の設定で合わせるか、
Page Rules または Configuration Rules を使って条件を絞って個別に設定することもできます。
なお、モードの違いについてはこちらが詳しいです。
gRPC クライアント
クライアント (greeter_client/main.go) TLS 化
クライアントも Go/Quick start を拝借しますが、TLS
でリクエストさせるため、クライアント greeter_client/main.go
を編集します。
--- greeter_client/main.go 2023-01-29 04:08:18.455501186 +0000
+++ greeter_client/main.tls.go 2023-01-29 15:00:49.520768741 +0000
@@ -26,6 +26,7 @@
"time"
"google.golang.org/grpc"
+ "google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
@@ -37,12 +38,19 @@
var (
addr = flag.String("addr", "localhost:50051", "the address to connect to")
name = flag.String("name", defaultName, "Name to greet")
+ useTLS = flag.Bool("use_tls", false, "Connection uses TLS if true")
)
func main() {
flag.Parse()
+ var creds credentials.TransportCredentials
+ if *useTLS {
+ creds = credentials.NewClientTLSFromCert(nil, "")
+ } else {
+ creds = insecure.NewCredentials()
+ }
// Set up a connection to the server.
- conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
+ conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(creds))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
接続
クライアント
ubuntu@vm2:~/grpc-go/examples/helloworld$ go run greeter_client/main.tls.go -addr=rpc.example.com:443 -use_tls=true
2023/01/29 04:20:08 Greeting: Hello world
ubuntu@vm2:~/grpc-go/examples/helloworld$ go run greeter_client/main.tls.go -addr=rpc.example.com:443 -use_tls=true -name=hoge
2023/01/29 04:21:54 Greeting: Hello hoge
サーバ
ubuntu@vm1:~/grpc-go/examples/helloworld$ sudo go run greeter_server/main.tls.go
2023/01/29 04:12:45 server listening at [::]:443
2023/01/29 04:20:08 Received: world
2023/01/29 04:21:54 Received: hoge
オブザバビリティ
ログ
HTTP リクエストの生ログをリアルタイムに確認するには Instant Logs です。
リクエストを投げながらログの確認ができるので、楽ちんです。
出力フィルタが用意されているので、欲しいログにマッチするフィルタを掛けてからログを開始しましょう。
Instant Logs の Host フィルタは host ヘッダそのものを取るようです。今回のようにクライアントが Hostname:443
とポートを追加してくるケースでは、equals
する場合は :443
も付けるようにします。(下の例では starts with
でやっているので、そこは無関係)
行をクリックすると詳細を確認できます。
リクエストやレスポンスの詳細情報が見えてます。
(下記は一部抜粋で、その他にも色んな情報を見ることができます)
統計情報
統計情報は Analytics Traffic で見ます。
裏では HTTP リクエストログをソースに Graphql が動いてますので、ソースログに対して多様な分析ができます。
いろいろなところをクリックすると面白いです。
以上、 gRPC の単純なプロキシ (+ Full TLS) として動作させることができました。
第2回はファイアウォールを噛まして、必要なリクエストのみオリジンに届けようと思います。