paketo-buildpacks / libjvm

A library and helper applications that form the basis for building the different Paketo-style JVM-providing buildpacks
Apache License 2.0
19 stars 21 forks source link

Add support for specifying JRE or JDK #81

Closed ethlo closed 3 years ago

ethlo commented 4 years ago

When building using the spring boot plugin it would be very useful to be able to pick JRE or JDK for the final build. I would be very grateful if this could be incorporated as an option.

nebhale commented 4 years ago

The buildpack is intentionally and explicitly designed to prevent the JDK being contributed to the application images. It is widely considered to be a significant security vulnerability to include the JDK at runtime in production systems and the buildpacks are all designed to facilitate secure-by-design outcomes.

I am interested in hearing about your need for the JDK though; maybe there's some other way to deliver the functionality you need.

ethlo commented 4 years ago

Thank you! I appreciate the feedback. We use on-the-fly recompilation for reporting and ETL using the recompilation support in Lamebda[1]. It basically allows for using Java or Groovy for scripting.

If you know of other ways I can include the programmatic java compiler, I'm most grateful.

[1] - https://github.com/ethlo/lamebda

nebhale commented 4 years ago

Groovy doesn't require a JDK to run (it can self-compile on the fly using nothing but the JRE), so I don't see that particular use-case requiring the JDK. Do you have a pointer to any additional documentation on Lamebda that describes its JDK requirements?

ethlo commented 4 years ago

Groovy is one way to use it. Java is another. Java is preferred for its compile-time checking and familiarity. I have extracted the compilation part of the library into a new project here: https://github.com/ethlo/qjc and specifically the JavaCompiler here: https://github.com/ethlo/qjc/blob/master/qjc-java/src/main/java/com/ethlo/qjc/java/JavaCompiler.java

ethlo commented 4 years ago

As a side-note, could you tell me any sources for the security concern? I appreciate that the minimum amount of code deployed is ideal, but is there any known exploits where a JRE would be safer than a JDK base? Thank you!

nebhale commented 4 years ago

@ethlo thanks for your patience; I'm still mulling this one over. The overarching concern security teams find is that having compilers in containers allows for something easy to transfer, like source code (plain text), ends up in a container at which point it can be compiled into executable code and bad things can happen. This also ends up being an outright ban, in most companies, for Ruby, Python, and other interpreted runtimes inside of containers as well. Who knows if it's actual security or merely security theatre but it is one of the most important considerations we have to balance for enterprise customers.

ethlo commented 4 years ago

I appreciate the problem of balance. Making it an option would give flexibility for where a JDK is required, but of course, also open you up for "bad" configurations (including a JDK over a JRE). Personally I do not see the big problem, but smarter people than me may have a different saying in the matter.

tigerinus commented 3 years ago

In our case, often we fiddle around the JVM in the container in our test/staging environment and inspect for any root cause if there is a problem. This does require JDK environment for tools like jmap, jdb, etc.

Since it's not production environment, we wouldn't be concerned about the security risk.

Ideally we are looking for a flag to specify JDK if it's for test/staging environment and specify JRE if it's for production.

dmikusa commented 3 years ago

For the reasons Ben mentioned, this would never be the default behavior. I'm not opposed to adding a configuration option to force a JDK instead of a JRE though. When this setting is active, I would want the buildpack to emit a WARNING message indicating that a JDK is being installed instead of a JRE.

Does that seem reasonable?

kdvolder commented 3 years ago

We need this too. Our use-case is that we are building an application/service that allows applying openrewrite recipes to Java code. openrewrite requires JDK as it leverages the Java compiler in order to parse and manipulate Java code/ASTs.

Attempting to run our image without a JDK makes it fail with an error like the following:

java.lang.NoClassDefFoundError: com/sun/tools/javac/util/Context

For the reasons Ben mentioned, this would never be the default behavior.

I don't think anybody here is suggesting that it should be the default behaviour just that it should be possible to explicitly request a JDK when one's use case requires it.

As it is now, we cannot use the liberica buildpack since it produces a 'broken' image for us. This doesn't leave us with any good options really. All I can think of doing ATM is:

Neither of these options is really appealing for different reasons. And neither of these really improves the security of our images (arguably folks who really need a JDK, for whatever reason, are going to find a way to do it one way or another. Forcing them into some kind of 'doit yourself workaround' is more likely to expose them to more security issues than using the buildpack).

dmikusa commented 3 years ago

Thanks for the feedback!

use a different buildpack / VM (maybe the GraalVM buildpack because it doesn't provide a JRE so likely we'd get a JDK simply because there is no other choice there).

This is what I'd suggest. There are a handful that don't provide JRES. Off the top of my head, GraalVM, Microsoft OpenJDK, Amazon Corretto and Alibaba Dragonwell. So you could use these instructions to force an alternative JVM that doesn't have a JRE and you'd get what you need. https://paketo.io/docs/howto/java/#using-alternative-jvms

100% agreement that is not an ideal solution, just wanted to call it out as an option that would work now.

I'm going to move this issue as it would need to be a change in libjvm, consequently, the solution will be applied across all JVM providers. Possibly an option like $BP_JVM_TYPE with acceptable values of jre or jdk with a default of jre.

To the point of @tigerinus

Ideally we are looking for a flag to specify JDK if it's for test/staging environment and specify JRE if it's for production.

I don't think we could do this as buildpacks don't really have the concept of test/staging, most make assumptions that you're building for prod. However given a flag like I mentioned you could certainly build two different images one with a JDK (dev/test) and one with a JRE (prod).

ethlo commented 3 years ago

Thank you! 🙏😊