SSD Nodes Learn 🎉 VPS dès $5.50/mois
Guides Matt ConnorPar Matt Connor

Ajouter une CA au magasin de confiance Ubuntu

Créez une CA privée avec openssl, signez un certificat feuille, puis installez la racine dans /usr/local/share/ca-certificates pour fiabiliser HTTPS interne.

Ajouter votre propre CA au magasin de certificats de confiance d’Ubuntu

Pour ajouter votre propre CA au magasin de certificats de confiance d’Ubuntu, copiez le certificat racine dans /usr/local/share/ca-certificates/, avec un nom qui se termine par .crt, puis exécutez sudo update-ca-certificates. Une CA (autorité de certification) est une paire de clés dont le certificat est autorisé à signer d’autres certificats. Une fois que la machine fait confiance à votre racine, elle accepte tous les certificats signés par cette racine. Les connexions HTTPS entre vos propres services ne présentent alors plus d’échec de vérification.

Ce guide construit toute la chaîne hors ligne avec openssl. Vous créez une clé racine et un certificat racine, vous émettez un certificat feuille pour un serveur, puis vous installez la racine et observez la réponse de la même commande de vérification changer. Cet ordre est important : effectuer la vérification avant et après l’installation permet de voir que l’installation a modifié le résultat.

Ubuntu 24.04 fournit OpenSSL 3 et le paquet ca-certificates dans une image par défaut. Vous n’avez donc rien à installer au préalable (vérifié en août 2026).

Quand devez-vous utiliser votre propre CA ?

Une CA publique comme Let's Encrypt a besoin d'un nom dans le DNS public et d'un serveur qu'elle peut joindre. Les noms internes ne conviennent pas. Une base de données sur un réseau privé ou un panneau d'administration lié à un tunnel ne peut pas obtenir de certificat public. Ces services ne doivent pas non plus être exposés sur Internet uniquement pour en obtenir un.

Un certificat autosigné sur Ubuntu ne concerne exactement qu'un seul hôte. Chaque client doit faire confiance à ce certificat, et le prochain hôte demande de recommencer le même travail. Une CA privée déplace cette décision d'un niveau. Les clients font confiance à la racine une seule fois, puis tous les certificats signés par cette racine sont approuvés, y compris ceux d'hôtes qui n'existent pas encore.

Le coût est réel. La clé de la racine peut signer tout ce que les contraintes autorisent. Toute personne qui peut lire ca.key peut donc émettre des certificats que vos machines accepteront. Protégez-la comme vous protégez une clé privée dans la gestion des clés SSH. Si un service possède un nom DNS public, ignorez tout cela et utilisez une CA publique : Certbot avec nginx et Let's Encrypt demande moins de travail et n'exige aucune installation côté client.

Créer la clé de l’AC et le certificat racine

Travaillez dans un répertoire que seul votre utilisateur peut ouvrir. La clé racine ne doit jamais en sortir.

install -d -m 700 ~/ca
cd ~/ca
openssl genrsa -aes256 -out ca.key 4096
chmod 600 ca.key

-aes256 chiffre la clé avec une phrase secrète de votre choix, et chaque commande ultérieure qui signe avec cette clé vous la demande. Laissez -aes256 désactivé et la clé reste en clair sur le disque. Une sauvegarde ou un second compte administrateur suffit alors pour permettre à quelqu’un d’émettre des certificats approuvés par vos machines.

Créez maintenant le certificat racine, que la clé de l’AC signe elle-même.

openssl req -x509 -new -key ca.key -sha256 -days 3650 \
  -subj "/O=Example Internal/CN=Example Internal Root CA" \
  -addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
  -addext "keyUsage=critical,keyCertSign,cRLSign" \
  -addext "subjectKeyIdentifier=hash" \
  -addext "nameConstraints=critical,permitted;DNS:internal.example" \
  -out ca.crt

Remplacez internal.example par le suffixe de nom que vous utilisez réellement, puis lisez la section suivante avant de conserver cette dernière extension.

