The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

ネイティブイメージでのSSLの利用

常時SSL接続の時代へと急速に移行しているので、SSLを利用できることは非常に重要です。

ネイティブ実行可能ファイルは標準ではSSLをサポートしていないので、このガイドではネイティブ実行可能ファイルでSSLをサポートする方法を説明します。

JDK モードでは特に変更しなくても SSL がサポートされているので、ネイティブ実行可能ファイルを使用する予定がない場合はパスできます。

前提条件

このガイドを完成させるには、以下が必要です:

  • 20分弱

  • IDE

  • GraalVMがインストールされ、JAVA_HOMEGRAALVM_HOME が適切に設定されていること

  • Apache Maven 3.9.6

このガイドはRESTクライアントガイドに基づいているので、最初にこのMavenプロジェクトを取得する必要があります。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

プロジェクトは resteasy-client-quickstart ディレクトリ にあります。

修正不要にみえる?!?

アプリケーションの設定ファイル ( src/main/resources/application.properties ) を開くと、以下の行が存在します:

quarkus.rest-client."org.acme.rest.client.ExtensionsService".url=https://stage.code.quarkus.io/api

これは、REST クライアントが SSL REST サービスに接続するように設定しています。

このガイドの目的から、RESTクライアントの応答をスタブ化する組み込み型のWireMockサーバーを起動する設定を削除して、テストが実際に https://stage.code.quarkus.io/api への呼び出しを伝播するようにする必要もあります。テストファイル src/test/java/org/acme/rest/client/ExtensionsResourceTest.java を更新し、次の行を削除します。

@QuarkusTestResource(WireMockExtensions.class)

ExtensionsResourceTest クラスから。

それでは、アプリケーションをネイティブ実行可能ファイルとしてビルドし、テストを実行してみましょう:

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative

そして、次のような結果が得られます:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

はい、修正不要で動作し、このガイドはかなり役立たずであるように見えますね。

実際は、そうではありません。マジックはネイティブ実行可能ファイルをビルドするときに起こります:

[INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] /opt/graalvm/bin/native-image -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=3 -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Duser.language=en -J-Duser.country=IE -J-Dfile.encoding=UTF-8 --features=io.quarkus.runner.Feature,io.quarkus.runtime.graal.ResourcesFeature,io.quarkus.runtime.graal.DisableLoggingFeature -J--add-exports=java.security.jgss/sun.security.krb5=ALL-UNNAMED -J--add-opens=java.base/java.text=ALL-UNNAMED -J--add-opens=java.base/java.io=ALL-UNNAMED -J--add-opens=java.base/java.lang.invoke=ALL-UNNAMED -J--add-opens=java.base/java.util=ALL-UNNAMED -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy\$BySpaceAndTime -H:+AllowFoldMethods -J-Djava.awt.headless=true -H:FallbackThreshold=0 --link-at-build-time -H:+ReportExceptionStackTraces -H:-AddAllCharsets -H:EnableURLProtocols=http,https -H:NativeLinkerOption=-no-pie -H:-UseServiceLoaderFeature -H:+StackTrace -J--add-exports=org.graalvm.sdk/org.graalvm.nativeimage.impl=ALL-UNNAMED -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.configure=ALL-UNNAMED -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.proxy=ALL-UNNAMED -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.localization=ALL-UNNAMED rest-client-quickstart-1.0.0-SNAPSHOT-runner -jar rest-client-quickstart-1.0.0-SNAPSHOT-runner.jar

重要なのは、Quarkusによって自動的に追加された以下のオプションです。

-H:EnableURLProtocols=http,https

これらは、ネイティブ実行可能ファイルのネイティブなSSLサポートを有効にします。しかし、手動で設定するべきではありません。この目的のために、以下のような優れた設定プロパティが用意されています。

