We are building an app based on Red Hat JBoss AMQ 6. We wrap some Java code around the base image to provide extra functionalities which are lacking in AMQ 6.
Now, when the CVE of Log4j stroke, we found that this component is vulnerable because it uses log4j 1.x. Now I don't just mean our Java code uses it, but also the base image of Red Hat AMQ 6 uses it. As AMQ 6 is EOL now, Red Hat does not provide support anymore, so there will not be official releases with fix.
So, how do I remove vulnerable log4j 1.x classes from:
- my Java code
- the base image
?
I am building with jib maven plugin.
It seems mvn dependency:tree only gives info about our Java wrapper code, not about the base image. And I don't understand what does the "+" and "-" mean while it gives output like this:
[INFO] +- org.jboss.resteasy:resteasy-jaxrs:jar:3.7.0.Final:compile
[INFO] | +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:jar:1.0.2.Final:compile
[INFO] | +- org.jboss.spec.javax.xml.bind:jboss-jaxb-api_2.3_spec:jar:1.0.1.Final:compile
[INFO] | +- org.reactivestreams:reactive-streams:jar:1.0.2:compile
[INFO] | +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] | +- org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec:jar:1.0.1.Final:compile
[INFO] | +- javax.activation:activation:jar:1.1.1:compile
[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.4:compile
[INFO] | | +- org.apache.httpcomponents:httpcore:jar:4.4.7:compile
[INFO] | | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | | \- commons-codec:commons-codec:jar:1.10:compile
[INFO] | +- commons-io:commons-io:jar:2.5:compile
[INFO] | +- net.jcip:jcip-annotations:jar:1.0:compile
[INFO] | \- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
Does + mean that it can be expanded further but is not shown here?
Some background here: https://nvd.nist.gov/vuln/detail/CVE-2021-44228
Step 1: Dealing with our wrapping Java code base
For our code, we do:
And we found some dep from other teams bringing in transitive log4j 1.17. Informed that team and they fixed that in a recent version, we just change in our pom the version to be it, and our pom is fixed.
If your dependency is not maintained anymore, you can enter the artifactory of your organization, and manually look for the classes below in all jars you need(the list is long, because apart from CVE-2021-4104 which mentions JMSAppender, I found log4j 1.x has a lot of other vulnerabilities and more classes should be removed)
org/apache/log4j/net/SocketServer.classorg/apache/log4j/net/SimpleSocketServer.class(just in case)org/apache/log4j/net/SocketAppender.classorg/apache/log4j/net/SMTPAppender$1.classorg/apache/log4j/net/SMTPAppender.classorg/apache/log4j/net/JMSAppender.classorg/apache/log4j/net/JMSSink.classorg/apache/log4j/net/JDBCAppender.classorg/apache/log4j/chainsaw/*.classIf you cannot fix your internal Nexus repo/artifactory, you can find the jar of log4j in local Maven registry (under
~/.m2) and remove the class; then you build your app again; but remember don't use-Uto redownload the jar from remote registry.Step 2: Dealing with base image jars
To find other libs in the base image containing log4j is more complicated.
Tampering the layers by removing the classes files cannot go undetected by Docker daemon. The sha256 value changes, you have to replace the sha256 value in the json file in the main dir with new
sha256sum layer.tar; but even with that, Docker daemon will give error when you load the tar:Cannot open /var/lib/docker/tmp-xxxx/...: file not foundor so.Then I tried to create a script to remove the classes at runtime, right before running the app, and define a new entrypoint in jib to run it before running the app.
But then I found it will slow down pod startup; unresponsive pods may be restarted by Openshift, causing unwanted delay and errors. But the output of this script gives me an idea of which jars contain the classes to remove, which is a solid basis for my next solution.
At last, I came up with a perfect solution
docker runthe image, and note down the jars' names in the output of the script.provideddependencies in pom.xmltarget/dependency)target/dependencydir to remove vulnerable classes, while building the image with jibBy doing this, we eliminate the vulnerable classes while building the image, pod startup speed is not compromised, and the binary transferred to production image registry is already safe.
An advantage of this approach is we are not limited by available tools provided by the container because the script runs now in our local environment. We can install whatever tool we need and use them in the script. For example, in the original script I defined function
extract_remove_repackageto complete a simple task of extracting+remove classes+repackaging, only becausezipis not installed in the base image. But in my local machine, this can be done byzipin one line,You have to make sure to bind 3, 4 and 5 to different maven build phases, so that they happen in such order. I bind 3) to
compile, 4) toprocess-classesand 5) topackage.Implementation details below:
src/main/jib/opt/amq/bin, so it could be copied into container. Also you needed the new entrypoint script here in the same folder. Now in this solution, moved tosrc/main/scripts)fix_log4j_1.x_cves.sh:copy-dependencypluginexec-plugin:jib plugin: (needs to be > 3.0.0 to be able to use<path><inclueds>)