174

Setting up keys for a local repository on a new ubuntu 20.10 virtual machine, I got a message that apt-key add was deprecated and I should read the apt-key(8) man page. The apt-key(8) man page is a collection of words strung together, but if it contains information I can't winkle it out. Can anyone tell me what, exactly, I should type on my terminal instead of:

apt-key add name-of-file

The command does apparently still work after honking at me, so I was able to proceed, but would like to know what I'll need to do in the future.

0

8 Answers 8

290

You need to know why apt-key add is deprecated

All of the answers so far work around the symptom ("Don't use apt-key add") but fail to address the actual problem that led to apt-key add being deprecated. The problem is not a question of appending a key to one big keyring file etc/apt/trusted.gpg vs manually putting single-key keyring files into the directory /etc/apt/trusted.gpg.d/. These two things are equivalent, and doing either one is a huge security risk.

The problem is that any key you add to either of the above is completely and unconditionally trusted by apt. This means that when installing any package from any repo (including the official distro repos), apt will happily accept the package being signed by any of those trusted keys (whether the key belongs to the repository the package is coming from or not). This weakens the assurance provided by the package signing mechanism against malicous packages being injected into the official Ubuntu mirrors network.

What we want to do instead is configure apt to accept signatures from a third-party repository only on packages being installed from that repository — no cross-signing. Apt's default pinning rules give higher priority to official distro repos, which (in conjunction with proper key management) offers some protection against third-party repos replacing distro-provided packages. (At least, I think that's default. You can use apt-cache policy to inspect the current pin priorities, and if needed you can adjust pinning based on origin to achieve this effect. See man apt_preferences for details.)

The instructions given in Ugo Delle Donne's answer for converting the key to the (legacy) keyring v4 format that apt will accept are correct and helpful, but that's only half of the solution. I'll reiterate them here (cleaned up slightly) so all the steps are consolidated in one place:

  • Download the key:
    • wget https://host.domain.tld/path/to/<keyfile>.<ext>
      (No need for -O or >; wget defaults to saving the file in your current directory with the same filename it has on the server.)
  • Verify that the filetype is "PGP public key block Public-Key (old)":
    • file <keyfile>.<ext>
  • gpg supports a number of key formats, so if your key is in a different format, convert it by importing it into a temp keyring, then exporting it again:
    • gpg --no-default-keyring --keyring ./temp-keyring.gpg --import <keyfile>.<ext>
    • gpg --no-default-keyring --keyring ./temp-keyring.gpg --export --output <your-keyfile-name>.gpg
    • rm temp-keyring.gpg

Now that you have your converted key, do not add it to apt's trusted keystore by copying it into /etc/apt/trusted.gpg.d/. Instead, put it somewhere like /etc/apt/keyrings/. (You might need to create that keyrings directory first.) There's nothing special about that location, it's just a convention recommended by man 5 sources.list in Ubuntu 22.04 and a related Debian Wiki entry.

At this point, nothing has changed and apt doesn't know the key exists. The last step is to modify the specific .list file for the repository to tell apt where to find the key for that specific repo.

  • Edit the file /etc/apt/sources.list.d/<example>.list, and in between deb and the url, add [signed-by=/etc/apt/keyrings/<your-keyfile-name>.gpg]

Now apt will accept that key's signature for all packages in that repo and only that repo.

Notes:

  • If you already have keyring files in /etc/apt/trusted.gpg.d/, you can copy move them to /etc/apt/keyrings/ as-is, and then update all the corresponding .list files so each one has a signed-by field pointing to its own key.
  • If you already have keys in the /etc/apt/trusted.gpg keyring file beyond the official repo keys, this answer details the steps to locate and remove them. You can then follow all the same steps above to set them up the safer way. (Exporting them from that keyring is also possible, but the exact steps are left as an exercise for the reader.)
  • To import a repo's key from a keyserver to a standalone file:
    • gpg --no-default-keyring --keyring <output-file-name>.gpg --keyserver <some.keyserver.uri> --recv-keys <fingerprint>
    • This should give you a key that apt will accept without conversion.
  • Apt is still very trusting, and a malicious or compromised repo can bypass this measure easily because packages currently can run arbitrary shell code as root in their setup scripts. Closing off one attack vector doesn't hurt, though, and progress is (slowly) being made on other fronts.
  • Optionally, you can switch to the newer, more verbose Deb822 format using individual .sources files instead of .list files. It's more work, but personally I find the result far more readable.

