Skip to content

Commit

Permalink
Remove warning on build time truststore property
Browse files Browse the repository at this point in the history
(cherry picked from commit a82419f)
  • Loading branch information
vsevel authored and gsmet committed Dec 23, 2021
1 parent aa67c38 commit b16f1c5
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,6 @@ public class MainClassBuildStep {
static final String LOG = "LOG";
static final String JAVA_LIBRARY_PATH = "java.library.path";

private static final String JAVAX_NET_SSL_TRUST_STORE = "javax.net.ssl.trustStore";
private static final String JAVAX_NET_SSL_TRUST_STORE_TYPE = "javax.net.ssl.trustStoreType";
private static final String JAVAX_NET_SSL_TRUST_STORE_PROVIDER = "javax.net.ssl.trustStoreProvider";
private static final String JAVAX_NET_SSL_TRUST_STORE_PASSWORD = "javax.net.ssl.trustStorePassword";
private static final List<String> BUILD_TIME_TRUST_STORE_PROPERTIES = List.of(JAVAX_NET_SSL_TRUST_STORE,
JAVAX_NET_SSL_TRUST_STORE_TYPE, JAVAX_NET_SSL_TRUST_STORE_PROVIDER, JAVAX_NET_SSL_TRUST_STORE_PASSWORD);

public static final String GENERATE_APP_CDS_SYSTEM_PROPERTY = "quarkus.appcds.generate";

private static final FieldDescriptor STARTUP_CONTEXT_FIELD = FieldDescriptor.of(Application.APP_CLASS_NAME, STARTUP_CONTEXT,
Expand Down Expand Up @@ -236,22 +229,6 @@ void build(List<StaticBytecodeRecorderBuildItem> staticInitTasks,
.ifNonZero(mv.invokeStaticMethod(ofMethod(ImageInfo.class, "inImageRuntimeCode", boolean.class)))
.trueBranch();

// GraalVM uses the build-time trustStore and bakes the backing classes of the TrustStore into the the native binary,
// so we need to warn users trying to set the trust store related system properties that it won't have an effect
for (String property : BUILD_TIME_TRUST_STORE_PROPERTIES) {
ResultHandle trustStoreSystemProp = inGraalVMCode.invokeStaticMethod(
ofMethod(System.class, "getProperty", String.class, String.class),
mv.load(property));

BytecodeCreator inGraalVMCodeAndTrustStoreSet = inGraalVMCode.ifNull(trustStoreSystemProp).falseBranch();
inGraalVMCodeAndTrustStoreSet.invokeVirtualMethod(
ofMethod(Logger.class, "warn", void.class, Object.class),
inGraalVMCodeAndTrustStoreSet.readStaticField(logField.getFieldDescriptor()),
inGraalVMCodeAndTrustStoreSet.load(String.format(
"Setting the '%s' system property will not have any effect at runtime. Make sure to set this property at build time (for example by setting 'quarkus.native.additional-build-args=-J-D%s=someValue').",
property, property)));
}

mv.invokeStaticMethod(ofMethod(Timing.class, "mainStarted", void.class));
startupContext = mv.readStaticField(scField.getFieldDescriptor());

Expand Down Expand Up @@ -468,7 +445,6 @@ private void writeRecordedBytecode(BytecodeRecorderImpl recorder, String fallbac

/**
* registers the generated application class for reflection, needed when launching via the Quarkus launcher
*
*/
@BuildStep
ReflectiveClassBuildItem applicationReflection() {
Expand Down
39 changes: 24 additions & 15 deletions docs/src/main/asciidoc/native-and-ssl.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -225,16 +225,28 @@ And let's build the native executable again:

[WARNING]
====
This behavior is new to GraalVM 19.3+.
This behavior is new to GraalVM 21.3+.
====

When creating a native binary, GraalVM embraces the principle of "immutable security" for the root certificates.
This essentially means that the root certificates are fixed at image build time, based on the certificate configuration used at that build time
(which for Quarkus means when you perform a build having `quarkus.package.type=native` 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.
GraalVM supports both build time and runtime certificate configuration.

As a consequence, system properties such as `javax.net.ssl.trustStore` do not have an effect at
=== Build time configuration

The build time approach favors the principle of "immutable security" where the appropriate certificates are added at build time, and can never be changed afterward.
This guarantees that the list of valid certificates cannot be tampered with when the application gets deployed in production.

However, this comes with a few drawbacks:

* If you use the same executable in all environments, and a certificate expires, the application needs to be rebuilt, and redeployed into production with the new certificate, which is an inconvenience.
* Even worse, if a certificate gets revoked because of a security breach, all applications that embed this certificate need to be rebuilt and redeployed in a timely manner.
* This requires also to add into the application all certificates for all environments (e.g. DEV, TEST, PROD), which means that a certificate that is required for DEV but should not be used elsewhere, will make its way anyway in production.
* Providing all certificates at build time complicates the CI, specifically in dynamic environments such as Kubernetes where valid certificates are provided by the platform in the `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` PEM file.
* Lastly, this does not play well with third party software that do not provide a dedicated build for each customer environment.

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.package.type=native` 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.

In this situation, system properties such as `javax.net.ssl.trustStore` do not have an effect at
run time, so when the defaults need to be changed, these system properties must be provided at image build time.
The easiest way to do so is by setting `quarkus.native.additional-build-args`. For example:

Expand All @@ -244,11 +256,11 @@ quarkus.native.additional-build-args=-J-Djavax.net.ssl.trustStore=/tmp/mycerts,-
----

will ensure that the certificates of `/tmp/mycerts` are baked into the native binary and used *in addition* to the default cacerts.
The file containing the custom TrustStore does *not* (and probably should not) have to be present at runtime as its content has been baked into the native binary.

[IMPORTANT]
====
The file containing the custom TrustStore does *not* have to be present at runtime as its content has been baked into the native binary.
====
=== Run time configuration

Using the runtime certificate configuration, supported by GraalVM since 21.3 does not require any special or additional configuration compared to regular java programs or Quarkus in jvm mode. See the https://www.graalvm.org/reference-manual/native-image/CertificateManagement/#run-time-options[GraalVM documentation] for more information.

[#working-with-containers]
=== Working with containers
Expand All @@ -258,7 +270,4 @@ as described in the previous section, it will work properly in container as well

== Conclusion

We make building native executable easy and, even if the SSL support in GraalVM is still requiring some serious thinking,
it should be mostly transparent when using Quarkus.

We track GraalVM progress on a regular basis so we will promptly integrate in Quarkus any improvement with respect to SSL support.
We make building native executable using SSL easy, and provide several options to cope well with different types of security requirements.

0 comments on commit b16f1c5

Please sign in to comment.