quarkus: Native Image SSL Problem

Although I have followed all the directions in the documentations(https://quarkus.io/guides/native-and-ssl-guide) I am getting an annoying warning and error at the end of my microprofile rest client to the service with SSL(only in native image, not in development):

WARNING: The sunec native library, required by the SunEC provider, could not be loaded.

Caused by: java.lang.UnsatisfiedLinkError: sun.security.ec.ECKeyPairGenerator.generateECKeyPair(I[B[B)[Ljava/lang/Object; [symbol: Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair or Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair__I_3B_3B]

I had followed these steps to produce the native image:

mvn package -Pnative -Dnative-image.docker-build=true docker build -f src/main/docker/Dockerfile.native -t dockerrepo.company.com/appTodo docker run -i --rm -p 8080:8080 dockerrepo.company.com/appTodo

And I put all the SSL configuration that I can find from the documentations in the maven plugin:

                    <plugin>
                        <groupId>io.quarkus</groupId>
                        <artifactId>quarkus-maven-plugin</artifactId>
                        <version>${quarkus.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>native-image</goal>
                                </goals>
                                <configuration>
                                    <enableHttpUrlHandler>true</enableHttpUrlHandler>
                                    <enableJni>true</enableJni>
                                    <enableAllSecurityServices>true</enableAllSecurityServices>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

Any additional steps did I miss?

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Comments: 40 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Any news ?

Thanks @jamesfalkner. Your dockerfile worked for me.

I’m using quarkus-amazon-lambda extension and quarkus-amazon-dynamodb extension to access DynamoDB from AWS Lambda with custom runtime (I mean, native-image), and getting the same error:

.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
        at software.amazon.awssdk.http.apache.internal.impl.ApacheSdkHttpClient.execute(ApacheSdkHttpClient.java:72)
        at software.amazon.awssdk.http.apache.ApacheHttpClient.execute(ApacheHttpClient.java:240)
        at software.amazon.awssdk.http.apache.ApacheHttpClient.access$500(ApacheHttpClient.java:106)
        at software.amazon.awssdk.http.apache.ApacheHttpClient$1.call(ApacheHttpClient.java:221)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.executeHttpRequest(MakeHttpRequestStage.java:66)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:51)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage.execute(MakeHttpRequestStage.java:35)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:73)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallAttemptTimeoutTrackingStage.execute(ApiCallAttemptTimeoutTrackingStage.java:42)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:77)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.TimeoutExceptionHandlingStage.execute(TimeoutExceptionHandlingStage.java:39)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.doExecute(RetryableStage.java:113)
        at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.execute(RetryableStage.java:86)
        ... 28 more
Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:91)
        at sun.security.validator.Validator.getInstance(Validator.java:181)
        at sun.security.ssl.X509TrustManagerImpl.getValidator(X509TrustManagerImpl.java:318)
        at sun.security.ssl.X509TrustManagerImpl.checkTrustedInit(X509TrustManagerImpl.java:179)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:193)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
        ... 60 more
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
        at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
        at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120)
        at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104)
        at sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:89)
        ... 72 more

https://github.com/kdnakt/quarkus-sandbox/tree/master/quarkus-lambda-dynamodb

It doesn’t work for the maven plugin as well. In the documentation https://quarkus.io/guides/native-and-ssl I see

You haven’t noticed anything but, while building the image, Quarkus has automatically set java.library.path to point to the GraalVM library folder (the one containing the SunEC library).

It has also set javax.net.ssl.trustStore to point to the cacerts file bundled in the GraalVM distribution. This file contains the root certificates.

So, I expect to get a native app with included SunEC library.

However, when I execute my app I receive

Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

FWIW this also failed for me even when using Maven.

From my experiments, it seems -Djava.library.path no longer has any effect - if all the *.so files are in the same directory as the app, it works. So here’s the Dockerfile I am using:

FROM quay.io/quarkus/ubi-quarkus-native-image:19.1.1 as nativebuilder
RUN mkdir -p /tmp/ssl-libs \
  && cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs \
  && cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-libs

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY target/*-runner /work/application
COPY --from=nativebuilder /tmp/ssl-libs /work
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djavax.net.ssl.trustStore=/work/cacerts"]

I’m using exactly this dockerfile, the only change with the example in the readme is the maven target folder for the gradle build folder

FROM quay.io/quarkus/ubi-quarkus-native-image:19.1.1 as nativebuilder
RUN mkdir -p /tmp/ssl-libs/lib \
  && cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs \
  && cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-libs/lib/

FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY build/*-runner /work/application
COPY --from=nativebuilder /tmp/ssl-libs/ /work/
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djava.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/work/cacerts"]

You need to copy the cacerts file and the SunEC library inside your container (see the COPY above, the files should be $GRAALVM_HOME/jre/lib/security/cacerts for one and $GRAALVM_HOME/jre/lib/amd64/libsunec.so on Linux, it’s a bit different on macOS). You can copy them in your VM (I would suggest to put the .so in a lib/ directory).

Then you need to add a , "-Djava.library.path=./lib", -Djavax.net.ssl.trustStore=./cacerts" to your CMD.

Please report back your findings. Once we get something working, it could probably be added to the documentation.