Sources:

23
  • 3
    @Hrobky yes, if the key is an old binary-format "public key block" that has been ascii-armored, that will work. However, if the key file is in the newer binary "keybox database" format, which apt doesn't support, it needs to be actually converted to the old public key block format (after dearmoring if applicable). If there's a one-step command for that binary→binary conversion, I haven't encountered it yet.
    – Askeli
    Jan 28, 2021 at 15:42
  • 14
    "This means that any third-party repo whose apt signing key is in there is allowed to replace any package on your entire system, no questions asked." -- this is possible even if you use the newer method, no? Because apt will still have no concept of which repository is permitted to ship which packages. Unless you also implement some pinning, but I don't see that in any instructions. Jun 1, 2021 at 20:26
  • 6
    Is there a reason why this process is not automatic with some apt command to replace the deprecated behavior? By the description it seems it can easily be scripted. Oct 11, 2021 at 6:43
  • 5
    @RobieBasak It looks like Debian does have instructions for this, but I have to say that this sounds really complicated. Hopefully add-apt-repository will be updated or some other tool will be put together to automate this process...
    – Compholio
    May 18, 2022 at 23:27
  • 4
    According to "man 5 sources.list" on Ubuntu 22.04, if you are a system manager who wants to add an apt source with a keyring, the keyring should go to /etc/apt/keyrings/ (e.g. for the winehq repo). On the other hand, if you are a pkg maintainer who wants to install a keyring with the package postinst script (e.g. google-chrome, Microsoft teams, slack) you should place it in /usr/share/keyrings/.
    – zeehio
    Jun 3, 2022 at 6:06
17

I stumbled on the same problem and luckily some other question lighted the way. In my example I was trying to add a teamviewer repository to a recent Kali linux and I was being blocked by the key verification.

I'm quite sure there's a more elegant way to do this but the following steps helped me fix the problem:

  1. Download the relevant key

    wget -O - https://download.teamviewer.com/download/linux/signature/TeamViewer2017.asc > ~/teamviewer.key

  2. Verify the type of file

    file ~/teamviewer.key

    it should be PGP public key block Public-Key (old)

  3. Create a keyring

    gpg --no-default-keyring --keyring ./teamviewer_keyring.gpg --import teamviewer.key

  4. This file is still not a valid key that can be added to /etc/apt/trusted.gpg.d/ since it's a keyring, but from the keyring we can extract the key with

    gpg --no-default-keyring --keyring ./teamviewer_keyring.gpg --export > ./teamviewer.gpg

  5. This file is the key you want to move to the trusted key folder

    sudo mv ./teamviewer.gpg /etc/apt/trusted.gpg.d/

happy sudo apt update!!!

1
  • 19
    Do not use this accepted answer and do not put files in /etc/apt/trusted.gpg.d/. See the aswer with the most upvotes for a better solution. Jul 5, 2022 at 6:52
13

The reason for this deprecation is because using apt-key add simply appends the gpg key to the trusted global APT keyring. It's similar to the preferred method of adding local_repo.list to /etc/apt/sources.list.d/ instead of using add-apt-repository dep /link/to/repo version, which appends the message to the global sources.list file.

I think it's a bit more awkward to understand than using the .d folder, but essentially we want to get the gpg key into a standalone keyring file, then point to this keyring file in the source listing. The default keyring file location is /usr/share/keyrings, and it can be a .asc or .gpg file. I'm not sure the difference but I do know the global keyring files are binary files, not plaintext.

For example:

Using generic names can be a bit hard to understand sometimes, so here is an example of installing mongoDB:

Get the MongoDB gpg key and add it to a new keyring file

curl https://www.mongodb.org/static/pgp/server-4.2.asc | sudo tee -a /usr/share/keyrings/buster-mongodb-org-4_2.asc

Add a source entry for apt, pointed to this new keyring.

For example, if your repository file is located at /etc/apt/sources.list.d/mongodb-org-4_2.list run the following command to add the keyfile:

echo "deb [signed-by=/usr/share/keyrings/buster-mongodb-org-4_2.asc] https://repo.mongodb.org/apt/debian buster/mongodb-org/4.2 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-4_2.list

