このエントリは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コメントにもあるように、カスタムセキュリティを指定し、署名検証を無効化するしかない。

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だったりする)。