Chaque extension a une fonction précise.

  • basicConstraints avec CA:TRUE transforme cet objet en certificat d’AC. Sans cela, un client rejette tous les certificats signés par cette clé, même si la signature elle-même est correcte.
  • pathlen:0 indique que l’AC peut signer des certificats finaux, mais aucune autre AC subordonnée.
  • keyUsage limite l’utilisation de la clé à la signature de certificats et de listes de révocation. La même clé ne peut donc pas être utilisée par erreur comme clé de serveur TLS.
  • subjectKeyIdentifier donne à la racine un identifiant vers lequel les certificats finaux peuvent pointer. Le client peut ainsi trouver le bon émetteur dans un magasin qui en contient plusieurs centaines.
  • nameConstraints limite les noms pour lesquels cette AC est autorisée à émettre des certificats.

Relisez ce que vous avez créé au lieu de supposer que la commande a fait ce que vous vouliez.

openssl x509 -noout -subject -issuer -serial -dates -in ca.crt
openssl x509 -noout -text -in ca.crt

Subject et issuer affichent la même chaîne, car un certificat racine se signe lui-même. Le numéro de série et les deux dates proviennent du fichier que vous venez de créer. Relevez-les dans cette sortie plutôt que dans le guide de quelqu’un d’autre.

Limiter ce que votre AC est autorisée à signer

Une racine du magasin système est approuvée pour tous les noms sur Internet, sauf indication contraire. Cela représente une autorité importante concentrée dans un seul fichier sur un seul serveur. nameConstraints la réduit. Avec permitted;DNS:internal.example dans la racine, une chaîne issue de cette AC pour un nom situé en dehors de internal.example est rejetée, même si la signature est valide.

Testez ce comportement au lieu de lui faire confiance.

openssl req -new -newkey rsa:2048 -nodes -keyout /tmp/outside.key -out /tmp/outside.csr \
  -subj "/CN=www.example.com"
openssl x509 -req -in /tmp/outside.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 30 -sha256 \
  -extfile <(printf 'subjectAltName=DNS:www.example.com\n') -out /tmp/outside.crt
openssl verify -CAfile ca.crt /tmp/outside.crt
echo $?

Le certificat est émis, car votre AC signe tout ce que vous lui demandez de signer. C’est lors de la vérification que l’opération échoue : le code de sortie est différent de zéro et OpenSSL indique la contrainte rencontrée. C’est l’objectif de cette extension. Même avec une clé d’AC volée, il est impossible de produire un certificat fonctionnel pour un nom situé en dehors du sous-arbre. Supprimez les fichiers restants avec rm /tmp/outside.* lorsque vous avez terminé.

Voici quatre points à connaître avant d’appliquer une contrainte. Elle est marquée critical. Un client qui ne comprend pas l’extension doit donc rejeter la chaîne au lieu de l’ignorer. C’est le comportement le plus sûr, mais il peut surprendre une ancienne bibliothèque TLS. Un sous-arbre autorisé pour les noms DNS ne restreint pas les SAN de type adresse IP. En effet, un type de nom qui n’a pas de sous-arbre indiqué reste sans restriction. Ajoutez donc permitted;IP:10.0.0.0/255.255.0.0 dans la même extension si vos certificats contiennent des adresses IP. Le sous-arbre doit couvrir tous les noms que vous émettrez, y compris les noms d’hôte courts. Ainsi, un certificat pour le nom nu app échouerait avec l’exemple précédent. Enfin, la contrainte est intégrée à la racine. Si vous changez d’avis, vous devez donc créer un nouveau certificat racine et l’installer de nouveau sur chaque client.

Émettre un certificat leaf signé par votre CA

Un certificat leaf est celui qu’un serveur présente aux clients. Commencez par sa propre clé et une CSR (certificate signing request). Celle-ci contient la clé publique et le nom demandé. Elle est signée par la clé leaf afin de prouver que le demandeur détient la clé privée correspondante.

openssl req -new -newkey rsa:2048 -nodes \
  -keyout app.key -out app.csr \
  -subj "/CN=app.internal.example"