Install mongodb from this newly added repo

sudo apt install -y mongodb-org

Reference

This is still new to me, but most of what I know came from this excellent answer in the unix SE

3
  • I'm curious how the file server-4.2.asc from the remote server turned into buster-mongodb-org-4_2.asc on the local side. Is that name important somehow? Jun 3, 2022 at 1:46
  • It should be noted that newer versions of mongodb may also require [ arch=amd64,arm64 ] on Ubuntu and I'm not sure yet what the separator is to add that along with the key path.
    – mchid
    Feb 19, 2023 at 3:54
  • 1
    @mchid The separator between options is a space, like this: [arch=amd64,arm64 signed-by=...]
    – Moshe Katz
    Aug 13, 2023 at 3:40
9

I created a shell script that can download and install keys to be used with [signed-by=] declaration in sources.list.

It's available on github.com/ameinild/add-apt-key.

POSIX Script for installing APT keys

General help

This script will help with installing PGP keys for APT repositories.

This script supports up to 2 arguments:

  • 1st argument is input file. This can be either:
    • An URL - key will be downloaded into current path (using wget or curl)
    • A filename - reads an existing key in current path
    • A path and a filename - reads an existing key in given path
  • 2nd argument is key output path and output name. This can be either:
    • Only filename - output path is set in config, saved as given filename
    • A path and a filename - output path is given here, saved as given filename
    • Only a path (end with /) - output path is given here, filename is taken from existing key
    • Empty - output path is set in config, filename is taken from existing key

This script has a config file /usr/local/etc/add-apt-key.conf, where the following variables can be set:

  • keypath : path to store converted key - default is /etc/apt/keyrings
  • verbosity : if set to Yes - displays extra output
  • removetmp : if set to Yes - remove input (non-converted) file

Example 1: (PWD=/root)

sudo add-apt-key https://mariadb.org/mariadb_release_signing_key.asc /usr/share/keyrings/

Will download key in /root, convert it and store as /usr/share/keyrings/mariadb_release_signing_key.gpg

Example 2: (PWD=/home/user)

sudo add-apt-key /root/mariadb_release_signing_key.asc /usr/share/keyrings/mariadbkey

Will use existing key in /root, convert it and store as /usr/share/keyrings/mariadbkey.gpg

Example 3: (PWD=/home/user)

sudo add-apt-key mariadb_release_signing_key.asc mariadbkey

Will use existing key in /home/user, convert it and store as /etc/apt/keyrings/mariadbkey.gpg

After installing the PGP key, it is also possible to add the key and repository to /etc/apt/sources.list

  • The choice to add this will be presented in the script as the first input option
  • If Yes is chosen, the repository string must be pasted as the second input option

This completes the key installation by adding the corresponding repository line to /etc/apt/sources.list

Installation

Install by running the following commands:

sudo curl -L https://raw.githubusercontent.com/ameinild/add-apt-key/master/add-apt-key -o /usr/local/bin/add-apt-key
sudo curl -L https://raw.githubusercontent.com/ameinild/add-apt-key/master/add-apt-key.conf -o /usr/local/etc/add-apt-key.conf
sudo chmod a+rx /usr/local/bin/add-apt-key
14
  • 8
    Therefore, it is clearly demonstrated above that Linux is definitely not adapted to average end-users. Those Ubuntu and others should warned that you need serious advanced skills and have to be willing to spend a lot of time training, searching, and dealing , with those issues... even-more, with small guarantee that you that whatever you do will work or not create further problems. That's dishonesty. Jul 16, 2021 at 17:19
  • 3
    I'm pretty sure that future versions of Ubuntu will have adapted its own scripts to the "new" way of installing PGP keys. In the meantime, I've written a script to help other users achieve the closest possible to automating this. If you find it too advanced and not useful that's OK, but it was actually meant as a help. Jul 16, 2021 at 17:25
  • 1
    The script is updated with an option to write GPG key and repository directly to /etc/apt/sources.list Nov 1, 2021 at 19:00
  • 2
    @YannMonnier you are 100% right. If the Ubuntu developers cannot match their "security concerns" with what the community actually needs, the Ubuntu desktop will just stop being a viable option. I'm a big fan of Slackware, where the tools are much more streamlined and simple (although documentation is lacking). They are also likely "less secure", but we're not running a bank here - it's a PC!
    – levitopher
    Aug 6, 2022 at 16:00
  • 3
    New default location for keys is /etc/apt/keyrings. Oct 13, 2022 at 13:35
