Reduce Docker Images by 20 MB by Verifying APT Packages without gnupg
When working with package sources you can pass the plain text asc key into signed-by instead of a binary gpg key.
When configuring the sources list for a package you can use the
signed-by option to pass in a GPG key. You’ll want to save the key in
/etc/apt/keyrings since that’s what APT suggests since they deprecated
Did you know you can pass in the plain text ASCII key directly too? Here’s a snippet from the
apt-key man pages:
Make sure to use the “asc” extension for ASCII armored keys and the “gpg” extension for the binary OpenPGP format (also known as “GPG key public ring”).
How Does This Work?
Let’s go over a real example. I’ll use installing Node because I recently encountered this in my example Docker web apps since they use esbuild but this isn’t limited to Node. It will work with all signed apt packages.
Node’s official documentation for installing itself on Debian says to do:
sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo mkdir -p /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
It suggests using the binary version of their GPG key. That’s what running
gpg --dearmor /etc/apt/keyrings/nodesource.gpg on their key will produce.
Then it says to add that binary key to your sources list:
NODE_MAJOR=20 echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" \ | sudo tee /etc/apt/sources.list.d/nodesource.list
signed-by option is pointing to the binary
If you curl down
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key this is a plain text / ASCII PGP key.
Based on the man pages we looked at earlier all we need to do is rename this file to be
nodesource.asc and it will work because of its file extension. Then we can reference it with
Since we don’t need to generate a binary GPG key we don’t need to apt install
gnupg. We can also avoid referencing
ca-certificates since technically
curl installs this package.
Technically you don’t need to mkdir
/etc/apt/keyrings on modern versions of Debian and Ubuntu since it exists by default but that’s only a quick aside.
Trying It Out in Docker
I did my tests in the official Debian Bookworm slim Docker image. You can run that with:
docker container run -it debian:bookworm-slim
At the time of this blog post it comes with 88 packages that are installed by default. You can check by running
apt list --installed and then piping it to
| wc -l, you need to subtract 1 because the first line of output of
apt list --installed isn’t a package.
Now try running:
apt-get update && apt-get install gnupg, notice that it prompts you that it will use 26.1 MB of extra disk space to install it. Even if you use
apt-get install --no-install-recommends gnupg it’s still 19.5 MB of files. There’s also 113 installed packages.
If you have a ~200 MB image that’s a ~10% savings or even ~5% with a ~400 MB image. Not only that but it’ll speed up your builds since there’s less being installed.
Does It Still Work?
Yes, you can spin up a new container and run
apt-get update && apt-get install -y curl and then run this to install Node:
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key -o /etc/apt/keyrings/nodesource.asc \ && echo "deb [signed-by=/etc/apt/keyrings/nodesource.asc] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list \ && apt-get update && apt-get install -y --no-install-recommends nodejs
You can run
node --version to verify it works as well as
apt-get update to see that it picks up the nodesource list.
To be doubly safe it really works you can manually modify the
nodesource.asc file such as replacing 1 character and then when
nodejs tries to be installed you’ll get a GPG error that says the signature couldn’t be verified.
I’ve applied this method to my example Docker Rails app since it installs Node this way. The other example apps use the base Node image for its assets where Node is already installed.
I also use this method to install Docker itself on Debian / Ubuntu within my Ansible role. This optimization saves having to run 1 extra task to create a binary GPG key.
The demo video goes over running some of the commands we came across in this post.
- 0:51 – Going over the process of adding a package to your sources list
- 2:30 – Checking out the man pages for apt-key
- 2:54 – Running a Debian Bookworm slim Docker container which has 88 packages
- 3:47 – There’s 113 packages after installing gnupg, it uses +26 MB of space
- 5:27 – That could be a 5-10% reduction in image size
- 5:38 – Making sure everything works, including GPG key verification
- 8:06 – I made this change to my example Rails app and Ansible role for Docker
Are you using this method of verifying signed keys? Let me know below.