🚀 Executive Summary
TL;DR: The ‘apt-key is deprecated’ warning indicates a shift from a globally trusted keyring to a more secure, per-repository key management system. To resolve this, PPA keys should be moved to the modern ‘signed-by’ method, ensuring CI/CD pipelines and server provisioning continue to function on modern Debian and Ubuntu systems.
🎯 Key Takeaways
- The ‘apt-key is deprecated’ warning signals a security enhancement, moving from a single global keyring (`/etc/apt/trusted.gpg`) to isolated, per-repository keys.
- The ‘Right Way’ to fix this involves creating a dedicated `/etc/apt/keyrings/` directory for GPG keys and explicitly linking them to repository source files using the `[signed-by=…]` attribute.
- While a ‘Quick Fix’ involves piping dearmored keys to `/etc/apt/trusted.gpg.d/`, it maintains a global trust model and is not recommended for long-term production use.
- A ‘Nuclear Option’ script can help migrate existing keys from `trusted.gpg` to individual files in `trusted.gpg.d`, but still requires manual updates to `sources.list.d` files with the `signed-by` attribute.
- Automating the ‘Right Way’ fix in base images, Ansible roles, or CI runners prevents future build failures and enhances infrastructure security.
Fix the notorious “apt-key is deprecated” warning by moving your PPA keys to the modern, secure “signed-by” method, ensuring your CI/CD pipelines and server provisioning don’t break on modern Debian and Ubuntu systems.
So, Your Build is Failing. Let’s Talk About ‘apt-key’.
I remember it vividly. It was 2 AM, and a P1 incident ticket landed in my queue. A critical deployment pipeline for our main monolith, `prod-monolith-alpha`, was failing. The error? A cryptic warning message that the on-call junior engineer had never seen before: Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead. The build script, which had worked flawlessly for three years, was now halting on a simple apt-get update. A base image had been updated automatically, and suddenly, our entire deployment process was dead in the water.
If you’re reading this, you’ve probably just hit the same wall. Your Ansible playbook, your Dockerfile, your trusty server setup script—it’s all screaming at you about apt-key. Don’t panic. You’re not alone, and this is a good thing, I promise. It’s the system forcing us to be more secure. Let’s break it down.
First, The “Why”: What’s a Keyring and Why Did It Break?
Think of the old apt-key system like a single master key for an entire apartment building. When you used apt-key add some_repo.gpg, you were adding a key to a global, trusted keyring (/etc/apt/trusted.gpg). This meant that the key for the Node.js repository could, in theory, be used to validate packages from the PostgreSQL repository. If any one of those keys were compromised, an attacker could potentially sign malicious packages and get them trusted as if they were official.
The new method is about isolation. Instead of one global keyring, every software repository you add gets its own key, stored in a dedicated place (/etc/apt/keyrings/). Then, in your repository configuration file, you explicitly tell APT: “For this specific repository, you must use this specific key to verify its packages.” It’s like giving each apartment its own unique key instead of a master key. It’s more work, but it’s a hell of a lot more secure.
The Solutions: From “Get Me Out of Here” to “Built to Last”
I’ve seen this problem tackled a few ways in the wild. Here are three approaches, from the quick-and-dirty to the architecturally sound.
Solution 1: The Quick & Dirty Fix (The Band-Aid)
Let’s say your build is on fire and you just need it working right now. This method is the direct descendant of the old way, but it puts the key in the “correct” directory without fully embracing the new system. It still uses a global trust model, but it silences the deprecation warning in many cases.
You probably have a line in your script that looks like this:
# The OLD, broken way
wget -qO - https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
The quick fix is to dearmor the key and dump it into the trusted.gpg.d directory. This directory is for dropping in key files that APT will trust globally.
# The QUICK FIX: Pipe the key to the trusted.gpg.d directory
wget -qO - https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg
Darian’s Take: Look, I get it. Sometimes you just need to stop the bleeding. This will often work and get your pipeline green again. But you haven’t actually fixed the underlying security issue. You’ve just moved the key. Don’t leave this in a production script long-term. You’re just kicking the can down the road.
Solution 2: The “Right Way” Fix (The Permanent Solution)
This is the method you should be using. It fully embraces the new per-repository key model. It’s a two-step process: place the key in a dedicated, isolated keyring directory, and then tell the repository source list where to find it.
Step 1: Create the keyrings directory and download the key there.
We’ll create a dedicated directory for our keys. This is best practice to keep things organized and secure.
# Create the directory if it doesn't exist
sudo install -m 0755 -d /etc/apt/keyrings
# Download the key, dearmor it, and save it to the new directory
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Set proper permissions for the key file
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Step 2: Modify your repository source file to use the new key.
Now, we create or edit the repository’s .list file in /etc/apt/sources.list.d/. The magic is the [signed-by=...] part. This explicitly tells APT which key to use for this repo.
# Add the repository to your sources list
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Now, update your package list
sudo apt-get update
No warnings. Clean, secure, and future-proof. This is how we do it on all our new server images and CI runners like ci-runner-bionic-04.
Solution 3: The “Nuclear” Option (For Legacy Systems)
What if you’ve inherited a server like legacy-prod-db-01 with a dozen old keys in the main trusted.gpg keyring? Migrating them one by one is a pain. This is an advanced approach for cleaning up a messy system. It’s a script to extract all the keys from the old keyring and move them to the new format.
WARNING: This is a powerful script. It directly manipulates your system’s trust stores. Test it on a non-critical machine first. I am not responsible if you break your package manager. You have been warned.
#!/bin/bash
# Script to migrate keys from legacy apt-key to the new format
set -e
echo "Starting migration of keys from trusted.gpg..."
# Export all keys from the main keyring to individual files
apt-key exportall | gpg --dearmor > /tmp/temp-trusted-export.gpg
# Split the exported file into individual keys
gpg --enarmor < /tmp/temp-trusted-export.gpg | csplit -z -f /tmp/key- -b "%02d.asc" - "/-----BEGIN PGP PUBLIC KEY BLOCK-----/" "{*}"
# Process each individual key file
for keyfile in /tmp/key-*.asc; do
if [ -s "$keyfile" ]; then
echo "Processing ${keyfile}..."
# Get the fingerprint to use as the filename
fingerprint=$(gpg --show-keys --with-colons "${keyfile}" | grep '^fpr' | cut -d: -f10)
if [ -n "$fingerprint" ]; then
# Dearmor the key and place it in the trusted.gpg.d directory
echo "Moving key with fingerprint ${fingerprint}"
gpg --dearmor < "${keyfile}" > "/etc/apt/trusted.gpg.d/${fingerprint}.gpg"
else
echo "Could not get fingerprint for ${keyfile}"
fi
fi
done
echo "Cleaning up temporary files..."
rm /tmp/temp-trusted-export.gpg /tmp/key-*.asc
echo "Migration complete. You should now audit your source.list files to use [signed-by]."
echo "This script does NOT automatically update your source lists."
This script gets you halfway there—it moves the keys. You still need to go into your /etc/apt/sources.list.d/ files and add the [signed-by=...] attribute for each repository, pointing to the new key files. It’s a cleanup tool, not a magic wand.
My Final Two Cents
It’s tempting to use the quick fix and move on. We’re all under pressure. But taking the extra ten minutes to implement Solution #2, the “Right Way,” will save your future self (or the next engineer) a massive headache. It’s a small change that makes your infrastructure more robust and secure.
Automate it, put it in your base images, bake it into your Ansible roles. Stop using apt-key add today. Your future self will thank you when you’re sleeping soundly instead of troubleshooting a broken build at 2 AM.
🤖 Frequently Asked Questions
âť“ What does the ‘apt-key is deprecated’ warning signify and why did it break my build?
The warning signifies that the old `apt-key` system, which used a single global keyring (`/etc/apt/trusted.gpg`), is being phased out due to security concerns. It broke your build because modern Debian/Ubuntu systems now enforce a more secure, isolated per-repository key model, causing `apt-get update` to halt on scripts using the deprecated method.
âť“ How does the ‘Quick Fix’ compare to the ‘Right Way’ for resolving apt-key deprecation?
The ‘Quick Fix’ pipes dearmored keys into `/etc/apt/trusted.gpg.d/`, silencing the warning but retaining a global trust model, which is less secure. The ‘Right Way’ involves creating a dedicated `/etc/apt/keyrings/` directory for each key and explicitly linking it to its specific repository via the `[signed-by=…]` attribute in the `sources.list.d` file, offering superior security and isolation.
âť“ What is a common implementation pitfall when migrating from apt-key and how can it be avoided?
A common pitfall is using the ‘Quick Fix’ (moving keys to `trusted.gpg.d`) as a permanent solution. While it stops immediate errors, it doesn’t address the underlying security issue of global trust. To avoid this, always implement the ‘Right Way’ by creating isolated keyrings in `/etc/apt/keyrings/` and using the `signed-by` attribute in your repository source files for true per-repository key management.
Leave a Reply