Message d’erreur
curl: (60) SSL certificate problem: unable to get local issuer certificate
Également affiché sous la forme
- curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
- SSL certificate problem: unable to get local issuer certificate
Les builds de curl reposant sur OpenSSL (Linux, Homebrew sous macOS, Git for Windows) affichent ce texte ; les versions plus récentes (8.22.0 dans notre test, alors que 8.14.1 utilisait encore le texte ci-dessus) le formulent « SSL certificate OpenSSL verify result: unable to get local issuer certificate (20) », en ajoutant le code de vérification d’OpenSSL. curl compilé avec Schannel sous Windows signale la même situation par « schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) », et la libcurl reposant sur GnuTLS (utilisée par git sous Debian et Ubuntu) par « server verification failed: certificate signer not trusted ». Les outils construits sur libcurl, comme PHP et git, affichent la partie qui suit « (60) » avec leur propre préfixe.
curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)
Ce que cela signifie
curl a reçu les certificats du serveur, mais n’a pas trouvé, dans son propre fichier d’AC, le certificat qui a émis le dernier de la chaîne. Le certificat est peut-être parfaitement valide ; curl ne parvient simplement pas à le rattacher à une racine qu’il approuve, et refuse donc la connexion (code de sortie 60). L’élément manquant est soit un certificat intermédiaire que le serveur a oublié d’envoyer, soit une AC racine absente de votre machine.
Pourquoi cela se produit
Le serveur n’envoie que son propre certificat
fréquenteLes AC publiques signent les certificats de serveur avec un certificat intermédiaire, et le serveur doit envoyer ce certificat intermédiaire avec son certificat feuille. Un serveur configuré avec cert.pem au lieu de fullchain.pem fonctionne dans les navigateurs de bureau, qui mettent en cache les certificats intermédiaires et récupèrent ceux qui manquent, mais curl ne fait ni l’un ni l’autre et s’arrête au certificat feuille.
Le certificat provient d’une AC privée ou d’entreprise
fréquenteLes services internes, les environnements de préproduction et les ingress Kubernetes utilisent souvent des certificats émis par une AC d’entreprise ou faite maison. Cette racine ne figure pas dans le fichier d’AC public qu’utilise curl (/etc/ssl/certs/ca-certificates.crt sous Debian et Ubuntu) : rien de ce qu’elle a émis ne peut donc être vérifié tant que la racine n’est pas installée.
Un proxy d’inspection TLS re-signe le trafic
occasionnelleLes proxys d’entreprise et les solutions de sécurité des endpoints (Zscaler, Netskope, Palo Alto et autres) remplacent le certificat de chaque site par un certificat émis par leur propre AC. Le navigateur fait confiance à cette AC via le magasin de certificats du système d’exploitation, tandis que curl, les conteneurs et WSL utilisent un fichier d’AC distinct qui ne la contient pas : chaque appel HTTPS échoue donc de la même manière.
La machine n’a aucun fichier d’AC utilisable
occasionnelleLes images de conteneur slim et distroless sont livrées sans le paquet ca-certificates, et les anciens systèmes embarquent des fichiers d’AC antérieurs aux racines actuelles. Avec un fichier d’AC vide ou obsolète, même les certificats de sites publics bien connus échouent avec ce message.
L’AC a été ajoutée à un magasin que ce curl ne lit pas
rareChaque build de curl lit un fichier d’AC bien précis : le curl de Homebrew, un environnement conda et Git for Windows fournissent chacun le leur, et il existe sous Windows des builds Schannel comme des builds OpenSSL. Une AC ajoutée au magasin de certificats Windows ou au trousseau macOS n’atteint que les builds qui lisent ce magasin.
Comment corriger l’erreur
- 1.
Voir ce que le serveur envoie réellement
Listez les certificats du handshake. Si un seul apparaît (profondeur 0) et que son émetteur est une AC intermédiaire, la configuration du serveur est incomplète et doit être corrigée sur le serveur. Si la chaîne se termine par une racine d’entreprise ou faite maison, c’est au client qu’il manque cette racine.
bash # Which certificates does the server send, and who issued the last one? openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' # 0 s:CN=api.example.com # i:C=US, O=Example Trust Services, CN=Example TLS Issuing CA <- leaf only: intermediate missing - 2.
Corriger le serveur : servir la chaîne complète
Configurez le serveur web avec un fichier qui contient le certificat feuille suivi de tous les certificats intermédiaires. Cela corrige l’erreur pour tous les clients à la fois, y compris les applications mobiles et les clients d’API que vous ne contrôlez pas.
bash # Leaf first, then each intermediate in order; the root itself is optional cat api.example.com.crt intermediate.crt > fullchain.pem # nginx: ssl_certificate /etc/nginx/tls/fullchain.pem; # Apache: SSLCertificateFile /etc/apache2/tls/fullchain.pem # certbot: use live/<name>/fullchain.pem, never cert.pem - 3.
Installer une AC racine privée dans le magasin du système
Lorsque la chaîne se termine légitimement par une racine d’entreprise ou interne, ajoutez cette racine au fichier d’AC du système d’exploitation. Procurez-vous la racine auprès de votre équipe informatique ou plateforme, ou auprès de l’AC elle-même ; jamais à partir du certificat présenté par la connexion qui échoue, puisque c’est précisément ce à quoi vous ne pouvez pas encore faire confiance.
bash # Debian, Ubuntu, Alpine (the file must end in .crt) sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates # RHEL, Fedora, Amazon Linux sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust - 4.
Indiquer à curl un fichier d’AC pour une commande ou un shell
--cacert étend la confiance le temps d’un seul appel, sans toucher au système ; CURL_CA_BUNDLE définit le fichier d’AC de tous les appels curl de l’environnement. Le fichier peut contenir plusieurs certificats PEM.
bash curl --cacert corp-root-ca.pem https://api.example.com/ # or for every curl command in this shell (a file may hold several PEM certificates) export CURL_CA_BUNDLE=/opt/certs/corp-and-public-roots.pem - 5.
Installer le fichier d’AC dans les conteneurs minimaux
Si même les sites publics échouent dans un conteneur, l’image n’a pas de fichier d’AC. Installez ca-certificates dans l’image (ou copiez /etc/ssl/certs/ca-certificates.crt depuis une étape de build) plutôt que de désactiver la vérification.
bash # Debian/Ubuntu-based images apt-get update && apt-get install -y --no-install-recommends ca-certificates # Alpine apk add --no-cache ca-certificates - 6.
Diagnostic temporaire : confirmer qu’il s’agit d’un problème de confiance
-k (--insecure) désactive la vérification des certificats : une réponse réussie prouve donc seulement que le chemin réseau fonctionne et que l’échec tient à la confiance. Ne le laissez jamais dans des scripts : avec -k, n’importe qui sur le chemin peut lire et modifier le trafic, y compris les identifiants et le code téléchargé.
bash # Diagnostic only: if this works, the problem is trust, not the network. curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com/
Erreurs associées
curl: (60) SSL certificate problem: self-signed certificate in certificate chaincurl (OpenSSL backend)curl: (60) SSL certificate problem: self-signed certificatecurl (OpenSSL backend)verify error:num=20:unable to get local issuer certificateOpenSSL CLI (openssl s_client / openssl verify)fatal: unable to access 'https://git.example.com/team/app.git/': SSL certificat…git over HTTPS with libcurl + OpenSSL (Git for Windows default, macOS Homebrew, Alpine, RHEL)x509: certificate signed by unknown authorityGo crypto/x509