SSLが事実上の標準となっている現在、私たちのエクステンションの一部では自動的にSSLのサポートを有効にすることにしました:

  • Agroalコネクションプールエクステンション ( quarkus-agroal )、

  • Amazon Services エクステンション(quarkus-amazon-*),

  • Consul Config エクステンション(quarkus-consul-config),

  • Elasticsearch クライアントエクステンション ( quarkus-elasticsearch-rest-clientquarkus-elasticsearch-java-client ) と、Hibernate Search Elasticsearch 拡張 ( quarkus-hibernate-search-orm-elasticsearch ) 、

  • Elytron Security OAuth2 エクステンション(quarkus-elytron-security-oauth2),

  • gRPC エクステンション(quarkus-grpc),

  • Infinispan クライアントエクステンション ( quarkus-infinispan-client )、

  • Jaeger エクステンション ( quarkus-jaeger )、

  • JGit エクステンション ( quarkus-jgit )、

  • JSch エクステンション(quarkus-jsch),

  • Apicurio Registry 2.xのAvroライブラリが使用されている場合、Kafka Client エクステンション( quarkus-kafka-client),

  • Keycloak Authorization エクステンション(quarkus-keycloak-authorization),

  • Kubernetes クライアントエクステンション ( quarkus-kubernetes-client ),

  • Logging Sentry エクステンション(quarkus-logging-sentry),

  • Mailer エクステンション ( quarkus-mailer ),

  • MongoDB client エクステンション(quarkus-mongodb-client),

  • Neo4j エクステンション ( quarkus-neo4j ),

  • OIDC とOIDC client エクステンション(quarkus-oidc and quarkus-oidc-client),

  • IBM DB2 エクステンションのReactiveクライアント(quarkus-reactive-db2-client),

  • PostgreSQLエクステンションのReactiveクライアント ( quarkus-reactive-pg-client ) ,

  • MySQL エクステンションの Reactive クライアント ( quarkus-reactive-mysql-client ),

  • Reactive client for Microsoft SQL Server エクステンション(quarkus-reactive-mssql-client),

  • Redis クライアントエクステンション ( quarkus-redis-client ),

  • RESTEasy Classic REST クライアントエクステンション (quarkus-resteasy-client),

  • REST Client エクステンション(quarkus-rest-client),

  • SmallRye GraphQL Client エクステンション(quarkus-smallrye-graphql-client),

  • Spring Cloud Config client エクステンション(quarkus-spring-cloud-config-client),

  • Vault エクステンション(quarkus-vault),

  • Cassandraクライアントエクステンション ( cassandra-quarkus-client ) 、

これらのエクステンションのいずれかがプロジェクトに含まれている限り、SSLサポートはデフォルトで有効になります。

いずれも使用しておらず、とにかくSSLサポートを有効にしたい場合は、以下を設定に追加してください。

quarkus.ssl.native=true

ここで、あとで役立つので、ネイティブ実行可能ファイルのサイズを確認してみましょう:

$ ls -lh target/resteasy-client-quickstart-1.0.0-SNAPSHOT-runner
-rwxrwxr-x. 1 gandrian gandrian 46M Jun 11 13:01 target/rest-client-quickstart-1.0.0-SNAPSHOT-runner

では、SSLを無効にしてどうなるか見てみましょう

Quarkusには、SSLのサポートを完全に無効にするオプションがあります。なぜでしょうか?それは、一定のコストがかかるからです。ですから、必要ないと確信している場合は、完全に無効にすることができます。

まずは、RESTサービスのURLを変えずに無効化して様子を見てみましょう。

src/main/resources/application.properties を開いて、以下の行を追加します:

quarkus.ssl.native=false

そして、またビルドしてみましょう:

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative

ネイティブ実行可能ファイルのテストは、以下のエラーで失敗します:

Caused by: java.lang.IllegalArgumentException: https://stage.code.quarkus.io/api requires SSL support but it is disabled. You probably have set quarkus.ssl.native to false.

このエラーは、ネイティブ実行可能ファイルで明示的に有効にしない状態でSSLを使用しようとしたときに発生するエラーです。

では、 src/main/resources/application.properties でRESTサービスのURLを変更して、SSLを使用し ない ように変更してみましょう:

quarkus.rest-client."org.acme.rest.client.ExtensionsService".url=http://stage.code.quarkus.io/api

また、 http://stage.code.quarkus.io/api は 302 ステータスコードで応答するので、 -DskipTests のテストもスキップする必要があります。

ではまたビルドしてみましょう:

コマンドラインインタフェース
quarkus build --native -DskipTests
Maven
./mvnw install -Dnative -DskipTests

ネイティブ実行可能ファイルのビルドオプションをよく確認してみると、SSL関連のオプションがなくなっているのがわかります。

[INFO] [io.quarkus.creator.phase.nativeimage.NativeImagePhase] /opt/graalvm/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dcom.sun.xml.internal.bind.v2.bytecode.ClassTailor.noOptimize=true -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -jar rest-client-1.0.0-SNAPSHOT-runner.jar -J-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 -H:+PrintAnalysisCallTree -H:EnableURLProtocols=http -H:-SpawnIsolates -H:+JNI --no-server -H:-UseServiceLoaderFeature -H:+StackTrace

