How I learned to stop worrying and love the latest tag
or how to develop a secure update strategy for container images
The latest tag gets a bad rep. A quick search or LLM prompt might make you think it's best treated like nuclear waste — stay well clear and pretend it doesn't exist. But the truth is a little more complex, and the tag has a place as part of a well-engineered update strategy.
First, let's remind ourselves of what the tag means. The tag is the part of the image name after the colon; for example, the 8 in docker pull redis:8 or latest in docker pull nginx:latest. If an image is pulled without a tag, as in docker pull redis, the latest tag is assumed (so docker pull nginx and docker pull nginx:latest are equivalent). And that's about it. There's nothing else special about the tag except by convention. By convention, the latest tag will point to the most recent version of the image. Both Docker official images and Chainguard Containers follow this convention (but not Docker Hardened Images, which eschew the tag completely).
The latest issues
What’s great about `latest` is that it’s easy to remember, and normally, you will get the freshest image available.
But what are the problems with latest? Fundamentally, the issue is that it's not reproducible; each time you pull the image, you might get a different version. That version could be a new major version of the software with associated breaking changes that destroy your build. If someone else builds your Dockerfile, they can end up with something completely different. And good luck rolling back to the previous version, as you have no record of what it was.
Image pinning
But there's a really easy fix to this problem: pin the image to a digest. If you haven't seen one before, a digest is a cryptographic hash that uniquely identifies an image’s contents. It looks like this:
docker pull cgr.dev/chainguard/redis:latest@sha256:0bbbadbd9f830a8b1ca75a72515ae57ef5418e5f5af35413183f782ac8cb98e6
Whenever you pull an image with a digest, you will get exactly the same image back. In other words, it solves the reproducibility problem mentioned above — you won't change versions without warning, everyone who uses that tag will get the same image, and rolling back just means keeping track of the previous digest.
Finding and updating digests
That still leaves a couple of issues: how do you find the digest, and how do you update it? Thankfully, there is some tooling around to help you here.
First, how to find the digest? The easiest way is to look at the output of docker pull, but that's pretty manual. An improvement is to use crane digest, which will give the output directly and is easier to embed in scripts. But suppose you have Dockerfiles with multiple FROM statements, Kubernetes YAML, and Compose files that all need to have pinned digests. In this case, a better solution is to use frizbee, which will update any image references it finds in files with pinned digests.
The next thing you will want to do is set up automatic updating of the digest when a new version is released. Ideally, this will be tied to a test suite so you are always sure a version update hasn't broken anything. At Chainguard, we use digestabot for this purpose, but Dependabot and Renovate will also work. All of these tools work by opening pull requests on a repository. Renovate has the significant advantage of being able to add digests in place (although there is also work on a Dependabot feature to do this), meaning you can combine the find-the-digest and update-the-digest phases.
Once you've done this, you will have a workflow that uses the up-to-date software but retains reproducibility and maintainability.
Another common solution is to specify a specific version (such as redis:8.2.3) in tags. In my opinion, using a digest should be preferred to specifying a specific tag for several reasons:
Digests are completely immutable; you are guaranteed to get the same image, but tags may change at any point.
Digests are immune to malicious updates; a tag can be changed to point to a tampered version, but a digest will be checked to ensure it always points to exactly the same version.
The update intention is clear. If the tag is
8.2.3, it can imply that the specific version was chosen for a reason, and newer versions may break.latestimplies that we always want to run the newer version of the image whenever possible.
Alternatively, another option is to specify a major version and a digest, for example, redis:8:@sha256:0bbbadbd9f830a8b1ca75a72515ae57ef5418e5f5af35413183f782ac8cb98e6. This approach implies that minor and patch versions should be updated automatically, while major versions are handled with greater care.
A maintainable, reproducible, and secure solution
Most people should be on a workflow like this — automatically updating to the newest version of images and software. In some cases, however, especially in enterprise projects, projects can get stuck on older versions, requiring costly migration processes to update. At Chainguard, we support both workflows. Smaller teams and projects often use our free images, which provide access to the latest tag and support the pinning workflow. We don't delete images, so old digests will continue to work. Other users require access to older software versions, SLA guarantees, and FIPS support, which are available in our paid subscriptions.
An important point about updates is that they're not just about the main package in the software, but also all the other dependencies. Just because there isn't a new nginx release doesn't mean the nginx image shouldn't be updated; there may be important security fixes in OS packages or other dependencies. At Chainguard, we constantly rebuild images to keep everything up to date. It's rare to see an image older than a day or two, which sets us apart from other vendors of secure images.
In the end, the latest tag should not be considered a security violation when it is part of a well-engineered strategy with pinning and updating. What should be considered a security violation are slow-moving processes that leave users on out-of-date software and at risk of exploitation.
Read this article to learn more about our usage of container image digests.
Share this article
Related articles
- engineering
The tech leader’s mandate: Use engineering to accelerate sales velocity
Sam Katzen, Staff Product Marketing Manager
- engineering
DriftlessAF: Introducing Chainguard Factory 2.0
Matt Moore, Co-founder and CTO, Manfred Moser, Senior Principal Developer Relations Engineer, and Maxime Greau, Principal Software Engineer
- engineering
The maturity gap in ML pipeline infrastructure
Patrick Smyth, Principal Developer Relations Engineer
- engineering
This Shit is Hard: Building hardened PyTorch wheels with upstream parity
Dann Frazier, Principal Software Engineer
- engineering
Gastown, and where software is going
Dan Lorenc, Assistant Mayor of Gastown
- engineering
Running Renovate as a GitHub Action (and NO PAT!)
Adrian Mouat, Staff Developer Relations Engineer