chmod 600 app.key

Les noms importants doivent figurer dans un fichier d’extension, et non dans la CSR. Les clients comparent le nom d’hôte à subjectAltName (SAN) et ignorent complètement le common name. Un certificat avec un CN mais sans SAN échoue donc à la vérification du nom d’hôte sur tous les clients actuels, quelle que soit la valeur du CN.

basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:app.internal.example, DNS:api.internal.example
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always

Enregistrez ce contenu dans app.ext, puis signez la demande avec la CA.

openssl x509 -req -in app.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -days 397 -sha256 -extfile app.ext -out app.crt

-CAcreateserial écrit ca.srl à côté de la CA. Ce fichier contient le prochain numéro de série, afin qu’aucun certificat émis par cette CA ne partage le même numéro. Conservez ce fichier dans le répertoire de la CA. -days 397 est un choix, et non une limite de l’outil. Les durées de validité courtes sont encore plus importantes ici qu’avec une CA publique, car une CA privée ne dispose d’aucune infrastructure de révocation : il n’y a ni CRL ni répondeur OCSP, sauf si vous en construisez un. Une clé leaf divulguée reste donc utilisable jusqu’à l’expiration du certificat.

Vérifiez le résultat avant de modifier le trust store.

openssl x509 -noout -subject -issuer -serial -dates -in app.crt
openssl x509 -noout -ext subjectAltName -in app.crt

La ligne issuer indique maintenant la CA, et non plus le certificat leaf lui-même. La ligne SAN liste les noms pour lesquels ce certificat est valide. Le client compare le nom uniquement à cette liste.

Vérifiez avec un fichier -CAfile explicite avant toute installation

openssl verify -CAfile ca.crt app.crt
echo $?

Cette commande pose une question précise : est-ce que app.crt forme une chaîne valide jusqu’au certificat indiqué dans ca.crt ? Elle ne dit rien sur les autorités approuvées par cette machine, car vous avez fourni la racine à OpenSSL sur la ligne de commande. Un échec indique un problème au niveau des certificats eux-mêmes. Corrigez-le avant de continuer.

Interrogez maintenant la machine.

openssl verify app.crt
echo $?

Sans -CAfile, OpenSSL utilise le répertoire de certificats intégré par défaut. openssl version -d affiche le répertoire de base utilisé par votre build. Sur Ubuntu, le répertoire certs qui s’y trouve pointe vers /etc/ssl/certs. Votre certificat racine ne s’y trouve pas encore. La vérification échoue donc : la chaîne atteint une autorité émettrice absente du magasin, et OpenSSL n’a plus d’autre emplacement à consulter. Notez le code de sortie. C’est lui qui changera dans deux étapes.

Un vrai client constitue un meilleur test que openssl verify, car il vérifie aussi le nom d’hôte. Servez le certificat et récupérez-le.

openssl s_server -accept 8443 -cert app.crt -key app.key -www &
curl --resolve app.internal.example:8443:127.0.0.1 https://app.internal.example:8443/

--resolve envoie la connexion vers 127.0.0.1 tout en demandant app.internal.example. Le SAN correspond donc, et la seule question restante concerne la confiance. curl échoue et affiche la raison pour laquelle il n’a pas pu vérifier la chaîne. Ajoutez -v pour obtenir plus de détails. Laissez le serveur de test en cours d’exécution.

Installer le certificat racine dans /usr/local/share/ca-certificates

sudo cp ca.crt /usr/local/share/ca-certificates/example-internal-root.crt
sudo chmod 644 /usr/local/share/ca-certificates/example-internal-root.crt
sudo update-ca-certificates

