Azureの依存関係を含むアプリケーションをNative Imageにしようとしたら失敗する

このエントリは2024/09/16現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容からの乖離が発生する可能性があります。

お問い合わせ

久しぶりにいつもの人から以下のような問い合わせが届いた。

現在GraalVMでNative Imageアプリケーションを作成し、それをAzure Container Appsで実行しようとしている。QuarkusであってもSpring Bootであっても、Native Imageアプリケーションのビルドに成功する場合と失敗する場合がある。何か構成すべき事柄があるのか?

「これ、前のエントリに書いたような」と思いつつ、いったんは背景を聞いてみた。

  • Spring Boot、QuarkusなどでExecutable JARを生成し、native-imageコマンドを使ってNative Image化している。
  • うまくいくときと行かないときがある。うまく行かないのは、Spring Cloud Azureの依存関係を追加している場合。Azure関連の依存関係を含まない場合には特に問題なくNative Imageアプリケーションを生成できる、とのこと。
  • 発生するエラーは以下のようなもの。
The build process encountered an unexpected error:

com.oracle.svm.core.util.VMError$HostedError: InternalFeature defined by com.oracle.svm.hosted.reflect.ReflectionFeature unexpectedly failed with a(n) java.lang.SecurityException
  at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:86)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.FeatureHandler.handleFeatureError(FeatureHandler.java:287)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:92)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.setupNativeImage(NativeImageGenerator.java:964)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:590)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:550)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:539)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:721)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.start(NativeImageGeneratorRunner.java:143)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:98)
Caused by: java.lang.SecurityException: class "com.azure.monitor.applicationinsights.spring.AzureSpringMonitorAutoConfig"'s signer information does not match signer information of other classes in the same package
  at java.base/java.lang.ClassLoader.checkCerts(ClassLoader.java:1173)
  at java.base/java.lang.ClassLoader.preDefineClass(ClassLoader.java:917)
  at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1025)
  at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.defineClass(NativeImageClassLoader.java:490)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.findClassViaClassPath(NativeImageClassLoader.java:442)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageClassLoader.loadClass(NativeImageClassLoader.java:629)
  at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
  at java.base/java.lang.Class.forName0(Native Method)
  at java.base/java.lang.Class.forName(Class.java:534)
  at java.base/java.lang.Class.forName(Class.java:513)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.ImageClassLoader.forName(ImageClassLoader.java:307)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.ImageClassLoader.forName(ImageClassLoader.java:303)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.ImageClassLoader.findClass(ImageClassLoader.java:296)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.RegistryAdapter.resolveType(RegistryAdapter.java:77)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ReflectionRegistryAdapter.resolveType(ReflectionRegistryAdapter.java:48)
  at org.graalvm.nativeimage.builder/com.oracle.svm.core.configure.ReflectionConfigurationParser.parseClass(ReflectionConfigurationParser.java:94)
  at org.graalvm.nativeimage.builder/com.oracle.svm.core.configure.ReflectionConfigurationParser.parseClassArray(ReflectionConfigurationParser.java:74)
  at org.graalvm.nativeimage.builder/com.oracle.svm.core.configure.ReflectionConfigurationParser.parseAndRegister(ReflectionConfigurationParser.java:69)
  at org.graalvm.nativeimage.builder/com.oracle.svm.core.configure.ConfigurationParser.parseAndRegister(ConfigurationParser.java:75)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ConfigurationParserUtils.doParseAndRegister(ConfigurationParserUtils.java:130)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ConfigurationParserUtils.lambda$parseAndRegisterConfigurations$2(ConfigurationParserUtils.java:116)
  at java.base/java.util.stream.ReferencePipeline$4$1.accept(ReferencePipeline.java:214)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ConfigurationParserUtils$1.tryAdvance(ConfigurationParserUtils.java:109)
  at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
  at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
  at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276)
  at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
  at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
  at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
  at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
  at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
  at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
  at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
  at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
  at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
  at java.base/java.util.stream.IntPipeline.reduce(IntPipeline.java:515)
  at java.base/java.util.stream.IntPipeline.sum(IntPipeline.java:473)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ConfigurationParserUtils.parseAndRegisterConfigurations(ConfigurationParserUtils.java:118)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.config.ConfigurationParserUtils.parseAndRegisterConfigurations(ConfigurationParserUtils.java:75)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionFeature.duringSetup(ReflectionFeature.java:265)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.lambda$setupNativeImage$16(NativeImageGenerator.java:964)
  at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:90)
  ... 7 more

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  53.612 s
[INFO] Finished at: 2024-09-16T05:30:09Z
[INFO] ------------------------------------------------------------------------

Spring Cloud Azureとは以下のもの(日本語ドキュメントだとAzure Spring Cloudになっているのはなぜかよくわからん)。

Azure Spring Cloud とは / What is Spring Cloud Azure?
https://learn.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure-overview

原因

Native Imageビルド時の署名検証を無効化していないため。まんま前のエントリに記載した通りである。

具体的には、上記例外の以下の箇所で、「署名者の情報が同じパッケージの別のクラスの署名情報と一致しない」というエラーが出ている。これはNative Image生成時に署名を確認しているが、Azure(というかMicrosoftが)提供しているJARが署名されているのに対し、その他のものが署名されていないことが原因で発生している。

java.lang.SecurityException: class "com.azure.monitor.applicationinsights.spring.AzureSpringMonitorAutoConfig"'s signer information does not match signer information of other classes in the same package

回避策

現在のところ、以下のIssueコメントにもあるように、カスタムセキュリティを指定し、署名検証を無効化するしかない。

[BUG] Occurs SecurityException when building native image based on Spring Cloud Azure Native support #30320
https://github.com/Azure/azure-sdk-for-java/issues/30320#issuecomment-1344445807

src/main/resources/custom.propertyに以下の内容を含めておく。

jdk.jar.disabledAlgorithms=MD2, MD5, RSA, DSA

そして、native-maven-pluginのJVM引数に指定しておく。

<plugin>
  <groupId>org.graalvm.buildtools</groupId>
  <artifactId>native-maven-plugin</artifactId>
  <configuration>
    <buildArgs>
      <buildArg>...</buildArg>
      <jvmArgs>-Djava.security.properties=src/main/resources/custom.security</jvmArgs>
    </buildArgs>
  </configuration>
</plugin>

この方式は、Azureが提供する依存関係だけでなく、署名したJARを使ったアプリケーションをNative Image化する場合に当てはまる。そのため、もし上記エラーメッセージが出ているのであればちょっと思い出すとよいかもしれない(もっとも、署名済みJARを提供している組織は少なく、その少ない1組織がMicrosoftだったりする)。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください