Replace apt-key with a Repository-Specific Keyring

That "apt-key is deprecated" warning is not going away, and the old apt-key add habit trusts a repository key for every source on the machine. This guide moves one repository to a dedicated keyring selected with Signed-By. Allow about 20 minutes, plus time to confirm the repository's real key fingerprint. The commands are based on apt 2.8.3.

apt-key is deprecated. The installed manual says it is retained mainly for apt-key del in maintainer scripts, and that it will last be available in Debian 12 and Ubuntu 24.04. If you are adding a repository, use a separate keyring and a Signed-By source entry.

1. Inspect the current trust configuration

Start with read-only checks. They do not need elevated privileges unless your system has unusually restrictive permissions:

$ apt --version
apt 2.8.3
$ apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
... 

The list can contain keys from /etc/apt/trusted.gpg and every file in /etc/apt/trusted.gpg.d/. That is the trap: a key in this global set can be accepted for repositories that never meant to trust it. Before changing anything, record the repository's existing source entry and the fingerprint of the key it is meant to use.

Checkpoint: identify the source file without editing it:

$ rg -n '^(deb|Types:|URIs:|Suites:|Components:)' /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null

If rg is not installed, inspect the same files with grep -R -n. Replace the placeholder values in the remaining examples with the repository's documented URL, distribution and component.

2. Confirm the key before trusting it

Do not download a key from an unverified URL and assume that having it proves ownership. Get the repository operator's documented fingerprint through a channel you trust, then compare it with the key file or its exported contents. A mismatch means stop.

The example below assumes you already have an authenticated key file at /tmp/repository-key.asc. It only displays the fingerprint:

$ gpg --show-keys --with-fingerprint /tmp/repository-key.asc
pub   rsa4096 2024-01-01 [SC]
      0123 4567 89AB CDEF 0123  4567 89AB CDEF 0123 4567
uid           [ unknown] Repository signing key

The dates, algorithm, identity and fingerprint will differ. Match the complete fingerprint, not a short key ID or a name printed in a comment. Binary OpenPGP keys should use a .gpg filename, and ASCII-armoured keys may use .asc; the apt 2.8.3 manual documents both formats.

3. Install the key in the operator keyring directory

APT recommends /usr/share/keyrings for package-managed keyrings and /etc/apt/keyrings for keyrings managed by the system operator. Create the latter and copy the verified key there. These commands change system state and need sudo:

$ sudo install -d -m 0755 /etc/apt/keyrings
$ sudo install -m 0644 /tmp/repository-key.asc /etc/apt/keyrings/example-repository.asc
$ ls -l /etc/apt/keyrings/example-repository.asc
-rw-r--r-- 1 root root ... /etc/apt/keyrings/example-repository.asc

Keep the file readable by APT's unprivileged _apt user.

Warning: do not put an operator-managed key into /etc/apt/trusted.gpg, and do not pipe an unchecked network response to sudo apt-key add -. The old command gives the key broader scope than this migration needs.

Checkpoint: verify the installed copy still has the expected fingerprint:

$ gpg --show-keys --with-fingerprint /etc/apt/keyrings/example-repository.asc

4. Add Signed-By to the repository source

For a traditional one-line source, put the option in square brackets after deb. Replace every placeholder, including the distribution and component:

deb [signed-by=/etc/apt/keyrings/example-repository.asc] https://repo.example.invalid/debian stable main

For a deb822 source file, the equivalent fields are:

Types: deb
URIs: https://repo.example.invalid/debian
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/example-repository.asc

Use an absolute path. The sources.list(5) manual says the file must be readable by _apt. If no Signed-By is specified, APT falls back to its global trusted keyrings, which defeats the scope reduction.

Save the source in the same format and location your system already uses.

Warning: do not leave two entries for the same repository, one with Signed-By and one without. APT may report a conflicting configuration or carry on using the broader entry.

5. Test the repository before removing the old key

Refresh package metadata and watch for signature or permission errors:

$ sudo apt-get update
Hit:1 https://repo.example.invalid/debian stable InRelease
Reading package lists... Done

The exact lines depend on your configured sources. A successful update proves APT could read the keyring and verify the repository metadata. It does not prove the key belongs to the repository operator, which is why the fingerprint check came first.

If APT reports that the key is unreadable, check the path and permissions:

$ namei -l /etc/apt/keyrings/example-repository.asc
$ sudo -u _apt test -r /etc/apt/keyrings/example-repository.asc && echo readable

If it reports a missing public key, compare the source path, the key format and the fingerprint. Do not fix a signing failure by moving the key into the global trusted directory.

6. Remove the obsolete global key carefully

Only remove the old key after the repository works through its new scoped entry and you have checked whether another repository still needs it. Removing a shared key can break unrelated package updates. First locate the old fingerprint and file from apt-key list, then make a reversible backup of the exact file:

$ sudo cp --preserve=all /etc/apt/trusted.gpg.d/old-repository.gpg /etc/apt/trusted.gpg.d/old-repository.gpg.backup
$ sudo mv /etc/apt/trusted.gpg.d/old-repository.gpg /etc/apt/trusted.gpg.d/old-repository.gpg.disabled
$ sudo apt-get update

This changes the filename so APT no longer treats it as a trusted keyring fragment.

Recovery: if the update fails in a way that points to this key, restore the original name and investigate:

$ sudo mv /etc/apt/trusted.gpg.d/old-repository.gpg.disabled /etc/apt/trusted.gpg.d/old-repository.gpg
$ sudo apt-get update

Warning: after a successful maintenance window, remove the backup only when you are certain it is no longer needed. That deletion is irreversible, so it is deliberately left out of the migration sequence.

Done means