Les points suivants déterminent si l’opération fonctionne :

  • Le nom de fichier doit se terminer par .crt. La page de manuel update-ca-certificates indique que les certificats portant l’extension .crt et situés sous /usr/local/share/ca-certificates sont inclus et considérés comme fiables implicitement. Un fichier nommé root.pem ou root.cer est ignoré sans message.
  • Le contenu doit être au format PEM, c’est-à-dire un bloc encodé en base64 encadré par les lignes BEGIN CERTIFICATE et END CERTIFICATE. Renommer un fichier DER en .crt ne le convertit pas : il reste binaire et n’est pas lu. Convertissez-le avec openssl x509 -inform DER -in ca.der -out ca.crt.
  • Seul le certificat racine doit être placé ici. La clé privée de l’autorité de certification et le certificat feuille n’ont pas leur place dans un trust store.

update-ca-certificates affiche le nombre de certificats ajoutés et supprimés. Si aucun certificat n’a été ajouté, l’extension ou le format du fichier en est la cause.

Confirmez la modification du point de vue du système, plutôt qu’en vous fiant à ce message.

ls -l /etc/ssl/certs/$(openssl x509 -noout -subject_hash -in /usr/local/share/ca-certificates/example-internal-root.crt).0
grep -c 'BEGIN CERTIFICATE' /etc/ssl/certs/ca-certificates.crt

La première commande construit un nom de fichier à partir du subject hash de votre certificat et l’affiche. update-ca-certificates a créé ce lien symbolique, qui pointe vers le fichier installé. La deuxième commande compte les certificats contenus dans le bundle à fichier unique. Exécutez-la également avant l’installation pour observer l’augmentation d’une unité.

Lorsque vous copiez ce certificat racine sur d’autres machines, vérifiez que la copie est intacte avant de l’installer. Une erreur sur un certificat racine peut avoir de graves conséquences sur le système. Traitez-le comme n’importe quel téléchargement que vous vérifieriez avec une somme de contrôle avant de l’utiliser.

Vérifiez à nouveau avec le magasin de certificats du système

openssl verify app.crt
echo $?
curl --resolve app.internal.example:8443:127.0.0.1 https://app.internal.example:8443/

Les mêmes commandes et les mêmes fichiers de certificats produisent une réponse différente. Rien n’a changé concernant app.crt, et le serveur est celui que vous avez démarré précédemment. La seule différence est que la racine se trouve maintenant dans le magasin consulté par ces clients, ce qui permet de compléter la chaîne. C’est le mécanisme à retenir : la vérification consiste à rechercher un émetteur auquel le client fait déjà confiance, et installer une autorité de certification permet d’ajouter cet émetteur à l’emplacement où le client effectue sa recherche.

Arrêtez le serveur de test avec kill %1.

Pourquoi /etc/ssl/certs n’est pas l’emplacement où placer votre fichier

/etc/ssl/certs est généré automatiquement. update-ca-certificates le remplit avec des liens symboliques vers les vrais fichiers de certificats et écrit le bundle concaténé /etc/ssl/certs/ca-certificates.crt à côté de ces fichiers.

Un certificat que vous copiez manuellement dans ce répertoire n’est trouvé par aucun composant. La recherche dans les répertoires d’OpenSSL ouvre uniquement les fichiers dont le nom correspond au hash du sujet d’un certificat. Un fichier nommé myca.crt est donc invisible pour OpenSSL. Sous Ubuntu, curl lit le fichier bundle. Celui-ci est reconstruit à partir des sources enregistrées. Votre copie n’est donc pas prise en compte non plus. Exécutez update-ca-certificates --fresh : les liens symboliques du répertoire sont supprimés puis recréés. Tout lien créé manuellement est donc supprimé.

L’autre partie de cette séparation est /usr/share/ca-certificates. Elle appartient au paquet ca-certificates et est répertoriée dans /etc/ca-certificates.conf. Les mises à jour du paquet la réécrivent. /usr/local/share/ca-certificates est le répertoire réservé à l’administrateur local. Votre autorité de certification survit donc à chaque mise à niveau du paquet qui gère le reste.

Quels programmes ignorent le magasin de certificats du système

