Adding a key to /etc/apt/trusted.gpg.d
is insecure because it adds the key for all repositories. This is exactly why apt-key
had to be deprecated.
Short version
Do similar to what Signal does.
If you want to use the key at https://example.com/EXAMPLE.gpg
for a repository listed in /etc/apt/sources.list.d/EXAMPLE.list
, use:
sudo mkdir -p /etc/apt/keyrings/
wget -O- https://example.com/EXAMPLE.gpg |
gpg --dearmor |
sudo tee /etc/apt/keyrings/EXAMPLE.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/EXAMPLE.gpg] https://example.com/apt stable main" |
sudo tee /etc/apt/sources.list.d/EXAMPLE.list
# Optional (you can find the email address / ID using `apt-key list`)
sudo apt-key del support@example.com
Long version
While the deprecation notice recommends adding the key to /etc/apt/trusted.gpg.d
, this is an insecure solution. To quote this article from Linux Uprising:
The reason for this change is that when adding an OpenPGP key that's used to sign an APT repository to /etc/apt/trusted.gpg
or /etc/apt/trusted.gpg.d
, the key is unconditionally trusted by APT on all other repositories configured on the system that don't have a signed-by
(see below) option, even the official Debian / Ubuntu repositories. As a result, any unofficial APT repository which has its signing key added to /etc/apt/trusted.gpg
or /etc/apt/trusted.gpg.d
can replace any package on the system. So this change was made for security reasons (your security).
The proper solution is explained in that Linux Uprising article and on the Debian Wiki: Store the key in /etc/apt/keyrings/
(or /usr/share/keyrings/
if you're the package maintainer), and then reference the key in the apt source list.
Therefore, the appropriate method is as follows:
- Download the key from
https://example.com/EXAMPLE.gpg
and store it in /etc/apt/keyrings/EXAMPLE.gpg
.
The Debian wiki explains that you should dearmor the key (i.e. convert it from base64 to binary) for compatibility with older software. The > /dev/null
simply stops the binary key from being displayed in your terminal.
wget -O- https://example.com/EXAMPLE.gpg |
gpg --dearmor |
sudo tee /etc/apt/keyrings/EXAMPLE.gpg > /dev/null
Optionally, you can verify that the file you downloaded is indeed a PGP key by running file /etc/apt/keyrings/EXAMPLE.gpg
and inspecting the output.
- Add the key to the source file that is used by the repository.
Find the appropriate file in
/etc/apt/sources.list.d/
and edit it so that it links to the keyring you just added.
If the file doesn't exist, you can make one.
In the end, it should look something like this:
deb [signed-by=/etc/apt/keyrings/EXAMPLE.gpg] https://example.com/apt stable main
- Remove the key from
apt-key
, if it was added before.
Run sudo apt-key list
to list all the keys, and find the one that was previously added.
Using the key's email address or fingerprint, run sudo apt-key del support@example.com
.
Using the newer DEB822 format
In step 2, instead of using the one-line format for sources in sources.list.d
, you can also use the newer multi-line format called DEB822. This format is easier to read for humans and computers, and has been available in apt since 2015. Debian and Ubuntu plan to use DEB822 as the default format starting late 2023. Repolib's documentation has a nice comparison and covers the motivation behind the new format.. Note that some external tools that parse the source files themselves instead of wrapping around apt do not fully support this format yet.
To switch to this format, let's say you have the following one-line format source file /etc/apt/sources.list.d/example.list
:
deb [signed-by=/etc/apt/keyrings/EXAMPLE.gpg] https://example.com/apt stable main
Comment out this line, and create a new file, /etc/apt/sources.list.d/example.sources
, containing:
Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/EXAMPLE.gpg
Run sudo apt update
, and if you see example.com/apt
correctly being updated, you can remove the old /etc/apt/sources.list.d/example.list
.
Additional resources