iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💮

Managing APT Repository Keys After apt-key Deprecation

に公開

As those using the official Debian probably already know, the apt-key command, used by the APT package management tool to manage OpenPGP public keys for electronic signatures, has been deprecated. Furthermore, it seems the apt-key command will be removed in Debian 12.

Ubuntu, being a Debian-based distribution, naturally follows suit.

$ sudo apt update

...

W: https://download.docker.com/linux/ubuntu/dists/jammy/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

I don't recall seeing this kind of warning until Ubuntu 21.10, so I had been ignoring it. But, well, it's about time to address it. Fortunately, handling third-party public keys doesn't seem to be too difficult in APT 2.4 and later[1].

In this article, I will introduce the steps for importing public keys and registering repositories, using the Docker Engine APT installation procedure on Ubuntu 22.04 LTS and later as an example.

Previous Installation Procedure

Although it seems to have been removed now, the old instructions on the “Install Docker Engine on Ubuntu” page were as follows:

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

to register the public key, and

$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

to register the repository. In this state, you could install it with:

$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Third-party OpenPGP public keys imported via the apt-key command are stored in the /etc/apt/trusted.gpg keyring file. You can view the contents of this file using the apt-key list command.

$ apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
--------------------
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown ] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]
...

Whoa. A warning appeared right away (lol).

Importing Third-Party OpenPGP Public Keys

On the current "Install Docker Engine on Ubuntu" page, the procedure for importing the OpenPGP public key is as follows:

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

To explain briefly, the first half of the command downloads the public key, and the second half stores it in the /usr/share/keyrings/docker-archive-keyring.gpg file. Since the file downloaded in the first half is in ASCII Armor format text, the gpg command in the second half converts it using --dearmor (i.e., into binary) before storing it. The key point here is that the public key data is placed as a standalone file rather than being added to a keyring file via the apt-key add command.

ASCII Armor is Perfectly Fine

Looking at the apt-key manual with the man command, it says:

Make sure to use the "asc" extension for ASCII armored keys and the "gpg" extension for the binary OpenPGP format (also known as "GPG key public ring"). The binary OpenPGP format works for all apt versions, while the ASCII armored format works for apt version >= 1.4.

So, in current versions, it seems perfectly fine to store it in ASCII Armor format. Furthermore, regarding the location of the public key files:

Recommended: Instead of placing keys into the /etc/apt/trusted.gpg.d directory, you can place them anywhere on your filesystem by using the Signed-By option in your sources.list and pointing to the filename of the key. See sources.list(5) for details. Since APT 2.4, /etc/apt/keyrings is provided as the recommended location for keys not managed by packages.

It is recommended to place them in the /etc/apt/keyrings/ directory in combination with the Signed-By option (described later). Therefore, the previous command can be replaced without even needing the gpg command:

$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker-key.asc

(The output filename is arbitrary). Simple! ♪

[Promotion] Pre-verify public keys with gpgpdump

You can use my gpgpdump command to analyze and display any OpenPGP data on the web. For example:

$ gpgpdump fetch -u --indent 2 https://download.docker.com/linux/ubuntu/gpg
Public-Key Packet (tag 6) (525 bytes)
  Version: 4 (current)
  Public key creation time: 2017-02-22T18:36:26Z
  Public-key Algorithm: RSA (Encrypt or Sign) (pub 1)
  RSA public modulus n (4096 bits)
  RSA public encryption exponent e (17 bits)
User ID Packet (tag 13) (43 bytes)
  User ID: Docker Release (CE deb) <docker@docker.com>
Signature Packet (tag 2) (567 bytes)
  Version: 4 (current)
  Signiture Type: Positive certification of a User ID and Public-Key packet (0x13)
  Public-key Algorithm: RSA (Encrypt or Sign) (pub 1)
  Hash Algorithm: SHA2-512 (hash 10)
  Hashed Subpacket (33 bytes)
    Signature Creation Time (sub 2): 2017-02-22T19:34:24Z
    Key Flags (sub 27) (1 bytes)
      Flag: This key may be used to certify other keys.
      Flag: This key may be used to sign data.
      Flag: This key may be used to encrypt communications.
      Flag: This key may be used to encrypt storage.
      Flag: This key may be used for authentication.
    Preferred Symmetric Algorithms (sub 11) (4 bytes)
      Symmetric Algorithm: AES with 256-bit key (sym 9)
      Symmetric Algorithm: AES with 192-bit key (sym 8)
      Symmetric Algorithm: AES with 128-bit key (sym 7)
      Symmetric Algorithm: CAST5 (128 bit key, as per) (sym 3)
    Preferred Hash Algorithms (sub 21) (4 bytes)
      Hash Algorithm: SHA2-512 (hash 10)
      Hash Algorithm: SHA2-384 (hash 9)
      Hash Algorithm: SHA2-256 (hash 8)
      Hash Algorithm: SHA2-224 (hash 11)
    Preferred Compression Algorithms (sub 22) (4 bytes)
      Compression Algorithm: ZLIB <RFC1950> (comp 2)
      Compression Algorithm: BZip2 (comp 3)
      Compression Algorithm: ZIP <RFC1951> (comp 1)
      Compression Algorithm: Uncompressed (comp 0)
    Features (sub 30) (1 bytes)
      Flag: Modification Detection (packets 18 and 19)
    Key Server Preferences (sub 23) (1 bytes)
      Flag: No-modify
  Unhashed Subpacket (10 bytes)
    Issuer (sub 16): 0x8d81803c0ebfcd88
  Hash left 2 bytes
    b2 c9
  RSA signature value m^d mod n (4094 bits)
