このエントリは2022/10/18現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容との乖離が発生する可能性があります。
問い合わせ
タイトル通りの内容が届いた。とあるREST APIにHTTPSでアクセスするアプリケーションをコンテナー上で実行すると、以下の例外が発生した、とのこと。
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
もうちょっと深く尋ねてみた。
- distrolessのコンテナーイメージをベースイメージとして利用
- jlinkで作成したJDK 17ベースのカスタムJREを利用
- full JDK(ローカル環境も含む)のコンテナーであれば、問題なく動作
原因
JCA (Java Cryptography Architecture、Java暗号化アーキテクチャ) と互換性のあるセキュリティプロバイダーがカスタムJREに含まれていなかったことが原因であった。本件は以下のドキュメントにも記載がある。
JCA と暗号化のための JCE プロバイダー / JCE Provider for JCA and Crypto
https://learn.microsoft.com/java/openjdk/java-security#jce-provider-for-jca-and-crypto
OpenJDKの場合、jdk.crypto.ec
モジュールにJava Cryptography Extension (JCE) の既定の実装プロバイダーが含まれているが、jdeps
で必要なモジュールを識別し、jlink
でカスタムJREを作成する場合、このjdk.crypto.ec
モジュールが含まれない(依存関係を認識できない)ことがある。
TLSのための依存関係が入っているLinuxイメージ上で実行している場合は、カスタムJREであってもHTTPSでのアクセスが可能の場合がある。例えばHelidon 3.0.1 (MP) でとあるREST APIにアクセスするアプリケーションをカスタムJREで動作させるようにコンテナーイメージを作成したときの出力のスクリーンショット。確かに依存モジュールとしてjdk.crypto.ec
はヒットしていない。

カスタムJREに対して–list-modulesを実行しても再確認できる。

例えばdebian-slimイメージ上でこのカスタムJREを使い上記アプリケーションを実行すると問題なく動作するが、distrolessイメージ上の場合、明示的に必要なモジュールを含めたり、依存関係を追加指定したりしなければhandshake_failureが発生する。3rdパーティープロバイダーを利用しないのであれば、jlinkでカスタムJREを作成する際に、このjdk.crypto.ec
モジュールを明示的に指定しなければならない。これはJDKのバージョンを問わないため、JDK 19でも同じ事象が発生する。