I was installing elasticsearch following this guide, but elasticsearch is not really the part of this question.
In the first step, I need to add the key:
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
and got the following message:
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
The installation process was fine, but since it's deprecated, I'm looking for the new usage that replaces apt-key
. (I have no problem installing the package.) From man apt-key
I saw
apt-key(8) will last be available in Debian 11 and Ubuntu 22.04.
...
Binary keyring files intended to be used with any apt version should therefore always be created with gpg --export.
but it didn't say the alternative to apt-key add
. I tried
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --export
but didn't work. So what do I use after the pipe of wget
when apt-key
is removed?
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.
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.sources
, use:
sudo mkdir -m 0755 -p /etc/apt/keyrings/
curl -fsSL https://example.com/EXAMPLE.gpg |
sudo gpg --dearmor -o /etc/apt/keyrings/EXAMPLE.gpg
echo "Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/EXAMPLE.gpg" |
sudo tee /etc/apt/sources.list.d/EXAMPLE.sources > /dev/null
# Optional (you can find the email address / ID using `apt-key list`)
sudo apt-key del [email protected]
# Optional (not necessary on most systems)
sudo chmod 644 /etc/apt/keyrings/EXAMPLE.gpg
sudo chmod 644 /etc/apt/sources.list.d/EXAMPLE.sources
ℹ️ You can also embed the key directly into the
.sources
file! See the section "Embedding the key" below.
ℹ️ We're using the
.sources
format here, not the old.list
format. This is supported on basically all systems today. See the section "Old one-line format" below for more info.
While the deprecation notice recommends adding the key to /etc/apt/trusted.gpg.d
, this is an insecure solution, and deprecated as of apt 2.9.24 (released January 2025). 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 asigned-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 keys are managed by a package), and then reference the key in the apt source list.
Therefore, the appropriate method is as follows:
Create directory
Create the directory for PGP keys if it doesn't exist, and set its permissions.
This step explicitly sets the recommended permissions, just in case you've changed your umask using sudo's umask_override
.
Creating the directory is actually only necessary in releases older than Debian 12 and Ubuntu 22.04, but it can't hurt to run this line either way.
sudo mkdir -m 0755 -p /etc/apt/keyrings/
Download key
Download the key from https://example.com/EXAMPLE.gpg
and store it in /etc/apt/keyrings/EXAMPLE.gpg
.
By giving options -fsSL
to curl
we enable error messages, ensure redirects are followed, and reduce output so you can see sudo's password prompt.
The Debian wiki explains that you should dearmor the key (i.e. convert it from base64 to binary) for compatibility with older software.
curl -fsSL https://example.com/EXAMPLE.gpg |
sudo gpg --dearmor -o /etc/apt/keyrings/EXAMPLE.gpg
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.
Register repository
A key has been added, but apt
doesn't know about the repository yet.
To add the repository, you should create a .sources
file in /etc/apt/sources.list.d/
that describes how to use the repository, and where to find the key.
(You may also have .list
files in that directory.
See the section "Old one-line format" below for more info.)
The contents of the created .sources
file should look something like this:
Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/EXAMPLE.gpg
The Signed-By
field should link to the key you just downloaded.
If a repository wants you to specify an architecture, or you want to use multiple components (e.g. main contrib
), the contents may instead be something like
Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main universe
Architectures: amd64 i386
Signed-By: /etc/apt/keyrings/EXAMPLE.gpg
A "flat" repository doesn't work with suites and components, and instead specifies an exact path.
In the DEB822 format, this is represented by setting Suites:
to that path, and omitting the Components:
field entirely.
In this case, the Suites:
field must end with a /
.
For example:
Types: deb
URIs: https://example.com/apt
Suites: deb/
Signed-By: /etc/apt/keyrings/EXAMPLE.gpg
If you are adapting the file from an existing repo, they may be using the old one-line format instead. See the section "Old one-line format instead" below for more info.
For more examples, see the sources.list(5)
man pages.
(optional) Remove old key
If you previously added a third-party key with apt-key
, you should remove it.
Run sudo apt-key list
to list all the keys, and find the one that was previously added.
Then, using the key's email address or fingerprint, run sudo apt-key del [email protected]
.
(optional) Force-set permissions
If you have a custom umask_override
set for sudo
, or if you use ACLs, files will be created with different permissions than usual.
In those cases, explicitly set permissions for EXAMPLE.gpg
and EXAMPLE.list
to 644
.
apt 2.2.4 and newer support embedding the public key directly in the sources.list
.
You can check your version of apt by running apt -v
.
Debian 10 "Buster" LTS (EOL: 2024-06-30) and Ubuntu 20.04 "Focal Fossa" (EOL: 2025-04-30) are too old, but Debian 11 "Bullseye" and Ubuntu 22.04 "Jammy Jellyfish" are good to go!
To embed a key, replace the path in Signed-By: /etc/apt/keyrings/EXAMPLE.gpg
with the raw key, and delete the file /etc/apt/keyrings/EXAMPLE.gpg
.
Importantly, you must indent each line of the key block by (at least) one space, and you must put an indented .
instead of an empty line.
(Removing the empty line at the start of the key invalidates the key!)
For example, you may have a .sources
file like below.
(Real keys should be much longer than this. This one is too short to be secure.)
Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By:
-----BEGIN PGP PUBLIC KEY BLOCK-----
.
mI0EZWiPbwEEANPyu6pUQEydxvf2uIsuuYOernFUsQdd8GjPE5yjlxP6pNhVlqNo
0fjB6yk91pWsoALOLM+QoBp1guC9IL2iZe0k7ENJp6o7q4ahCjJ7V/kO89mCAQ09
yHGNHRBfbCo++bcdjOwkeITj/1KjYAfQnzH5VbfmgPfdWF4KqS/TmJP9ABEBAAG0
G0phbmUgRG9lIDxqYW5lQGV4YW1wbGUub3JnPojMBBMBCgA2FiEEK8v49DttJG7D
35BwcvTpbeNfCTgFAmVoj28CGwMECwkIBwQVCgkIBRYCAwEAAh4BAheAAAoJEHL0
6W3jXwk4YLID/0arCzBy9utS8Q8g6FDtWyJVyifIvdloCvI7hqH51ZJ+Zb7ZLwwY
/p08+Xnp4Ia0iliwqSHlD7j6M8eBy/JJORdypRKqRIbe0JQMBEcAOHbu2UCUR1jp
jJTUnMHI0QHWQEeEkzH25og6ii8urtVGv1R2af3Bxi9k4DJwzzXc5Zch
=8hwj
-----END PGP PUBLIC KEY BLOCK-----
The script below will create a new .sources
file at /etc/apt/sources.list.d/EXAMPLE.sources
with the key at https://example.com/EXAMPLE.gpg
embedded into it:
echo "Types: deb
URIs: https://example.com/apt
Suites: stable
Components: main
Signed-By:
$(wget -O- https://example.com/EXAMPLE.gpg | sed -e 's/^$/./' -e 's/^/ /')" | sudo tee /etc/apt/sources.list.d/EXAMPLE.sources > /dev/null
# Optional (see above)
sudo apt-key del [email protected]
sudo chmod 644 /etc/apt/sources.list.d/EXAMPLE.sources
Thus far, this answer has used the "new" DEB822 format (.sources
files) to specify repositories, instead of the old one-line format (.list
files).
The DEB822 format has been supported since apt 1.1 (released in 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.
If you are running Debian 9 "Stretch" or newer, or Ubuntu 16.04 "Xenial Xerus" or newer, you're good to go!
This section is intended for those who cannot use DEB822, or for those who want to migrate to DEB822.
The following script replaces the DEB822 script from the section "Short version", at the top of this answer.
sudo mkdir -m 0755 -p /etc/apt/keyrings/
curl -fsSL https://example.com/EXAMPLE.gpg |
sudo gpg --dearmor -o /etc/apt/keyrings/EXAMPLE.gpg
echo "deb [signed-by=/etc/apt/keyrings/EXAMPLE.gpg] https://example.com/apt stable main" |
sudo tee /etc/apt/sources.list.d/EXAMPLE.list > /dev/null
# Optional (see above)
sudo apt-key del [email protected]
sudo chmod 644 /etc/apt/keyrings/EXAMPLE.gpg
sudo chmod 644 /etc/apt/sources.list.d/EXAMPLE.list
If you can, you should migrate to DEB822, because that will be the default format in Debian and Ubuntu. That said, as of February 2025, there is no urgency to migrate, because the old one-line format is not deprecated.
Since apt 2.9.24 (released January 2025), you can run apt modernize-sources
to automatically migrate all your .list
files to DEB822.
Note, however, that some fields, such as arch=...
are not migrated correctly, so you must add Architectures: ...
to your .sources
file manually.
Fields with multiple values are space-separated, so multiple architectures would be written as Architectures: amd64 i386
.
man 5 sources.list
, describes the old one-line format and the DEB822 formats in detailman 8 apt-secure
, describes how signature checking works