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 negotiated
とALPN 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対応しているかOpenSSLのSSLクライアントで確認できるので忘れずに実施する
openssl s_client -alpn h2 -connect <domain>:<port>
- 出力に
ALPN protocol: h2
があるか確認する
- grpc-javaをつかっているならクライアント接続に用いられるChannelでテストを実施してクロスチェックを強化する
- Androidは
OkHttpChannelBuilder
を用いるのでServerのテストにもOkHttpChannelBuilderを想定したクライアントのテストを加える
- Androidは
- コンテナのOpenSSLをALPNサポートしているVersionにしてもALPN対応できていなかった件については引き続き調査を進める。
ということで、タイトルのとおり「grpc-javaのServerでTLSを有効にした場合はALPN対応しているか確認すべし」を教訓として学んだ。
コード
TLSが有効なgRPC Serverに接続するgrpc-javaのクライアントテストをgithubに追加しています。
テストコードはこちら。