7

As a direct workalike, replace apt-key add with gpg --dearmor:

curl [KEYURL] | sudo gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/[KEYFILE].gpg

However, this is not recommended (other than as a workalike to apt-key) since all keys in the trusted directory are unconditionally trusted; it is better to put the output in a (non-globally) trusted directory (as others have suggested), and have each source specify which key(s) to trust, individually.

0
7

UPDATE: 2023-Nov-15, Back in August, a PR I submitted to the apt-manage project was accepted, it includes a quick-install script which will install apt-manage on Debian and Ubuntu and their derivitives.

Once again, I've modified my answer below, replacing the installation with the quick-install script.


UPDATE: 2023-May-16, I can confirm apt-manage is the safest most consistent way I found to manage apt sources with keys properly.

I've rewritten the answer, removing my personal script (you can view it in the revisions history if you'd like) to focus on the command and not my personal code.


All of the answers here are great, and I've learned a lot from them.

Per @mesterlion comments, as of this time there is a single tool that does all of this, and does it correctly, properly maintained by the Pop!_OS team.

That tool is apt-manage which is part of RepoLib module which introduced the key sub-command in version 2.

So in Pop!_OS 22.04, installation will look like this:

sudo apt install --yes apt-manage

The upstream projects (Ubuntu and Debian) are missing this package, for that: the apt-manage project has a quick-install script (full disclosure, I submitted the PR for it).
Installing will look like:

curl https://raw.githubusercontent.com/pop-os/repolib/HEAD/quick-install.sh | bash 

More details can be found in the Installation section of the git-repo's README.md.

Example 1

After installing apt-manage, below is an example of a set of calls from my system:

# Adding PPA
sudo apt-manage add --terse --format=sources ppa:ppa:alessandro-strada/ppa

# Adding APT source and assinging a key
sudo apt-manage add --terse --format=sources --name Microsoft --identifier packages-microsoft-com 'deb [arch=amd64] https://packages.microsoft.com/ubuntu/22.04/prod jammy main'
# Assigning a key via URL
sudo apt-manage key packages-microsoft-com --url=https://packages.microsoft.com/keys/microsoft.asc

# R-Project needed some additional love - because they do something 'different':
sudo apt-manage add --terse --format=sources --name R-Project --identifier cloud-r-project-org 'deb [arch=amd64] https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ ""_""'
# Specific to R-Project, as one of the values are empty and the command line can' pass it effectively.
sudo sed -i /etc/apt/sources.list.d/cloud-r-project-org.sources -Ee 's/""_""//g'
# Assigning a key via fingerprint
sudo apt-manage key cloud-r-project-org --fingerprint=E298A3A825C0D65DFD57CBB651716619E084DAB9

# After all were added, run update.
sudo apt update

Example 2: Initialize docker on a fresh Ubuntu compute instance

set -e

export DEBIAN_FRONTEND=noninteractive

apt-get update \
&& apt-get install --yes --no-install-recommends \
    apt-transport-https ca-certificates \
    wget gnupg software-properties-common lsb-release \
    curl jq bash-completion

has() { command -v "$1" > /dev/null; }

# Try differnt ways of installing apt-manage
# First let's hope there is package ready for installation
has apt-manage \
|| curl https://raw.githubusercontent.com/pop-os/repolib/HEAD/quick-install.sh | bash 

# If the repo isn't part of existing apt sources, add it
REPO_URL="https://download.docker.com/linux/ubuntu"
APT_NAME="$(
    apt-manage list -a \
    | grep -B4 "${REPO_URL}" | head -1 \
    | sed -Ee 's/^\W*([^:]+):$/\1/'
)"
if [[ -n "${APT_NAME}" ]]; then
    >&2 printf '%s\n' \
        '' \
        "$(apt-manage list "${APT_NAME}")" \
        '' \
        "Docker repository found [${APT_NAME}]. Skipping."
