This is a guest blog from our friends at Snyk. It originally appeared here.
Today we’re pleased to announce an update to our popular Docker and Snyk vulnerability cheat sheet. Since 2020, millions of MacOS and Windows developers have been able to use docker scan
to analyze their containers in their local environments as part of their day-to-day development. This capability gives teams feedback at the time of active development for faster cycles.
Our updated cheat sheet includes information and a focus on the Log4j vulnerability covered in a number of other postings by Snyk and Docker. In this post, we’ll outline the cheat sheet and some of our enhanced guidance.
1. Scan your container images
Scanning your images is as easy as running docker scan
and we highly recommend you get in the habit of scanning your image during development. With docker scan
not only do you get fast feedback for your image as you create it, you can also use the results of the scan operation to gate your tasks. This is especially helpful when you use flags to fail the step on a pipeline.
docker scan <imagename>
Here is an example we use to show a typical docker scan
for a publicly available image. You would want to scan a public image for vulnerabilities as part of your processes. This is useful when you want to examine the contents of an image hosted on Docker Hub:
$ docker scan alpine:3.15.0 --severity high
Testing alpine:3.15.0...
Organization: atlassian-bitbucket
Package manager: apk
Project name: docker-image|alpine
Docker image: alpine:3.15.0
Platform: linux/amd64
Base image: alpine:3.15.0
Licenses: enabled
✔ Tested 14 dependencies for known issues, no vulnerable paths found.
According to our scan, you are currently using the most secure version of the selected base image
Given the recent interest in Log4j, here is a command you would use to scan specifically for the vulnerabilities (CVE-2021-44228 and CVE-2021-45046):
snyk container test wavefronthq/proxy:9.2 --app-vulns
docker scan test wavefronthq/proxy:9.2 --app-vulns
2. Use an official and current JDK in your image
You have many options for JDK versions, and we recommend you utilize an official version to keep up with the latest supported fixes. There are plenty of variations available, and your team may feel it is necessary to use a custom or variation. They will also understand the added burden and responsibility of needing to stay on top of these versions.
Using the latest JDK revision means staying in sync with security fixes, and you will likely find it is easier for your entire team to rely on a more stable and mainstream version.
Some official versions rely on tags that are easy to understand. For example, the openjdk image has different tags representing different versions of language support. Version 11 of the JDK is supported by openjdk:11
.
3. Upgrading your JDK isn’t enough
The fix cycle for the Log4Shell vulnerability was an iterative process and the first fix version was followed by additional fixes. Impacted Log4j versions included 2.14, 2.15, 2.17, and some minor versions. This was because once people found the vulnerability and applied patches, more people tested and examined the code to uncover more vulnerabilities.
One of the early thoughts was to update your JDK to pick up new libraries that worked to address underlying causes. Later, people found you should also change the setting
com.sun.jndi.ldap.object.trustURLCodebase
to false
.
This setting has the effect of preventing the use of URLs, which was an underlying cause for the vulnerability in the first place. You would only set this value to true if you really needed it, and chances are most applications do not.
4. Identify scanned images in Docker Hub
Docker worked closely with Snyk to integrate results in Docker Hub to allow as many people as possible to see Log4j results quickly and easily. The result is an in-line report showing if an image has been found to contain the vulnerability. This is a major upside for users, as it gives them a nice way to see the status.
Docker now includes scan results in DockerHub. This makes it easier for end-users to identify images that have been scanned for the Log4Shell CVE-2021-44228 and CVE-2021-45046, and if the vulnerabilities have been detected.
For example, this is an indicator you can find on a tag:
Another view shows more details, including a green badge for an image where LOG4SHELL was not detected, a red badge where it was detected, and a count of how many vulnerabilities were detected overall.
5. Use Docker Desktop 4.3.1+ with docker scan
0.11.0+
Docker Desktop already notifies you if your version is out of date, and the latest versions contain updates to best detect the Log4Shell vulnerability. Starting with Docker Desktop 4.3.1 and docker scan
0.11.0, these components are up to date for MacOS and Windows users. The latest versions of Docker Desktop are available at this link here,
Linux users are supported with docker-ce and have a different upgrade path. More details for Linux users are available in this Docker Log4j blog.
6. Don’t run as root
Over the years, we have built up knowledge based on experience. A noteworthy nugget is, “don’t run as root.” Many people start their container journey by running with defaults and it doesn’t occur to them to consider their impact. A good carryover from historical deployments is to run in a service account. Previously, your IT/ops folks would provision a user for a service and run that service as that user.
In containers, the operation requires you to create both a group and user in a Linux environment. The commands are a combination of the following:
RUN addgroup ... \
adduser ... \
chmod and chown
USER
Linux users are familiar with the addgroup
and adduser
commands to create an account for your application. The chmod
and chown
commands are present to set limits on what user has rights to run in a directory. These commands establish guardrails to protect your running container. If your application runs as root and is compromised, then your entire system is available to the attacker.
For more information, see point #1 in our Kubernetes security context blog post and cheat sheet that looks at various securityContext
settings and how to use them.
7. Use a read-only root filesystem
This simple change can have major benefits for your entire application. It is likely your application writes files to a limited number of folders. Consequently, other folders will benefit from being set to read-only. When you set key folders to read-only, attackers have limited options to where they may create temporary files and scripts.
For example, applications that provide API services are typically viewed as conduits of information and don’t store much data. Since the requirements to persist data to disk are limited, you have a great opportunity to utilize a read-only root filesystem.
One option is to utilize a read-only mount. During development, encourage your development team to mount read-only volumes with the –read-only
and verify their running container still functions. When developing locally, your team can easily iterate with docker run
commands to find a more optimal setup for a read-only filesystem.
Once your team finds a solution for local read-only volume mounts, the next step is to replicate the same functionality in your production requirements. Volumes are typically managed differently with orchestrators, and your preferred orchestrator will have options to configure similar read-only mounts.
Watch the Kubernetes Quick Hits: Use SecurityContext to run containers with a read-only filesystem video for an explanation, or point #7 in the previously mentioned cheat sheet for a Kubernetes example.
8. Upgrade your Log4j version the latest version
When the Log4j vulnerability was first detected, several fixes came out in rapid succession. It is our recommendation your team uses at least 2.17.1.
When you scan your Git repository with Snyk, you will see results indicating if you have a Log4J vulnerability and have the option to open a pull request to remediate. This is an easy and automatic way to update your application.
If you are directly using the Log4j library, you should update the dependency in your build file, typically a gradle or maven project. In your dependency list, update the version to 2.17.1 or higher.
If, however, you have a transitive dependency, you will need to update the library that brings in the out-of-date log4j version.
With Maven, you can run a command like this to find the updates for your dependencies:
mvn versions:display-dependency-updates
9. Don’t run containers in privileged mode
Development teams sometimes enable a container to run in privileged mode to test an idea, experiment, or even as part of a troubleshooting exercise. Running in privilege mode grants root permissions and capabilities.
This documentation from Docker describes what capabilities are available in privileged mode. If your team feels it is necessary to run in privileged mode, then encourage them to limit the capabilities.
Most applications do not really need elevated privileges, and since it starts with a docker run --privileged
command, it usually requires additional effort to make it work with your orchestrator.
We recommend you review the same Kubernetes quick hits video for greater context and point #5.
10. Minimize your container’s footprint
Most development teams like it when their code works and happens to be compact because it feels like we’re efficient with resources. Your container development can benefit from the same mindset. When you ship a lightweight container, it is generally better overall for several factors that include overall size and speed, but also security.
If your application does not need curl
or wget
to be present on the container, then you should remove it. If there is a new vulnerability that allows an attacker to run a command on your container, you want to limit the options available to enable access in your system. That unused but still present wget
may be the attacker’s favorite way of getting a running script onto your system.
The Log4Shell vulnerability is precisely the type of vulnerability that allows attackers to insert their favorite code just about anywhere on your system. The different examples include java snippets to run some type of code, which carries its own implications. However, if an attacker has an arsenal of scripts, they will attempt to find any way to create a file on your system’s filesystem.
Stay safe!
We have provided several tips and explanations for how to better protect yourself against software vulnerabilities like Log4Shell. The more tips you incorporate, the better your chances will be for addressing existing and future vulnerabilities. You’ll find that once you start making these tips a habit, you and your team will have better feedback cycles.