そして以下のようになります:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

SSLを有効にしたネイティブ実行可能ファイルのサイズを確認したのを覚えていますか?SSLサポートを完全に無効にした状態でもう一度確認してみましょう:

$ ls -lh target/resteasy-client-quickstart-1.0.0-SNAPSHOT-runner
-rwxrwxr-x. 1 gandrian gandrian 35M Jun 11 13:06 target/resteasy-client-quickstart-1.0.0-SNAPSHOT-runner

はい、以前は 46MB だったのが 35MB になりました。SSLはネイティブの実行可能サイズで11MBのオーバーヘッドを持っています。

そして、それだけではありません。

クリーンな状態でもう一回

設定ファイルに変更した内容を元に戻し、以下のコマンドでSSLを有効に戻してみましょう。

git checkout -- src/main/resources/application.properties

そして、もう一度ネイティブ実行可能ファイルをビルドしてみましょう:

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative

TrustStoreのパス

この動作は、GraalVM 21.3+の新機能です。

GraalVMは、ビルド時と実行時の両方の証明書設定をサポートしています。

ビルド時設定

ビルド時アプローチでは、適切な証明書がビルド時に追加され、その後は決して変更できないという「不変のセキュリティ」の原則を採用しています。これにより、アプリケーションが本番環境にデプロイされる際に、有効な証明書のリストが改ざんされないことが保証されます。

しかし、これにはいくつかの欠点があります。

  • すべての環境で同じ実行可能ファイルを使用している場合、証明書の有効期限が切れると、アプリケーションを再構築し、新しい証明書を使って本番環境に再展開する必要があり、不便です。

  • さらに悪いことに、セキュリティ侵害が原因で証明書が失効した場合、その証明書を組み込んだすべてのアプリケーションを適時に再構築し、再展開する必要があります。

  • このため、すべての環境(DEV、TEST、PRODなど)に対応したすべての証明書をアプリケーションに追加する必要があります。つまり、DEVでは必要だが他の場所では使用してはいけない証明書が、本番環境ではそのまま使用されてしまうということです。

  • ビルド時にすべての証明書を提供すると、CIが複雑になります。特に、Kubernetesのような動的な環境では、有効な証明書がプラットフォームから /var/run/secrets/kubernetes.io/serviceaccount/ca.crt PEMファイルで提供されます。

  • 最後に、お客様の環境に合わせて専用のビルドを提供しないサードパーティのソフトウェアとは相性が良くありません。

Creating a native executable using build time certificates essentially means that the root certificates are fixed at image build time, based on the certificate configuration used at build time (which for Quarkus means when you perform a build having quarkus.native.enabled=true set). This avoids shipping a cacerts file or requiring a system property be set in order to set up root certificates that are provided by the OS where the binary runs.

このような状況では、 javax.net.ssl.trustStore のようなシステムプロパティは実行時には効果がないので、デフォルトを変更する必要がある場合には、これらのシステムプロパティをイメージのビルド時に提供する必要があります。最も簡単な方法は、 quarkus.native.additional-build-args を設定することです。例えば、以下のようになります。

quarkus.native.additional-build-args=-J-Djavax.net.ssl.trustStore=/tmp/mycerts,-J-Djavax.net.ssl.trustStorePassword=changeit

上記は /tmp/mycerts の証明書がネイティブバイナリーに焼き込まれ、デフォルトの cacerts に 追加で 使用されることを保証します。カスタム TrustStore を含むファイルはその内容がネイティブバイナリに焼きこまれているので、実行時に存在する必要は ありません (そしておそらく存在すべきではありません)。

実行時設定

21.3以降GraalVMでサポートされている実行時証明書設定を使用すると、通常のJavaプログラムやjvmモードのQuarkusと比べて、特別な追加設定は必要ありません。 詳細については、「ネイティブイメージでのGraalVM証明書管理」ガイドの 実行時オプション セクションを参照してください。

コンテナーへの対応

コンテナー内でネイティブバイナリーを実行する際に特別な対応を取る必要はありません。前のセクションで説明したように、ネイティブバイナリーがカスタムTrustStoreを使って適切にビルドされていれば、コンテナー内でも正常に動作します。

まとめ

私たちは、SSLを使ったネイティブ実行可能ファイルのビルドを容易にし、様々なタイプのセキュリティ要件に対処するための複数のオプションを提供します。

関連コンテンツ