L’installation de la racine corrige le problème pour tous les programmes qui utilisent OpenSSL ou lisent /etc/ssl/certs. Cela concerne curl, wget, git, le module standard ssl de Python et les programmes Go, qui lisent les fichiers système sous Linux. Les runtimes qui embarquent leur propre liste de certificats ne sont pas concernés. C’est la principale source de confusion après une installation réussie.

  • Node.js utilise une liste intégrée au binaire. Indiquez-lui votre certificat racine avec NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/example-internal-root.crt, défini dans l’environnement avant le démarrage du processus, car Node ne lit cette variable qu’une seule fois au démarrage. Les versions actuelles de Node proposent également une option pour lire le magasin système ; exécutez node --help | grep -i system-ca pour vérifier si votre version la prend en charge.
  • La bibliothèque requests de Python utilise le bundle certifi. Définissez REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt pour ce processus ou transmettez verify="/etc/ssl/certs/ca-certificates.crt" à l’appel. pip nécessite --cert pour la même raison.
  • Java lit un keystore. Sous Ubuntu, le paquet ca-certificates-java installe un hook dans /etc/ca-certificates/update.d/. Lorsque ce paquet est présent, update-ca-certificates actualise donc aussi le keystore Java. Sinon, importez la racine avec keytool -importcert.
  • Firefox conserve son propre magasin et ne consulte jamais /etc/ssl/certs. Importez le certificat dans ses paramètres de certificats. Sous Linux, Chromium lit une base NSS propre à chaque utilisateur. Modifiez-la avec certutil, fourni par le paquet libnss3-tools.
  • Les conteneurs ont leur propre système de fichiers. Le magasin de l’hôte n’a donc aucun effet à l’intérieur du conteneur. Copiez la racine dans l’image, puis exécutez update-ca-certificates pendant le build. Tenez-en compte si vos services s’exécutent avec Docker Compose sur un VPS.

Lorsqu’un programme refuse encore le certificat après une installation correcte, déterminez quels fichiers il ouvre avant de modifier quoi que ce soit d’autre. strace -f -e trace=openat <command> 2>&1 | grep -i cert est peu précis, mais répond à la question en une seule exécution.

Conserver une CA utilisable dans le temps

Réémettre un certificat leaf consiste à reprendre l’étape de génération du CSR, puis l’étape de signature, avec le même fichier app.ext. Les clients n’ont rien à faire, car la root qu’ils approuvent n’a pas changé. Conservez ca.srl et tous les fichiers .ext dans le répertoire de la CA afin que la prochaine émission reprenne une commande qui a déjà fonctionné, au lieu de devoir la reconstituer de mémoire.

Sauvegardez ca.key et ca.crt à un autre emplacement, hors de la machine, en les conservant chiffrés. Si vous perdez la clé, vous ne pouvez plus rien émettre : vous devez créer une seconde CA et installer sa root partout où se trouvait la première. Tenez une liste écrite de chaque machine et de chaque magasin de certificats applicatif ayant reçu la root, car cette liste est indispensable pour effectuer une rotation ou la supprimer.

Lorsque la root elle-même approche de sa date d’expiration, générez la remplaçante suffisamment tôt et installez les deux roots côte à côte. La présence de deux roots dans le magasin ne pose pas de problème : un client accepte l’une ou l’autre. Réémettez les certificats leaf avec la nouvelle root, puis supprimez l’ancienne lorsque plus rien n’en dépend.

Supprimer une CA du magasin de confiance

sudo rm /usr/local/share/ca-certificates/example-internal-root.crt
sudo update-ca-certificates --fresh

--fresh supprime les liens symboliques dans /etc/ssl/certs et les recrée à partir des sources encore présentes. La racine supprimée disparaît donc à la fois du répertoire et du bundle. Vérifiez sa suppression de la même manière que vous avez vérifié son installation.

openssl verify app.crt
echo $?
grep -c 'BEGIN CERTIFICATE' /etc/ssl/certs/ca-certificates.crt
ls -l /etc/ssl/certs/$(openssl x509 -noout -subject_hash -in ~/ca/ca.crt).0

La vérification échoue de nouveau, le nombre de certificats revient à sa valeur initiale et le lien symbolique de hachage a disparu.

