1. Introduction §
I really like containers, but they are something that is currently very bad from a security point of view: distribution
We download container images from container registries, whether it is docker.io, quay.io or ghcr.io, but the upstream project do not sign them, so we can not verify a CI pipeline or the container registry did not mess with the image. There are actually a few upstream actors signing their images: Fedora, Red Hat and universial-blue based distros (Bluefin, Aurora, Bazzite), so if you acquire their public key using for signing from a different channel, you can verify if you got the image originally built. Please do not hesitate to get in touch with me if you know about other major upstream that sign their container images.
Nevertheless, we can still create containers ourself from trustable artifacts signed by upstream. Let's take a look at how to proceed with Alpine Linux.
2. Get the rootfs §
The first step is to download a few files:
- Alpine's linux GPG key
- Alpine's "mini root filesystem" build for the architecture you want
- The GPG file (extension .asc) for the mini root filesystem you downloaded
Alpine linux download page on the official website
The GPG file is at the top of the list, it is better to get it from a different channel to make sure that if the website was hacked, the key was not changed accordingly with all the signed files, in which case you would just trust the key of an attacker and it would validate the artifacts. A simple method is to check the page from webarchive a few days / week before and verify that the GPG file is the same on webarchive and the official website.
The GPG key fingerprint I used is 0482 D840 22F5 2DF1 C4E7 CD43 293A CD09 07D9 495A as of the date of publication.
3. Verify the artifacts §
You will need to have gpg installed and a initialized keyring (I do not cover this here). Run the following command:
gpg --import ncopa.asc
gpg --verify alpine-minirootfs-3.23.3-x86_64.tar.gz.asc alpine-minirootfs-3.23.3-x86_64.tar.gz
It should answer something like this:
gpg: Signature made Wed Jan 28 00:25:36 2026 CET
gpg: using RSA key 0482D84022F52DF1C4E7CD43293ACD0907D9495A
gpg: Good signature from "Natanael Copa <ncopa@alpinelinux.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 0482 D840 22F5 2DF1 C4E7 CD43 293A CD09 07D9 495A
The line "Good signature...." tells you that the file integrity check matches the GPG key you imported. The rest of the message tells you that the key is not trustable. This is actually a GPG thing, you would need to edit your keyring and mark the key as "trustable" or have in your keyring a trusted key that signed this key (this is the web of trust GPG wanted to create), but this will only remove the warning. Of course, you can mark that key trustable if you plan to use it for a long time and you are absolutely sure it is the genuine one.
You do not need to verify the checksum using sha256, the GPG check did the same in addition to authenticate the person who produced the checksum.
Now you validated the minirootfs authenticity, you can create an Alpine container!
4. Container creation §
You can use podman or docker for this:
podman import alpine-minirootfs-3.23.3-x86_64.tar.gz alpine:3.23.3-local
You are now ready to build more containers based on your own cryptographically verified Alpine container image.
5. Example of use §
It is rather easy to build new containers with useful purpose on top of your new base container.
Create a Containerfile (or Dockerfile, your mileage may vary):
FROM alpine:3.23.3-local
RUN apk add nginx
CMD ["nginx", "-c", "/app/nginx.conf", "-g", "daemon off;"]
Build a container with this command:
podman build . -t alpine_local_nginx
6. Conclusion §
Without any kind of cryptographic signature mechanism available between upstream and the end user, it is not possible to ensure a container from a third party registry was not tampered with.
It is best for security to rebuild the container image, and then rebuild all the containers you need using your base image, rather than blindly trusting registries.
One tool to sign container images is cosign.
Cosign project GitHub page
7. Going further §
This process works for other Linux distributions of course. For instance, for Ubuntu you can download Ubuntu base image, the SHA256SUMS.gpg and SHA256SUMS files, and make sure to get a genuine GPG key to verify the signature.
Ubuntu official website: ubuntu-base 24.04 releases