
A while back we wrote about our automatically updated docker image for cfn-lint - a public, daily-rebuilt image for cfn-lint that fills the gap left by the lack of an official one. Two changes have just landed in that build, and both are worth a few words: the images are now multiplatform, and we have fixed a problem that, from cfn-lint v1.52.0 onwards, left the image unable to recognise any resources.
Multiplatform images: native amd64 and arm64
Until now, the image was built for linux/amd64 only. That was fine on x86 CI runners, but it no longer matches where a
lot of pipelines actually run. AWS Graviton-based runners and CodeBuild ARM containers are common now, and plenty of
developers run cfn-lint locally on Apple Silicon laptops. On all of those, an amd64-only image runs under emulation,
which is slower to start and can be flaky.
The image is now published as a single multi-architecture manifest covering both linux/amd64 and linux/arm64. You do
not need to change anything: docker pull and docker run automatically select the build that matches your host, so
ARM hosts now get a native ARM image rather than an emulated x86 one.
docker pull mysteriouscode/cfn-lint:latest
On the build side, we moved from a plain docker build to docker buildx, with QEMU set up so a single GitHub Actions
runner can produce both architectures and push them under the same tags:
| |
The result is one manifest list per tag, so :latest, :v1 and the exact version tags all resolve to the right
architecture for whoever pulls them.
When cfn-lint v1.52.0 stopped recognising resources
The second change is a fix. From cfn-lint v1.52.0, the image we built suddenly stopped recognising any resources - templates that linted cleanly the day before were now treated as if every resource type was unknown.
The cause is in how cfn-lint gets its schemas. cfn-lint validates your templates against the CloudFormation provider
schemas (the “specs”) - the per-resource definitions that describe which properties exist, their types and constraints.
These schemas used to be checked into the cfn-lint source tree and shipped as part of the package.
In PR #4539 (“Source schemas from enhanced-schemas repo
instead of local patching”), released in v1.52.0, the CloudFormation team removed those schemas from the source tree.
They now live in a separate resource-provider-enhanced-schemas
repository, which takes the raw provider schemas, patches them, and publishes them as a schemas-cfn-lint.zip file on its
releases. They are fetched separately now, rather than bundled with the code.
That change is fine if you install the published package, but our build does something deliberately different. As we explained in the original post, we build cfn-lint straight from the tagged source archive on GitHub, so we can build any version (including the v0.x line) from one Dockerfile:
| |
From v1.52.0, that source archive no longer contains the schemas. So the installed cfn-lint had nothing to validate against, and every resource came back unrecognised.
The fix: bake the schemas in with --update-specs
cfn-lint ships a command for exactly this situation: cfn-lint --update-specs (short form -u). It downloads the
current CloudFormation provider schemas and writes them into cfn-lint’s own data directory. Normally you would run it
once in a while to pull in the latest resource definitions, but here it is exactly what we need to put back the schemas
that no longer come with the source.
We run it as a build step in the Dockerfile, right after installing cfn-lint:
| |
Because this happens at build time, the schemas are baked into the image. That brings resource recognition back, and it means the image does not have to fetch anything the first time you lint a template. It stays self-contained, just as it was before, and works the same whether or not your pipeline has outbound network access.
Nothing to change on your side
Both changes are already live in the published images. Pull as usual and you get a native build for your architecture with a full, up-to-date set of CloudFormation schemas:
docker pull mysteriouscode/cfn-lint:latest
docker pull public.ecr.aws/mysteriouscode/cfn-lint:latest
As always, the whole build is public: you can read the Dockerfile and the GitHub Actions workflow to see exactly how the image is put together.