grpc-javaのServerでTLSを有効にした場合はALPN対応しているか確認すべし


開発中のプロジェクトでTLSが有効なGo製 gRPC ServerにAndorid8.0(Oreo)からは接続ができて、Kotlin製(grpc-java) gRPC Serverには接続ができない状況に直面した。

原因はOpenSSLでTLSを有効にしていたがALPN対応ができていなかった。Android8.0(Oreo)ではプロトコルのネゴシエーションにALPNが用いられる。Android8.0以下(Lolipopなど)では接続ができてAndroid8.0(Oreo)では接続できない、そんな状況であった。そして次のgrpc-javaのissue報告と同じような経験を踏んでいた。

このissueによるとServer側がALPN対応していないことが原因でALPN対応することで解決した、ということで参考にしながら解決まで進めた。対応内容をまとめていきたい。

ALPN対応ができているか確認する方法

issueを参考に次の方法でALPN対応ができているか確認したところ「No ALPN negotiated」と出力されALPN対応できていないことが発覚した。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ openssl s_client -alpn h2 -connect <domain>:<port>

---
・・・省略
No ALPN negotiated ← ALPN対応していないと、`No ALPN negotiated`と出力される
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : XXXX
・・・省略
---

プロジェクトではGo製のTLSが有効なgRPC Serverがあり同じ方法で確認したところ「ALPN protocol: h2」の出力が確認できた。そしてAndroid8.0(Oreo)からも接続ができていた。SSL Clientを用いた違い(No ALPN negotiatedALPN protocol: h2)を頼りにKotlin製(grpc-java)のgRPC Serverでも「ALPN protocol: h2」が出力されることを目指した。

改めてgrpc-java/SECURITY.mdを参照する

https://github.com/grpc/grpc-java/blob/master/SECURITY.md

Security.mdによるとTLSを有効にするためには2つの方法がありOpenSSLを用いるかjar起動のオプションのjavaagentにjetty-alpn-agentを加える方法がある。 以前のエントリでもまとめていた。

KotlinでgRPC。grpc-javaのTLS with JDKとTLS with OpenSSLの使い方をまとめた。 - 平日インプット週末アウトプットぶろぐ

プロジェクトではOpenSSLをつかっていたのだがALPN対応ができていなかった。最初はコンテナのubutsuが14.04/OpenSSLが1.0.1のためALPNがサポートされていないことが判明したので、OpenSSLを1.0.2にあげてみたが「ALPN protocol: h2」が出力されることはなかった。

そのため2つ目の方法のjar起動のオプションのjavaagentにjetty-alpn-agentを加える方法を試したところ「ALPN protocol: h2」の出力が確認できた。これでServer側の対応は準備ができた。そして実機からも無事接続が確認できた。解決である。

まとめ

ということで、タイトルのとおり「grpc-javaのServerでTLSを有効にした場合はALPN対応しているか確認すべし」を教訓として学んだ。

コード

TLSが有効なgRPC Serverに接続するgrpc-javaのクライアントテストをgithubに追加しています。

テストコードはこちら