Building DevSecOps solutions using AWS, Terraform and Kubernetes

Dockerfile Linting

  • 8th December 2024

Introduction

Linting can be used to verify that your Dockerfiles are adhering to a set of predefined guidelines. There are lots of linters available, but let’s look at using hadolint.

In our last blog post we created a DockerfileGood that uses multi-stage builds to reduce the image size and attack surface. However, it still contains further issues that need addressed.

Prerequisites

This blog post assumes:

  • You already have Docker installed
  • You have reviewed Hadolint and are comfortable installing it

Lint Example

Let’s recreate our DockerfileGood file from the last blog. Then we will run the hadolint linter against it to see where we can improve it.

1) Create Dockerfile

Create DockerfileGood:

FROM ubuntu:24.04
WORKDIR /app

# Pretend to install build tools
RUN dd if=/dev/zero of=mock-build-tools.zip  bs=100M  count=1

# Pretent to use build tools to create our script
RUN echo "print(\"Hello World\")" > main.py

# Remove our mocked build tools
RUN rm mock-build-tools.zip

# Create a new image and only copy over the files we want to keep
FROM ubuntu:24.04
COPY --from=0 /app /app

CMD echo "Hello World"

And run our linter command:

docker run --rm -i hadolint/hadolint hadolint - < DockerfileGood

Immediately you will see this needs improvements:

-:9 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
-:12 DL3022 warning: `COPY --from` should reference a previously defined `FROM` alias
-:14 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments
2) Fix Issues and re-run

Let’s fix our issues, and create DockerfileBetter:

FROM ubuntu:24.04 as build
WORKDIR /app

# Pretend to install build tools
# Pretent to use build tools to create our script
# Remove our mocked build tools
RUN dd if=/dev/zero of=mock-build-tools.zip  bs=100M  count=1 \
 && RUN echo "print(\"Hello World\")" > main.py \
 && RUN rm mock-build-tools.zip

# Create a new image and only copy over the files we want to keep
FROM ubuntu:24.04
COPY --from=build /app /app

CMD ["echo", "Hello World"]

Now re-run our linter:

docker run --rm -i hadolint/hadolint hadolint - < DockerfileBetter

You will see this passes as expected.

3) Change Trust Registries

Let’s take this a step further and enforce a private registry. We can utilise the --trusted-registry parameter for this:

docker run --rm -i hadolint/hadolint hadolint --trusted-registry docker.rhuaridh.co.uk - < DockerfileBetter

You will then see this image:

-:1 DL3026 error: Use only an allowed registry in the FROM image
-:12 DL3026 error: Use only an allowed registry in the FROM image

That’s it! We can now check to make sure staff are not using base images from untrusted sources.

Summary

Linting can be a useful tool to enforce best practice and to help secure your Dockerfiles.

For further help on configuring Hadolint, please check out their documentation.

If you’re using CICD, check out their continuous-integration section in their documentation.

Rhuaridh

Please get in touch through my socials if you would like to ask any questions - I am always happy to speak tech!