Partager :
apt · Debian 13
apt-key a disparu de Debian 13 : lister ses clés, puis vérifier quel dépôt chacune peut signer
Publié le · HardStacked · 8 min
Tu es passé à Debian 13, tu as tapé apt-key list par réflexe, et la commande n'existe plus. Le remplacement évident : boucler sur /etc/apt/trusted.gpg.d/ avec gpg --show-keys. Ça marche. Ça sort quelque chose qui ressemble exactement à l'ancienne sortie de apt-key list. Ce que personne ne te dit, c'est que cette liste répond à la mauvaise question.
Quelqu'un a posé la version directe de la question et n'a rien obtenu :
« apt-key is removed in Debian 13. How to list keys? »
Traduction : « apt-key a été retiré de Debian 13. Comment lister les clés ? » (Unix & Linux Stack Exchange, question 805005, environ 338 vues par mois, aucune réponse acceptée.)
La question qui compte n'est pas « quelles clés j'ai ». C'est « quelle clé peut signer quel dépôt ». Ce sont deux questions différentes, et l'écart entre les deux est exactement l'endroit où un dépôt que tu croyais verrouillé reste grand ouvert.
01. Le verdict en deux lignes
Une clé posée dans /etc/apt/trusted.gpg.d/ est acceptée pour tout dépôt qui ne se restreint pas lui-même avec une ligne Signed-By, peu importe le nom du fichier de la clé. Un dépôt sans Signed-By accepte une signature de n'importe quelle clé de ce dossier. Un dépôt avec Signed-By pointant sur une clé précise refuse toutes les autres clés, y compris celles qui vivent juste à côté dans trusted.gpg.d. Et apt modernize-sources, l'outil fourni par Debian pour migrer les anciennes entrées .list, peut écrire un champ Signed-By: syntaxiquement présent et complètement vide. Ce champ a l'air restreint. Il se comporte comme global.
Mesuré le 2026-09-27 sur Debian 13 (trixie), Raspberry Pi 5, apt 3.0.3 (signatures vérifiées par sqv).
02. Ce qui remplace vraiment apt-key list
gpg --show-keys sur chaque fichier de /etc/apt/trusted.gpg.d/ donne l'équivalent le plus proche : empreinte, uid, expiration. Sur cette machine, ça fait 10 fichiers. En voici deux :
Ces commandes sont fournies telles quelles, sans garantie. Teste d'abord sur une machine non critique ou sur un instantané.
gpg --show-keys, 2 fichiers sur 10
== /etc/apt/trusted.gpg.d/debian-archive-trixie-stable.asc
pub ed25519 2025-03-24 [SC] [expires: 2033-03-22]
41587F7DB8C774BCCF131416762F67A0B2C39DE4
uid Debian Stable Release Key (13/trixie) <debian-release@lists.debian.org>
== /etc/apt/trusted.gpg.d/debian-archive-bullseye-automatic.asc
pub rsa4096 2021-01-17 [SC] [expires: 2029-01-15]
1F89983E0081FDE018F3CC9673A4F27B8DD47936
Revocable by: 80E976F14A508A48E9CA3FE9BC372252CA1CF964
Revocable by: FBFABDB541B5DC955BD9BA6EDB16CF5BB12525C4
Revocable by: 8C823DED10AA8041639E12105ACE8D6E0C14A470
Revocable by: 309911BEA966D0613053045711B4E5FF15B0FD82
Revocable by: C74F6AC9E933B3067F52F33FA459EC6715B0705F
uid Debian Archive Automatic Signing Key (11/bullseye) <ftpmaster@debian.org>
sub rsa4096 2021-01-17 [S] [expires: 2029-01-15]
Voilà pour la liste. Elle te dit ce qu'il y a dans le fichier. Elle ne dit rien sur quel dépôt, s'il y en a un, a le droit d'utiliser cette clé, et elle ne peut pas voir une clé qui n'est même pas stockée comme fichier séparé : man apt-secure documente Signed-By comme acceptant la clé embarquée directement, en ASCII armored, à l'intérieur d'une stanza .sources. Une boucle sur trusted.gpg.d n'atteint jamais cette clé, parce qu'elle n'a jamais été déposée là.
03. Le test qui sépare les deux questions
man sources.list décrit Signed-By comme un moyen d'exiger « a repository to pass apt-secure(8) verification with a certain set of keys rather than all trusted keys apt has configured » (« qu'un dépôt passe la vérification apt-secure(8) avec un ensemble de clés précis plutôt qu'avec toutes les clés de confiance configurées dans apt »). Lu au pied de la lettre : un dépôt sans cette option est vérifié contre toutes les clés de confiance, pas une seule. Cette phrase est tout le mécanisme, et elle vaut la peine d'être confirmée sur le vrai binaire plutôt que d'être prise au mot.
Le banc : un dépôt local signé par une clé de test ed25519 jetable, un vrai apt-get update, une configuration apt isolée via APT_CONFIG dans un espace de noms utilisateur, pour que rien ne touche la vraie machine.
| Cas | Situation | Résultat |
| A | clé dans trusted.gpg.d, dépôt sans Signed-By | accepté, rc 0 |
| B | même clé toujours dans trusted.gpg.d, Signed-By pointe sur une autre clé | refusé, rc 100, « Missing key » |
| C | témoin : aucune clé nulle part | refusé, rc 100 |
| D | Signed-By pointe sur la bonne clé, trusted.gpg.d vide | accepté, rc 0 |
| E | la même clé globale, enregistrée sous zz-looks-harmless.asc | accepté, le nom du fichier ne compte pas |
| F | apt modernize-sources sur un .list sans signed-by | rc 0, avertissement, écrit Signed-By: vide |
| G | apt-get update juste après F, clé toujours dans trusted.gpg.d | accepté, rc 0 |
| H | même fichier qu'en G, trusted.gpg.d vidé | refusé, rc 100 |
Le cas F, suivi de G, est celui qui mérite qu'on s'y arrête. apt modernize-sources tourne, affiche un avertissement comme quoi il n'a pas pu déterminer le Signed-By automatiquement, et écrit quand même le champ dans le nouveau fichier .sources :
apt modernize-sources, cas F (extrait)
$ apt modernize-sources
Rewrite 1 sources? [Y/n] y
Modernizing /srv/etc/sources.list.d/test.list...
- Writing /srv/etc/sources.list.d/test.sources
Warning: Could not determine Signed-By for URIs: file:/srv/repo/, Suites: ./
[rc=0]
--- cat etc/sources.list.d/test.sources
Types: deb
URIs: file:/srv/repo/
Suites: ./
Components:
Signed-By:
Un grep Signed-By sur ce fichier trouve une occurrence et passe son chemin, convaincu que le dépôt est restreint. Le cas G montre ce qu'il se passe réellement : apt-get update juste après, avec une clé posée dans trusted.gpg.d, réussit quand même, rc 0. Un champ Signed-By: vide s'est comporté exactement comme l'absence du champ (cas A). Le cas H est la preuve, pas une note de bas de page : vide le dossier trusted.gpg.d et le même fichier, inchangé, échoue avec rc 100, « no keyring is specified ». Le fichier .sources n'a jamais eu sa propre confiance. Il empruntait la confiance globale depuis le début, et seul le cas H rend ça visible, parce que c'est le seul cas où on retire cette confiance globale et où on regarde le dépôt casser.
04. La commande qui répond à la vraie question
Ce script boucle par stanza (awk RS=""), lit Signed-By, attrape un bloc de clé embarquée, et retombe sur « n'importe quelle clé de trusted.gpg.d » quand le champ est absent ou vide :
liste-depots.sh
#!/bin/bash
# Quel dépôt accepte quelle clé ? Usage: liste-depots.sh [dossier] (défaut /etc/apt/sources.list.d)
D=${1:-/etc/apt/sources.list.d}
awk 'BEGIN{RS="";FS="\n"} {u="?";s="ANY key in trusted.gpg.d (no Signed-By)"
for(i=1;i<=NF;i++){ if($i~/^URIs:/){u=$i;sub(/^URIs:[ \t]*/,"",u)}
if($i~/^Signed-By:/){v=$i;sub(/^Signed-By:[ \t]*/,"",v)
if($(i+1)~/BEGIN PGP/) s="key embedded in this file"
else if(v=="") s="ANY key in trusted.gpg.d (Signed-By is EMPTY)"
else s=v }}
print u" -> "s}' "$D"/*.sources 2>/dev/null
grep -h '^deb' /etc/apt/sources.list "$D"/*.list 2>/dev/null | awk '{ if(match($0,/signed-by=[^] ]+/)) print $0" -> "substr($0,RSTART+10,RLENGTH-10); else print $0" -> ANY key in trusted.gpg.d (no signed-by)"}'
Vérifié contre 4 fichiers témoins avant de lui faire confiance sur une vraie machine : une stanza sans champ Signed-By, une avec le champ vide, une avec la clé embarquée directement, et une ligne .list legacy sans signed-by=. Les 4 sont ressortis correctement étiquetés. Sortie réelle sur cette machine :
liste-depots.sh sur ce Pi
$ bash liste-depots.sh
http://deb.debian.org/debian/ -> /usr/share/keyrings/debian-archive-keyring.pgp
http://deb.debian.org/debian-security/ -> /usr/share/keyrings/debian-archive-keyring.pgp
http://archive.raspberrypi.com/debian/ -> /usr/share/keyrings/raspberrypi-archive-keyring.pgp
Chaque dépôt nomme sa clé explicitement (un quatrième dépôt, tiers, est coupé de cette sortie ; il nomme aussi sa propre clé), aucun ne retombant sur « n'importe quelle clé de trusted.gpg.d ». C'est la réponse que gpg --show-keys sur trusted.gpg.d n'allait jamais te donner, parce qu'il ne lit pas du tout le côté dépôt de la relation.
05. Corriger un dépôt qui fait confiance à plus qu'il ne devrait
Si liste-depots.sh affiche « n'importe quelle clé de trusted.gpg.d » pour un dépôt qui ne devrait faire confiance qu'à une seule clé, le correctif reprend le cas D ci-dessus : dépose l'export public de cette clé dans /etc/apt/keyrings/, ajoute Signed-By: /etc/apt/keyrings/cette-cle.asc à la stanza .sources du dépôt (ou signed-by= sur une ligne .list), et relance. Mesuré : avec la clé rangée hors de trusted.gpg.d et Signed-By pointant directement dessus, apt-get update réussit toujours.
Ne retire pas tout de suite cette clé de trusted.gpg.d. Le cas H a mesuré exactement ça : retirer du pool global une clé dont un dépôt dépendait en silence, sans lui donner son propre Signed-By, et il arrête de se vérifier, rc 100. Avant de toucher à trusted.gpg.d, lance liste-depots.sh d'abord et vérifie qu'aucune autre entrée .sources ou .list de la machine ne dépend en silence de cette même clé globale sans le dire.
06. Ce que ça donne sur une vraie machine
liste-depots.sh sur ce Raspberry Pi 5 retourne 4 dépôts, et les 4 portent leur propre Signed-By, aucun ne retombant sur « n'importe quelle clé de trusted.gpg.d ». Pendant ce temps, /etc/apt/trusted.gpg.d/ contient 10 clés, dont 3 clés de signature de Debian 11 (bullseye). Aucune de ces 10 clés n'est requise par un dépôt configuré aujourd'hui, ça, c'est mesuré. Ce qui suit est une inférence, pas une deuxième mesure : ces clés seraient quand même acceptées, telles quelles, par n'importe quel dépôt ajouté demain qui saute le Signed-By, parce que le cas A a déjà montré que c'est exactement ainsi qu'un dépôt non restreint se comporte. Ce n'est pas une raison de les supprimer ici. Les 10 fichiers appartiennent à un paquet (dpkg -S : 9 à debian-archive-keyring, 1 à raspberrypi-archive-keyring), et les retirer à la main n'a pas été testé ; retiens le constat comme « vérifier ce qui en dépend d'abord », pas comme « faire le ménage ».
Portée
Mesuré sur apt 3.0.3, Debian 13 trixie. Non vérifié ici : Ubuntu, ou apt 2.x sur Debian 12 et antérieur.
apt modernize-sources dit lui-même, dans sa propre sortie, qu'il remplit Signed-By automatiquement « where they can be determined » (« lorsque ça peut être déterminé automatiquement »). Pour le seul dépôt de ce test, il n'a pas pu, et l'a dit dans un avertissement. Quels dépôts il résout automatiquement n'a pas été mesuré, donc ce texte ne fait aucune affirmation là-dessus non plus, dans un sens comme dans l'autre. Lance liste-depots.sh après chaque passage de modernize-sources, peu importe ce qu'il a affiché. Les cas F et G ensemble sont la raison : un code de sortie propre et un champ Signed-By: présent ne prouvent pas que le dépôt a été restreint.
La même forme traverse le reste de cette série, où le système déclare une chose et en fait une autre : un update-ca-certificates qui affiche 0 added, 0 removed que ton certificat soit pris ou ignoré et un systemctl enable qui annonce un échec alors que le service finit activé quand même.
Partager :