else
    apt-manage add --identifier download-docker-com --name Docker \
        --terse --format=sources \
        "$( printf "deb [arch=%s] %s %s %s" \
            "$(dpkg --print-architecture)" \
            "${REPO_URL}" \
            "$(lsb_release --codename --short)" \
            "stable"
        )"

    apt-manage key download-docker-com \
        --url=https://download.docker.com/linux/ubuntu/gpg
fi
10
  • 1
    If you use PopOS, you can use apt-manage (from repolib) out-of-the-box
    – MestreLion
    Dec 16, 2022 at 0:18
  • 1
    apt-manage does have options to download the GPG key from an URL and associate it with a repository. By default it uses /etc/apt/keyrings, which Debian also recommends
    – MestreLion
    Dec 30, 2022 at 23:42
  • 1
    It is available to Debian and Ubuntu, and works just fine in 22.04. Just get the .deb from their github release or create one yourself (instructions in their front page README): github.com/pop-os/repolib
    – MestreLion
    Jan 19, 2023 at 0:16
  • 1
    Yet another way of installing on Ubuntu is to add the PopOS repository to apt: add-apt-repository "deb https://apt.pop-os.org/release $(lsb_release -cs) main". That might be the best route (automatic updates), but make sure you also create an apt "pin" so it only pulls the repolib package from this repository and no other package!. See wiki.debian.org/…
    – MestreLion
    Jan 27, 2023 at 1:15
  • 1
    Agree, don't really know why it doesn't get the love it deserves. It's a well written tool.
    – Lockszmith
    May 16, 2023 at 14:58
0

Keys for use by apt are stored in /etc/apt/trusted.gpg.d/. apt-key managed these keyrings for you, but now that it's deprecated you need to choose a suitable file name <KEYRING> for the keyring yourself.

If you have the key already as a local file <FILE>, run

gpg --no-default-keyring --keyring=gnupg-ring:/etc/apt/trusted.gpg.d/<KEYRING>.gpg --import <FILE>

To directly read the key from <URL>, run

curl -sSfL <URL> | gpg --no-default-keyring --keyring=gnupg-ring:/etc/apt/trusted.gpg.d/<KEYRING>.gpg --import

Note: the prefix gnupg-ring: before the keyring name is required to create the keyring in the apt compatible (legacy) v4 format, rather than the (newer) keybox v1 format.

7
  • how should I modify the command you've mentioned, if I wanted to add gpg key: EBB4CCF6A72BC110 | 55D9B3F8D3E163D4CED77D9CEBB4CCF6A72BC110 from this PPA: https://launchpad.net/~ufleisch/+archive/ubuntu/kid3. I tried: curl -sSfL https://keyserver.ubuntu.com/pks/lookup?fingerprint=on&op=index&search=0x55D9B3F8D3E163D4CED77D9CEBB4CCF6A72BC110 | gpg --no-default-keyring --keyring=gnupg-ring:/etc/apt/trusted.gpg.d/<KEYRING>.gpg --import but it didn't work.
    – Jags
    Apr 25, 2021 at 0:32
  • (1) What should be the <URL> in case of this PPA: https://launchpad.net/~ufleisch/+archive/ubuntu/kid3 ? (2) Should I replace <KEYRING>.gpg with gnupg-ring.gpg ? Thanks alot.
    – Jags
    Apr 25, 2021 at 0:32
  • 2
    @Jags curl -sSfL 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x55d9b3f8d3e163d4ced77d9cebb4ccf6a72bc110' | sudo gpg --no-default-keyring --keyring=gnupg-ring:/etc/apt/trusted.gpg.d/kid.gpg --import
    – kynan
    Apr 25, 2021 at 21:23
  • Thank you so much, and one more question please. When I wanna import multiple keys at once for a new installation, can I just add more URLs like curl -sSfL <URL> <URL> <URL> or no? Thank you.
    – Jags
    Apr 25, 2021 at 22:58
  • The key was added just fine but now when I run sudo apt update, I'm getting alot of eerors like this: W: http://ppa.launchpad.net/ufleisch/kid3/ubuntu/dists/hirsute/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/kid.gpg are ignored as the file is not readable by user '_apt' executing apt-key. Thanks alot.
    – Jags
    Apr 26, 2021 at 0:37
0

If you have the *.asc file you can just --dearmor it

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .