Vous déployez des correctifs sur des serveurs, votre pipeline est vert, et puis — sans prévenir — cert verify failed apparaît comme un contrôle surprise.
apt ne peut plus récupérer de paquets, curl refuse de communiquer, les pulls Docker échouent et les logs applicatifs ressemblent à une malédiction médiévale :
« unknown authority », « unable to get local issuer certificate », « self-signed certificate in certificate chain ».
Ubuntu 24.04 n’est pas spécialement fragile ici. Il est juste honnête. Il vérifie TLS correctement, et il ne fera pas semblant que votre chaîne de certificats est correcte quand ce n’est pas le cas.
La solution n’est rarement pas de « désactiver la vérification ». La solution consiste à réparer les magasins de confiance et à servir des chaînes intermédiaires correctes. Faites-le une fois, faites-le bien, et passez à autre chose.
Fiche de diagnostic rapide
Quand la vérification TLS échoue, les gens ont tendance à s’agiter : réinstaller des paquets au hasard, changer des variables d’environnement, accuser Ubuntu, accuser « le réseau ».
Ne le faites pas. Vous déboguez un problème de chaîne de confiance. Traitez-le comme un incident de production : isolez, reproduisez et déterminez quel magasin de confiance est utilisé.
Première étape : reproduire avec un outil connu
- Si l’échec survient dans une appli, reproduisez avec
openssl s_client(vérité terrain) etcurl -v(comportement client). - Capturez : nom d’hôte, port, SNI, proxy/no-proxy, et si l’hôte en échec est dans un conteneur/VM.
Deuxième étape : décider s’il s’agit de la « chaîne serveur » ou du « magasin de confiance client »
- Si
openssl s_clientmontre des intermédiaires manquants, corrigez d’abord le serveur. C’est la correction propre. - Si la chaîne serveur est correcte mais que les clients échouent encore, votre magasin de confiance client est obsolète ou contourné (bundle CA personnalisé, lien symbolique cassé, image ancienne, magasin Java spécial).
Troisième étape : vérifier l’interception
- Si l’émetteur du certificat est votre entreprise, un proxy termine TLS. Ajoutez la CA racine d’entreprise au magasin de confiance de l’OS (et possiblement aux magasins spécifiques aux applications).
- Si le sujet du certificat ne correspond pas au nom d’hôte, vous n’atteignez pas le serveur que vous pensez atteindre (proxy, portail captif, détournement DNS, VIP erroné).
Quatrième étape : circonscrire le périmètre
- Est-ce que ça échoue uniquement sur un hôte ? C’est le magasin de confiance local, l’horloge, ou la config proxy.
- Est-ce que ça échoue sur toute la flotte ? C’est une rotation de CA, un changement de politique proxy, ou une chaîne serveur cassée déployée largement.
- Est-ce que ça échoue uniquement dans des conteneurs ? C’est la dérive du bundle CA d’image (ou les différences Alpine vs Debian).
Une idée paraphrasée de W. Edwards Deming que les ops réapprennent souvent à la dure : Sans données, vous n’êtes qu’une autre personne avec une opinion
(idée paraphrasée).
Collectez les preuves de la poignée de main avant de « réparer » quoi que ce soit.
Ce que signifie réellement « cert verify failed » sur Ubuntu 24.04
« Cert verify failed » n’est pas une seule erreur. C’est une famille d’échecs qui se terminent tous au même endroit : le client n’a pas pu construire un chemin de confiance depuis le certificat serveur présenté jusqu’à une CA racine de confiance.
Cela peut arriver pour plusieurs raisons concrètes :
- Certificat(s) intermédiaire(s) manquant(s) sur le serveur (le plus courant sur le terrain).
- Magasin de confiance client ne contenant pas la CA racine (fréquent avec une PKI privée ou une inspection TLS d’entreprise).
- Heure système incorrecte (certificat non encore valide / expiré).
- Non-correspondance du nom d’hôte (connexion au mauvais service, mauvais SNI, ou bizarreries DNS/Proxy).
- L’application utilise son propre bundle CA et ignore le magasin système (bonjour Java ; aussi certains environnements Python, Node et applications conteneurisées).
- Packaging du bundle CA cassé (rare, mais arrive après des mises à jour partielles, des modifications manuelles ou des accidents de couches d’image).
- Politique de révocation/CRL/OCSP dans des clients stricts (moins courant par défaut sur Ubuntu, mais fréquent dans les outils d’entreprise).
Ubuntu 24.04 utilise OpenSSL 3 dans le système de base et fournit le paquet ca-certificates contenant l’ensemble de confiance de Mozilla sous forme de bundle.
La plupart des outils en ligne de commande consultent finalement cela, sauf s’ils sont codés pour utiliser autre chose.
L’objectif n’est pas de « faire disparaître l’erreur ». L’objectif est de rendre la chaîne de certificats correcte et l’ancre de confiance explicite.
Si vous faites cela, l’erreur disparaît en conséquence. C’est la bonne direction causale.
Blague n°1 : Désactiver la vérification TLS en production, c’est comme enlever le détecteur de fumée parce qu’il ne cesse de sonner. Le bip faisait son travail.
Faits et historique qui expliquent le bazar actuel
Un peu de contexte rend les échecs d’aujourd’hui moins aléatoires. Voici quelques faits concrets et réellement utiles :
- Les bundles CA sur Linux suivent majoritairement le programme racine de Mozilla. Le paquet
ca-certificatesest essentiellement un wrapper adapté à la distribution autour de cette liste de confiance. - Les certificats intermédiaires ne sont pas universellement mis en cache. Certains clients mettent en cache les intermédiaires, d’autres non, et les caches expirent. Un serveur qui « marche sur mon laptop » peut quand même être cassé.
- Les changements précoces de chaîne de Let’s Encrypt ont brûlé beaucoup de monde. Les cross-signatures et les problèmes de sélection de chaîne ont causé des échecs intermittents sur des clients anciens et des serveurs mal configurés.
- SNI (Server Name Indication) est devenu pratiquement obligatoire. Sans SNI, vous pouvez obtenir le mauvais certificat depuis un point de terminaison multi-tenant et échouer la vérification du nom d’hôte.
- OpenSSL 3 a renforcé l’écosystème. Il n’a pas « cassé TLS » ; il a rendu les comportements faibles, ambigus ou mal configurés plus visibles et moins tolérés.
- L’interception TLS d’entreprise est plus vieille que la plupart des plateformes conteneurisées. Elle précède Kubernetes, Docker et même certains fournisseurs cloud ; elle est simplement devenue plus pénible une fois que tout est passé en HTTPS.
- Java a historiquement embarqué son propre magasin de confiance. Beaucoup d’apps d’entreprise l’utilisent encore, d’où le cas fréquent « marche avec curl, échoue dans l’appli ».
- La construction de chemin peut varier selon la bibliothèque. GnuTLS vs OpenSSL vs NSS peuvent réussir ou échouer différemment sur la même chaîne, selon la manière dont les intermédiaires sont gérés.
- Il n’existe pas un « emplacement standard » que chaque programme honore. Linux a des conventions, mais chaque pile peut les outrepasser, et nombre d’entre elles le font.
Magasins de confiance sur Ubuntu 24.04 : qui lit quoi
Avant d’exécuter des commandes, clarifiez un modèle mental : « le magasin CA de l’OS » n’est pas un fichier unique. C’est un ensemble de sources compilées en fichiers de bundle,
et différents outils choisissent différents points d’entrée.
Fichiers et répertoires clés
/etc/ssl/certs/ca-certificates.crt— le bundle PEM principal (défaut courant pour les outils basés sur OpenSSL)./etc/ssl/certs/— liens symboliques hachés et certificats individuels utilisés par les recherches OpenSSL./usr/local/share/ca-certificates/— où déposer les CA locales (.crt) pour qu’elles soient ajoutées au magasin système./etc/ca-certificates.conf— quelles CA sont activées/désactivées lors de la génération des bundles./var/lib/ca-certificates/— contenu généré/géré (ne pas l’éditer à la main).
Qui utilise quoi (typique)
- curl : utilise généralement le chemin/bundle OpenSSL ; respecte
SSL_CERT_FILE/SSL_CERT_DIR. - apt : utilise la pile OpenSSL/gnutls système selon la compilation ; sur Ubuntu il s’appuie typiquement sur la confiance système via
ca-certificates. - Python requests : utilise
certifipar défaut dans beaucoup de virtualenvs sauf configuration contraire pour utiliser le magasin système. - Java : utilise
cacertsdans le JRE sauf configuration explicite différente. - Docker : utilise la confiance de l’OS pour les appels vers les registres, mais dispose aussi de répertoires de certificats par registre.
Traduction en langage opérateur : si seule une application échoue, n’allez pas réinstaller sans cesse ca-certificates. Vous réparez probablement le mauvais magasin de confiance.
Tâches pratiques (commandes, sorties, décisions)
Ci-dessous des tâches pratiques à exécuter sur Ubuntu 24.04. Chaque tâche inclut : une commande, ce que signifie une sortie typique, et la décision à prendre ensuite.
Elles sont écrites pour de vrais incidents : serveurs, runners CI, conteneurs et réseaux d’entreprise.
Tâche 1 : Confirmer l’heure système (ennuyeux, mais prioritaire)
cr0x@server:~$ timedatectl
Local time: Mon 2025-12-30 11:22:43 UTC
Universal time: Mon 2025-12-30 11:22:43 UTC
RTC time: Mon 2025-12-30 11:22:43
Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Signification : Si l’horloge n’est pas synchronisée, vous pouvez obtenir des erreurs « certificat non encore valide » ou « expiré » même avec des chaînes parfaites.
Décision : Si System clock synchronized est no, corrigez d’abord le NTP. Ne touchez pas aux certificats tant que l’heure n’est pas correcte.
Tâche 2 : Reproduire avec curl et capturer l’échec exact de vérification
cr0x@server:~$ curl -Iv https://repo.example.internal/
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
curl: (60) SSL certificate problem: unable to get local issuer certificate
Signification : Le client n’a pas pu construire une chaîne jusqu’à une racine de confiance. Cela signifie souvent soit des intermédiaires manquants (côté serveur), soit une racine manquante (côté client).
Décision : Passez à openssl s_client pour voir ce que le serveur présente réellement.
Tâche 3 : Inspecter la chaîne serveur avec OpenSSL (vérité terrain)
cr0x@server:~$ openssl s_client -connect repo.example.internal:443 -servername repo.example.internal -showcerts -verify_return_error </dev/null
depth=0 CN = repo.example.internal
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = repo.example.internal
verify error:num=21:unable to verify the first certificate
verify return:1
Verification error: unable to verify the first certificate
---
Certificate chain
0 s:CN = repo.example.internal
i:CN = Example Issuing CA 01
-----BEGIN CERTIFICATE-----
...leaf...
-----END CERTIFICATE-----
---
Signification : Le serveur n’a présenté que le certificat leaf. Aucun intermédiaire n’a été envoyé. Les clients qui n’ont pas l’intermédiaire en cache échoueront.
Décision : Corrigez le serveur pour qu’il présente la chaîne complète (leaf + intermédiaire(s)). C’est la correction préférée.
Tâche 4 : Vérifier quel bundle CA curl utilise
cr0x@server:~$ curl -v https://example.com/ 2>&1 | grep -E "CAfile|CApath"
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
Signification : curl utilise le bundle système et le répertoire haché.
Décision : Si votre CA d’entreprise n’est pas de confiance, vous devez l’ajouter via /usr/local/share/ca-certificates et exécuter update-ca-certificates.
Tâche 5 : Vérifier que le bundle CA de l’OS existe et n’est pas manifestement corrompu
cr0x@server:~$ ls -l /etc/ssl/certs/ca-certificates.crt
-rw-r--r-- 1 root root 223541 Dec 30 10:58 /etc/ssl/certs/ca-certificates.crt
Signification : Le bundle existe et a une taille non triviale.
Décision : S’il manque ou est minuscule (quelques octets), suspectez un état de paquet cassé ou une exécution de gestion de configuration ratée. Réinstallez ca-certificates.
Tâche 6 : Réinstaller et régénérer proprement les certificats CA
cr0x@server:~$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists... Done
cr0x@server:~$ sudo apt-get install --reinstall -y ca-certificates
Reading package lists... Done
Building dependency tree... Done
0 upgraded, 0 newly installed, 1 reinstalled, 0 to remove and 0 not upgraded.
Setting up ca-certificates (20240203) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Signification : Le paquet est présent ; la régénération du bundle a été exécutée.
Décision : Si des erreurs apparaissent pendant « Updating certificates », arrêtez-vous et lisez-les. Permissions, disque plein ou fichiers corrompus dans le répertoire des CA locales peuvent bloquer la mise à jour.
Tâche 7 : Vérifier les CA locales et si elles ont été importées
cr0x@server:~$ ls -l /usr/local/share/ca-certificates
total 8
-rw-r--r-- 1 root root 2048 Dec 30 10:57 corp-proxy-root-ca.crt
-rw-r--r-- 1 root root 1876 Dec 30 10:57 corp-issuing-ca.crt
Signification : Des fichiers CA locaux existent dans le répertoire correct et ont l’extension .crt.
Décision : Si vos fichiers CA sont en .pem ou portent des extensions étranges, renommez-les en .crt et exécutez update-ca-certificates.
Tâche 8 : Importer les CA locales dans le magasin de confiance Ubuntu
cr0x@server:~$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
2 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
Signification : Vos deux CA locales ont été ajoutées et hachées dans /etc/ssl/certs.
Décision : Retestez l’outil en échec. S’il échoue encore, vous avez probablement un problème de chaîne intermédiaire côté serveur ou une appli qui utilise un autre magasin de confiance.
Tâche 9 : Vérifier une chaîne contre le magasin système explicitement
cr0x@server:~$ openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /tmp/server-leaf.pem
CN = repo.example.internal
error 20 at 0 depth lookup: unable to get local issuer certificate
error /tmp/server-leaf.pem: verification failed
Signification : Le seul leaf ne peut pas être vérifié car OpenSSL ne trouve pas son émetteur (intermédiaire) dans le magasin de confiance.
Décision : Si l’intermédiaire n’est pas censé être une racine de confiance, ne l’ajoutez pas au magasin juste pour « faire marcher ». Corrigez plutôt la chaîne serveur.
Tâche 10 : Récupérer et vérifier la chaîne complète depuis le serveur
cr0x@server:~$ openssl s_client -connect repo.example.internal:443 -servername repo.example.internal -showcerts </dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > /tmp/chain.pem
cr0x@server:~$ openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt -untrusted /tmp/chain.pem /tmp/chain.pem
/tmp/chain.pem: OK
Signification : Une fois les intermédiaires disponibles, la vérification réussit.
Décision : Si openssl verify réussit mais que votre appli échoue, votre appli utilise probablement un autre bundle CA (certifi Python, cacerts Java, bundle embarqué).
Tâche 11 : Diagnostiquer les échecs HTTPS d’apt avec sortie ciblée
cr0x@server:~$ sudo apt-get update -o Debug::Acquire::https=true
Ign:1 https://repo.example.internal noble InRelease
Err:1 https://repo.example.internal noble InRelease
Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.
Reading package lists... Done
W: Failed to fetch https://repo.example.internal/dists/noble/InRelease Certificate verification failed: The certificate is NOT trusted. The certificate issuer is unknown.
Signification : apt ne peut pas valider la chaîne du dépôt.
Décision : Soit le serveur du dépôt manque d’intermédiaires, soit votre magasin système n’inclut pas la racine d’entreprise. N’utilisez pas [trusted=yes] comme pansement sauf en cas de plan d’urgence.
Tâche 12 : Vérifier si un proxy est utilisé pour apt et curl
cr0x@server:~$ env | grep -iE 'http_proxy|https_proxy|no_proxy'
https_proxy=http://proxy.corp.internal:3128
no_proxy=localhost,127.0.0.1,.corp.internal
Signification : Les requêtes peuvent transiter par un proxy, potentiellement en interceptant TLS.
Décision : Si le proxy intercepte, installez sa CA racine dans le magasin de confiance système. Si vous vouliez un accès direct, corrigez la configuration d’environnement et d’apt.
Tâche 13 : Confirmer que le certificat reçu correspond au nom d’hôte (correction SNI)
cr0x@server:~$ openssl s_client -connect 10.20.30.40:443 -servername repo.example.internal </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer
subject=CN = repo.example.internal
issuer=CN = Example Issuing CA 01
Signification : Avec le SNI fourni, vous avez obtenu le certificat attendu.
Décision : Si le sujet est incorrect sans SNI, votre client/outil n’envoie peut-être pas le SNI (rare aujourd’hui, mais toujours possible dans des piles embarquées). Forcer des outils capables de SNI ou corriger le point de terminaison.
Tâche 14 : Identifier si Python utilise certifi au lieu des CA système
cr0x@server:~$ python3 -c "import ssl; print(ssl.get_default_verify_paths())"
DefaultVerifyPaths(cafile='/etc/ssl/certs/ca-certificates.crt', capath='/etc/ssl/certs', openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/lib/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/lib/ssl/certs')
cr0x@server:~$ python3 -c "import requests; import certifi; print(certifi.where())"
/usr/lib/python3/dist-packages/certifi/cacert.pem
Signification : Le module SSL utilise par défaut le magasin OS, mais requests peut préférer le bundle certifi selon le packaging et l’environnement.
Décision : Si votre CA d’entreprise n’est présente que dans le magasin OS, configurez votre appli pour l’utiliser (ou mettez à jour le bundle certifi dans cet environnement, ou fournissez un chemin CA correct).
Tâche 15 : Vérifier le magasin de confiance Java si seules les JVM apps échouent
cr0x@server:~$ sudo keytool -list -keystore /etc/ssl/certs/java/cacerts -storepass changeit | head
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 141 entries
Signification : Java a son propre magasin CA.
Décision : Si les racines d’entreprise ne sont pas présentes, importez-les dans le cacerts Java (ou pointez la JVM vers le bundle OS explicitement). Corriger uniquement la confiance OS ne sauvera pas la JVM ici.
Tâche 16 : Chemin de confiance pour registre Docker (si les pulls d’images échouent)
cr0x@server:~$ sudo ls -l /etc/docker/certs.d
total 4
drwxr-xr-x 2 root root 4096 Dec 30 11:01 registry.corp.internal:5000
cr0x@server:~$ sudo ls -l /etc/docker/certs.d/registry.corp.internal:5000
total 4
-rw-r--r-- 1 root root 2048 Dec 30 11:01 ca.crt
Signification : Docker dispose d’ancrages de confiance par registre ; il peut fonctionner même si la confiance OS est incomplète (ou vice versa).
Décision : Choisissez un modèle. En entreprise, je préfère ajouter la racine d’entreprise à la confiance OS et garder les overrides Docker minimaux et documentés.
Chaînes intermédiaires : le tueur silencieux
La plupart des incidents « cert verify failed » qui semblent mystérieux sont simplement des intermédiaires manquants. Les serveurs sont censés présenter une chaîne
qui permet aux clients de lier le certificat leaf à une racine de confiance. La racine elle-même n’est généralement pas envoyée ; les clients l’ont déjà.
Les intermédiaires doivent être envoyés par le serveur.
Comment cela échoue en pratique
Une mauvaise configuration commune consiste à installer uniquement le certificat leaf sur le point de terminaison TLS. Les navigateurs peuvent encore réussir parce que :
(a) ils ont mis en cache l’intermédiaire depuis ailleurs, (b) ils l’ont récupéré via AIA (Authority Information Access), ou (c) ils se montrent plus tolérants.
Pendant ce temps, les clients headless en production échouent parce qu’ils ne récupèrent pas les intermédiaires ou qu’ils sont empêchés d’effectuer des requêtes sortantes.
Que faire à la place
- Du côté serveur, configurez le service TLS avec le fichier de chaîne complète (leaf + intermédiaire(s), dans l’ordre correct).
- Confirmez avec
openssl s_client -showcertsque l’intermédiaire est réellement servi. - Privilégiez la correction côté serveur. Ajouter des intermédiaires comme ancres de confiance sur les clients est une dette opérationnelle déguisée en « solution rapide ».
Blague n°2 : Les chaînes de certificats sont comme les organigrammes — si vous sautez les managers intermédiaires, rien n’est approuvé et tout le monde blâme le stagiaire.
Proxies d’entreprise et interception TLS
Dans beaucoup d’entreprises, le HTTPS sortant est intercepté : le proxy termine TLS, inspecte le trafic, puis ré-encrypte vers la destination.
L’émetteur du certificat devient « Corporate Proxy Root CA » (ou similaire), et les clients échoueront sauf si cette racine est de confiance.
Comment confirmer l’interception
Lancez openssl s_client vers un site public depuis l’hôte affecté et inspectez l’émetteur. S’il ne s’agit pas d’une CA publique attendue,
vous ne parlez pas directement à Internet. Vous parlez à votre entreprise.
Comment corriger correctement
- Récupérez la CA racine d’entreprise (et tous les intermédiaires d’émission utilisés par le proxy) en format PEM.
- Installez-la dans
/usr/local/share/ca-certificateset exécutezupdate-ca-certificates. - Puis auditez les magasins de confiance spécifiques aux applications (Java, certifi Python, embarqué). Décidez d’un standard : utiliser la confiance OS ou maintenir des magasins par appli.
Ce qu’il ne faut pas faire
- Ne désactivez pas la vérification dans apt/curl globalement.
- Ne parsemez pas vos scripts CI de flags « insecure » en pensant avoir réglé le problème.
- Ne pas importer des certificats leaf comme racines de confiance. Ce n’est pas de la confiance, c’est une reddition.
Trois mini-récits d’entreprise issus du terrain
1) L’incident causé par une mauvaise hypothèse : « Le load balancer gère la chaîne »
Une société de taille moyenne gérait des dépôts de paquets internes derrière un load balancer managé. Une équipe a renouvelé le certificat leaf,
l’a téléversé, a vu les navigateurs réussir, et est passée à autre chose. Le lendemain, les fenêtres de patch ont commencé à échouer sur un groupe d’hôtes Ubuntu :
apt ne pouvait plus récupérer les mises à jour. « Cert verify failed » partout.
L’hypothèse était simple et erronée : ils croyaient que le load balancer servait automatiquement la chaîne intermédiaire correcte.
Il ne l’a pas fait. Il ne servait que le leaf. La raison pour laquelle cela « fonctionnait dans les navigateurs » était des intermédiaires en cache et, sur certains réseaux,
une récupération opportuniste via AIA. Les clients apt headless ne récupéraient pas. Les runners CI dans des réseaux restreints non plus.
Le débogage a pris plus de temps que nécessaire parce que tout le monde a commencé par réinstaller ca-certificates sur les clients.
Cela n’a rien changé. L’échec était côté serveur. Dès que quelqu’un a exécuté openssl s_client -showcerts et vu une chaîne de longueur un,
la correction est devenue évidente : configurer le load balancer avec un fullchain approprié.
La leçon durable n’était pas « utilisez fullchain » (tout le monde le savait déjà). C’était : ne faites confiance à rien que vous n’ayez pas vérifié depuis le point de vue du client en échec.
Le même point de terminaison peut sembler fonctionnel depuis un laptop et cassé depuis un serveur verrouillé.
2) L’optimisation qui s’est retournée contre eux : « Intégrer des bundles CA dans le conteneur pour la vitesse »
Une autre organisation a cherché à accélérer les builds de conteneurs en pinant une couche d’image de base contenant les certificats CA et en ne la mettant jamais à jour.
Leur logique était propre : les bundles CA évoluent lentement, et les mettre à jour « gaspille du temps de build ». L’équipe plateforme a même standardisé un chemin,
et les équipes applicatives devaient s’y fier.
Des mois plus tard, une politique proxy d’entreprise a été déployée. L’interception HTTPS sortante est devenue obligatoire pour certains sous-réseaux, et le proxy utilisait une nouvelle racine.
Les hôtes ont été mis à jour avec la racine d’entreprise via la gestion de configuration. Les conteneurs ne l’ont pas été. Soudain, les conteneurs ne pouvaient plus appeler d’API externes,
ne pouvaient plus récupérer de dépendances, et certains ne pouvaient même plus envoyer de logs.
Le motif de panne était piquant : les services fonctionnaient sur les hôtes bare-metal mais échouaient dans Kubernetes. Les développeurs accusaient Kubernetes.
Les SRE accusaient « des changements réseau ». Ce n’était ni l’un ni l’autre. C’était un bundle CA figé au niveau de l’image.
La résolution a été pragmatique : les images de base ont commencé à reconstruire les bundles CA sur un calendrier, et les images applicatives ont cessé d’outrepasser les chemins de confiance.
L’« optimisation » économisait des secondes par build et coûtait des jours en temps d’incident. Un échange très coûteux.
3) La pratique ennuyeuse mais correcte qui a sauvé la mise : « Une pipeline de confiance unique, une source de vérité »
Une entreprise de services financiers avait l’approche opposée : ennui implacable. Toutes les CA d’entreprise vivaient dans un dépôt versionné,
distribuées via gestion de configuration, et installées dans les magasins OS selon une petite série de procédures standard.
Ils avaient aussi une vérification quotidienne simple : lancer une sonde de vérification TLS depuis des hôtes représentatifs (y compris des conteneurs) vers des points critiques.
Quand un CA intermédiaire a tourné sur un service interne, quelques hôtes ont commencé à échouer la vérification. La sonde l’a détecté rapidement.
L’astreint n’avait pas besoin de savoir-faire tribal. Le runbook disait : vérifier la longueur de la chaîne servie ; comparer l’émetteur ; confirmer l’état du magasin local ; corriger la chaîne serveur.
C’est ce qu’ils ont fait.
La correction était côté serveur : un fichier fullchain manquait d’un intermédiaire après un changement d’automatisation de renouvellement.
Parce qu’ils avaient une pipeline de confiance centralisée, personne n’a essayé de « réparer les clients » en important des intermédiaires comme racines.
Le rayon d’impact est resté réduit et l’incident a été court.
Ce n’était pas glamour. C’était correct. En production, « ennuyeux » est un compliment.
Erreurs courantes : symptôme → cause racine → correctif
1) curl échoue, le navigateur fonctionne
Symptôme : curl: (60) unable to get local issuer certificate ; les navigateurs chargent la page.
Cause racine : Serveur manquant la chaîne intermédiaire ; le navigateur a mis en cache l’intermédiaire ou l’a récupéré via AIA.
Correctif : Configurez le serveur/load balancer avec le fullchain (leaf + intermédiaire(s)). Validez avec openssl s_client -showcerts.
2) apt update échoue seulement sur certains hôtes
Symptôme : erreurs HTTPS apt sur un sous-ensemble de la flotte ; d’autres hôtes sont OK.
Cause racine : Dérive : certains hôtes ont manqué les mises à jour de CA, ont un état ca-certificates cassé, ou ont de mauvaises variables proxy.
Correctif : Vérifiez l’heure, réinstallez ca-certificates, exécutez update-ca-certificates, et comparez les variables/config proxy entre hôtes.
3) « certificate signed by unknown authority » seulement dans les conteneurs
Symptôme : curl fonctionne sur l’hôte ; curl échoue dans le conteneur ; pulls Docker échouent dans le cluster.
Cause racine : Image conteneur avec bundle CA obsolète ou utilisant un magasin de confiance différent de l’hôte.
Correctif : Assurez-vous que le bundle CA est mis à jour dans l’image ; évitez de piner la couche CA indéfiniment ; installez la racine d’entreprise pendant la build ou montez la confiance OS si approprié.
4) L’application Java échoue, curl réussit
Symptôme : Logs JVM affichant PKIX path building failed ; curl vers le même endpoint réussit.
Cause racine : Le magasin de confiance Java manque la racine d’entreprise ou n’utilise pas le magasin OS.
Correctif : Importez la CA d’entreprise dans le cacerts Java ou configurez la JVM pour utiliser le bundle OS.
5) « self-signed certificate in certificate chain » après un déploiement de proxy
Symptôme : Échecs soudains et larges ; l’émetteur ressemble à une CA d’entreprise ; la chaîne inclut « self-signed ».
Cause racine : Interception TLS avec une racine d’entreprise non approuvée sur les clients (ou mauvaise racine distribuée).
Correctif : Installez la bonne CA racine d’entreprise dans la confiance OS (et dans les magasins applicatifs). Confirmez que l’émetteur correspond à la racine attendue.
6) La vérification échoue après avoir « nettoyé des fichiers de certs »
Symptôme : update-ca-certificates affiche des erreurs ; bundle manquant ; outils échouent partout.
Cause racine : Quelqu’un a édité des fichiers générés dans /etc/ssl/certs ou a supprimé des liens hachés.
Correctif : Réinstallez ca-certificates, relancez update-ca-certificates, et cessez de gérer les chemins générés avec des scripts ad-hoc.
7) Un seul domaine échoue, tout le reste marche
Symptôme : Un service interne retourne une erreur ; les autres sont OK.
Cause racine : Ce service sert la mauvaise chaîne, le mauvais certificat, ou a un mapping SNI incorrect sur le LB.
Correctif : Utilisez openssl s_client -servername pour confirmer le certificat correct ; corrigez la configuration serveur.
8) Échecs sporadiques qui « se résolvent seuls »
Symptôme : Le même client réussit parfois et échoue parfois, sans changement de config.
Cause racine : Backends multiples derrière un VIP ; certains servent la bonne chaîne, d’autres non. Ou multiples proxies avec politiques différentes.
Correctif : Touchez chaque backend directement ; comparez les chaînes servies ; standardisez la config TLS sur les membres du pool.
Checklists / plan étape par étape
Plan étape par étape pour un hôte Ubuntu 24.04 en échec
-
Confirmer l’heure et le réseau de base (
timedatectl, résolution DNS, route/variables proxy). Corriger l’heure en premier. -
Reproduire avec curl en utilisant
-Ivet capturer l’erreur exacte. Si c’est une non-correspondance de nom d’hôte, arrêtez-vous et corrigez le endpoint/SNI. -
Exécuter l’inspection de chaîne OpenSSL avec
-showcerts -verify_return_error -servername. Déterminez si des intermédiaires manquent. - Si des intermédiaires manquent, corrigez le serveur/LB pour servir le fullchain. Retestez depuis le même hôte.
-
Si l’émetteur est corporatif/proxy, installez la CA racine d’entreprise dans
/usr/local/share/ca-certificateset exécutezupdate-ca-certificates. - Si une seule appli échoue, identifiez son magasin de confiance (certifi Python, cacerts Java, bundle conteneur, chemin CA embarqué).
- Boucler : retirez tout flag temporaire insecure, documentez la méthode de distribution des CA, et ajoutez une sonde basique pour détecter les rotations futures.
Checklist pour corriger la chaîne côté serveur (à quoi ressemble le « propre »)
- Le certificat leaf correspond au nom d’hôte (SAN inclut le nom DNS).
- Le leaf est signé par une CA intermédiaire (pas auto-signé, sauf si une racine privée est volontairement utilisée).
- Le serveur présente leaf + intermédiaire(s) dans l’ordre correct.
- La CA racine n’est pas servie (généralement inutile et parfois déconseillée).
- La vérification réussit depuis un client propre utilisant le magasin de l’OS.
Checklist pour l’hygiène de confiance côté client (éviter les incidents répétés)
- Les racines d’entreprise sont distribuées via gestion de configuration, pas copiées à la main.
- Le magasin OS est mis à jour avec
update-ca-certificatesaprès les modifications. - Les conteneurs reconstruisent les bundles CA selon un calendrier ou pendant la build de façon fiable.
- Les équipes applicatives savent si elles doivent utiliser la confiance OS ou un magasin spécifique à l’appli.
- Des sondes valident quotidiennement les points critiques depuis des environnements représentatifs (hôte + conteneur + runner CI).
FAQ
1) Réinstaller ca-certificates est-ce toujours la solution ?
Non. Cela répare la génération de bundle locale et les paquets obsolètes, mais ne corrigera pas un serveur qui n’envoie pas les intermédiaires.
Utilisez openssl s_client -showcerts pour décider si le problème est la chaîne serveur ou la confiance client.
2) Dois-je ajouter le certificat intermédiaire au magasin de confiance client ?
En général non. Les intermédiaires ne sont pas des ancres de confiance ; ils font partie de la chaîne que le serveur doit envoyer.
Ajouter des intermédiaires aux magasins de confiance « marche », mais cela répand une mauvaise configuration serveur dans chaque client et conteneur que vous possédez.
3) Pourquoi ça marche sur mon laptop mais pas sur les serveurs ?
Intermédiaires en cache, magasins de confiance différents, proxies différents, ou comportement DNS/SNI différent.
Les serveurs sont souvent plus stricts et plus isolés, ce qui explique précisément pourquoi ils échouent en premier.
4) Où placer une CA racine d’entreprise sur Ubuntu 24.04 ?
Placez un certificat encodé PEM dans /usr/local/share/ca-certificates/ avec une extension .crt, puis exécutez sudo update-ca-certificates.
Vérifiez qu’il est inclus en testant des outils comme curl.
5) apt échoue avec des erreurs de certificat. Puis-je utiliser [trusted=yes] dans sources.list ?
Cela contourne les vérifications de signature pour ce dépôt, pas la vérification TLS d’une manière robuste, et c’est une régression de sécurité de toute façon.
Corrigez la confiance CA ou la chaîne serveur. N’envisagez les solutions non sécurisées que pour des scénarios de dernier recours et supprimez-les rapidement.
6) Mon application Python échoue mais curl système marche. Pourquoi ?
Beaucoup d’environnements Python utilisent le bundle certifi au lieu du magasin système.
Confirmez avec python3 -c "import certifi; print(certifi.where())" et décidez de pointer requests vers les CA système ou de mettre à jour le bundle.
7) Comment savoir si un proxy intercepte TLS ?
Inspectez l’émetteur d’un certificat en vous connectant à un site public connu.
Si l’émetteur est une CA interne, vous êtes intercepté. Ce n’est pas automatiquement malveillant ; c’est simplement une exigence de distribution de confiance.
8) Dois-je redémarrer les services après la mise à jour des CA ?
Souvent oui pour les processus de longue durée. Beaucoup de programmes lisent les bundles CA au démarrage et les gardent en mémoire.
Pour les daemons système et serveurs applicatifs, planifiez un redémarrage ou un déploiement progressif après les mises à jour de CA.
9) Quelle est la différence entre « unable to get local issuer certificate » et « self-signed certificate » ?
« Unable to get local issuer » signifie généralement intermédiaire manquant ou racine de confiance absente.
« Self-signed » signifie souvent que la chaîne inclut un certificat qui n’est pas approuvé comme racine, ou que vous êtes face à un certificat proxy/mitm sans la racine de confiance.
10) Comment prévenir cette classe d’incidents ?
Corrigez correctement les chaînes serveur, centralisez la distribution des CA, évitez les bundles CA figés dans les images, et ajoutez une sonde TLS quotidienne pour les endpoints critiques.
Le secret est la cohérence, pas les héros.
Conclusion : étapes suivantes qui tiennent vraiment
Ubuntu 24.04 n’est pas difficile quand il dit « cert verify failed ». Il a juste raison.
La correction durable la plus rapide est presque toujours l’une des deux choses : servir la chaîne intermédiaire correcte côté serveur, ou installer la bonne CA racine côté client.
Tout le reste est un détour qui se transforme en politique, et la politique finit par faire souffrir.
Étapes suivantes qui rapportent :
- Exécutez la fiche de diagnostic rapide sur un hôte en échec et capturez la sortie de la chaîne OpenSSL.
- Corrigez le fullchain côté serveur partout où vous contrôlez le endpoint ; traitez cela comme la remédiation prioritaire.
- Standardisez l’installation des CA d’entreprise via
/usr/local/share/ca-certificates+update-ca-certificates. - Auditez les magasins de confiance spécifiques aux applications (Java, certifi Python, conteneurs) et choisissez une approche standard.
- Ajoutez une sonde simple qui vérifie TLS depuis des environnements représentatifs, pour trouver la prochaine rupture avant vos utilisateurs.
Faites la chaîne correctement une fois. Le vous du futur sera un peu moins fatigué, ce qui est la chose la plus proche d’un défilé de victoire pour les opérations.