Public-Subkey Packet (tag 14) (525 bytes)
  Version: 4 (current)
  Public key creation time: 2017-02-22T18:36:26Z
  Public-key Algorithm: RSA (Encrypt or Sign) (pub 1)
  RSA public modulus n (4096 bits)
  RSA public encryption exponent e (17 bits)
Signature Packet (tag 2) (1086 bytes)
  Version: 4 (current)
  Signiture Type: Subkey Binding Signature (0x18)
  Public-key Algorithm: RSA (Encrypt or Sign) (pub 1)
  Hash Algorithm: SHA2-256 (hash 8)
  Hashed Subpacket (9 bytes)
    Signature Creation Time (sub 2): 2017-02-22T18:36:26Z
    Key Flags (sub 27) (1 bytes)
      Flag: This key may be used to sign data.
  Unhashed Subpacket (553 bytes)
    Issuer (sub 16): 0x8d81803c0ebfcd88
    Embedded Signature (sub 32) (540 bytes)
      Signature Packet (tag 2) (540 bytes)
        Version: 4 (current)
        Signiture Type: Primary Key Binding Signature (0x19)
        Public-key Algorithm: RSA (Encrypt or Sign) (pub 1)
        Hash Algorithm: SHA2-256 (hash 8)
        Hashed Subpacket (6 bytes)
          Signature Creation Time (sub 2): 2017-02-22T18:36:26Z
        Unhashed Subpacket (10 bytes)
          Issuer (sub 16): 0x7ea0a9c3f273fcd8
        Hash left 2 bytes
          d5 60
        RSA signature value m^d mod n (4095 bits)
  Hash left 2 bytes
    f2 b8
  RSA signature value m^d mod n (4095 bits)

Something like that. This allows you to pre-verify the details of the public key you are about to import.
Furthermore, by adding the --raw option to the gpgpdump fetch command, you can output the fetched data directly to standard output. So, instead of using the curl command for importing as shown earlier, you could do:

$ sudo sh -c "gpgpdump fetch --raw https://download.docker.com/linux/ubuntu/gpg > /etc/apt/keyrings/docker-key.asc"

or

$ gpgpdump fetch --raw https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker-key.asc > /dev/null

That concludes the promotion (lol).

Linking Repositories and Public Keys with Signed-By

Referring to the current "Install Docker Engine on Ubuntu" page, let's register the Docker Engine APT repository in source.list. Assuming the imported OpenPGP public key file is /etc/apt/keyrings/docker-key.asc, the repository registration would look like this:

$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker-key.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Or if you prefer using the add-apt-repository command:

$ sudo add-apt-repository "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker-key.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

This should also work. The key point is the signed-by option. You can use this to link the repository and the public key.

Once this is done, you can install and update packages as usual with apt update/install/upgrade.

Users Manage Third-Party Package Public Keys

The reason for doing this seemingly troublesome task is that if the private key corresponding to a third-party package's public key is leaked, the official APT side cannot address it, so they want to separate it from the keyring. If an unmanaged key whose private key has been leaked is left unattended, the possibility of "trusted malware" being injected increases.

Well, but the idea of separating management rather than excluding third-party keys is very Linux-like. It sets itself apart from the app stores of certain companies like A, G, or M (lol).

In return, the management of third-party public keys becomes the user's responsibility. If management of the public keys, including revocation, is not properly performed on the user side, you will end up carrying the risk yourself.

Be careful out there!

[Bonus] Installing pgAdmin 4

When installing pgAdmin, a friend to PostgreSQL service administrators, via APT, you also need to import the public key. Since v6.9, which supports Ubuntu 22.04 LTS, is out, let's try to handle it. It would look something like this (the output filename is arbitrary).

$ sudo curl -fsSL https://www.pgadmin.org/static/packages_pgadmin_org.pub -o /etc/apt/keyrings/pgadmin-4-key.asc

Repository registration is as follows:

$ sudo sh -c 'echo "deb [signed-by=/etc/apt/keyrings/pgadmin-4-key.asc] https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list'

That's it. After that, update and upgrade as usual, and there should be no problems.

脚注
  1. At the time of upgrading to Ubuntu 22.04 LTS, it was at APT 2.4.5. ↩︎

GitHubで編集を提案

Discussion