Cette commande modifie uniquement le magasin système. Annulez manuellement l’installation dans chacun des autres emplacements : videz NODE_EXTRA_CA_CERTS, supprimez l’alias de chaque keystore Java concerné, retirez la racine de chaque profil de navigateur et recréez toute image de conteneur qui l’intègre. La suppression de la racine n’invalide pas non plus les certificats qu’elle a signés. Ils restent valides sur toutes les machines qui lui accordent encore leur confiance. C’est pourquoi une CA privée doit disposer d’une liste écrite des emplacements où la racine a été déployée. Une CA que vous ne pouvez pas retirer complètement constitue une faille permanente. Testez donc sa suppression sur une machine le jour de sa mise en place, tant que la liste reste courte.

FAQ

Où dois-je placer un certificat CA sur Ubuntu ?

Placez-le dans /usr/local/share/ca-certificates/, avec un nom de fichier qui se termine par .crt et un contenu PEM, puis exécutez sudo update-ca-certificates. Ce répertoire est réservé à l’administrateur local ; les mises à niveau des paquets n’y touchent donc pas. /usr/share/ca-certificates appartient au paquet ca-certificates et /etc/ssl/certs est généré à partir des deux. Un fichier placé dans l’un de ces répertoires est donc écrasé ou ignoré.

Pourquoi curl rejette-t-il encore le certificat après update-ca-certificates ?

Examinez les causes dans l’ordre. Le fichier peut ne pas se terminer par .crt ou être au format DER plutôt que PEM. Dans ce cas, update-ca-certificates l’a ignoré et n’a rien ajouté. Le certificat peut ne contenir aucun subjectAltName correspondant au nom d’hôte. Il s’agit alors d’un échec lié au nom d’hôte, et non d’un échec de confiance ; vérifiez avec openssl x509 -noout -ext subjectAltName -in app.crt. Le serveur peut envoyer uniquement le certificat final alors qu’un certificat intermédiaire est également nécessaire. curl peut utiliser un bundle différent défini par CURL_CA_BUNDLE ou --cacert. Enfin, un service exécuté depuis longtemps doit être redémarré, car la plupart des programmes lisent le trust store une seule fois au démarrage.

Le trust store système couvre-t-il Firefox, Chrome, Node et Java ?

Non. curl, wget, git, le module standard ssl de Python et les programmes Go lisent les fichiers système. Ils fonctionnent donc dès que update-ca-certificates est exécuté. Firefox conserve son propre store. Chromium sous Linux utilise une base NSS par utilisateur, modifiée avec certutil du paquet libnss3-tools. Node.js a besoin de NODE_EXTRA_CA_CERTS, qui doit pointer vers votre fichier racine. Java lit un keystore, que update-ca-certificates actualise uniquement lorsque le paquet ca-certificates-java est installé. Le requests de Python utilise certifi et nécessite REQUESTS_CA_BUNDLE.

Comment supprimer une CA du trust store d’Ubuntu ?

Supprimez le fichier de /usr/local/share/ca-certificates/, puis exécutez sudo update-ca-certificates --fresh. L’option --fresh supprime les liens symboliques de /etc/ssl/certs et les recrée. Le certificat est ainsi supprimé à la fois des liens symboliques basés sur le hash et du bundle ca-certificates.crt. Vérifiez le résultat en exécutant openssl verify avec un certificat signé par cette CA, puis en consultant le code de sortie. Répétez ensuite la suppression dans tous les autres stores auxquels vous l’avez ajoutée, car cette commande ne les modifie pas.

Puis-je utiliser une CA privée à la place de Let’s Encrypt pour un site public ?

Non. Le navigateur d’un visiteur ne connaît pas votre certificat racine. Il affiche donc un avertissement sur toute la page, et vous ne pouvez pas installer votre certificat racine sur des machines que vous ne contrôlez pas. Une CA privée sert aux noms que seules vos propres machines résolvent et aux clients que vous administrez. Pour tout site visité par des utilisateurs externes, obtenez le certificat auprès d’une CA publique.