RAND_bytes() failed est une affirmation sur une primitive locale, non sur le compte, la clé prépartagée ou le port distant. Deux pannes très différentes produisent cette même ligne, et elles laissent des traces différentes. L’une est un moteur cryptographique qui refuse d’émettre des octets ; l’autre est un processus qui n’atteint pas la source d’entropie pour laquelle son code a été compilé. Les distinguer demande une lecture de la file d’erreurs et un regard sur la vue du système de fichiers du processus cloîtré, et ce contrôle doit précéder toute création sous /dev.

Ce que la valeur de retour distingue

Le contrat documenté distingue trois issues, et non deux : 1 pour le succès, -1 lorsque la méthode RAND chargée ne prend pas en charge la demande, et 0 pour les autres échecs, l’explication restant dans la file d’erreurs. La référence de RAND_bytes ajoute un point facile à négliger : le générateur par défaut s’initialise à partir du système d’exploitation sur les plateformes prises en charge, et lorsque cet amorçage échoue, il reste dans un état d’erreur au lieu de rendre des octets prévisibles.

Un seul de ces nombres décrit l’environnement. Un -1 relève de la compilation, du fournisseur ou d’une fonctionnalité absente, car le code demandait quelque chose que l’implémentation active n’offre pas. Un 0 accompagné d’une plainte d’amorçage relève de l’environnement, car le générateur n’a pas pu obtenir d’entropie du tout. Le nombre seul ne dit jamais lequel des deux, et le nom de la fonction non plus.

Quand un nœud de périphérique masqué est la vraie cause

Un service cloisonné voit une arborescence différente de celle du shell dans lequel vous tapez. Les prisons chroot, les images de conteneurs et les fichiers d’unité durcis présentent couramment un /dev qui contient moins de nœuds que celui de l’hôte. Si l’implémentation défaillante ouvre /dev/urandom par son chemin, cette différence suffit à casser le démarrage alors que l’hôte lui-même semble parfaitement sain. Un périphérique présent hors de la prison ne prouve rien sur ce que le processus emprisonné a le droit d’ouvrir.

Toute interface aléatoire n’a pas besoin d’un chemin, cependant. L’appel système getrandom de Linux n’accepte ni nom de fichier ni descripteur de fichier, et sa page de manuel note que cette propriété est utile précisément là où un chroot masque les chemins des périphériques.

Ainsi, l’explication du nœud manquant est une hypothèse sur une branche du code, non une règle générale sur les nombres aléatoires. Elle tient lorsque les preuves nomment un chemin, et elle relève de la conjecture lorsque les preuves nomment autre chose.

Lire la file d’erreurs, puis la vue du processus

Le moyen le plus rapide de trancher est de lire ce que la bibliothèque a déjà enregistré, puis de regarder directement la vue emprisonnée. Commencez par la compilation OpenSSL que le service a réellement chargée, car les piles de fournisseurs diffèrent entre versions majeures et entre distributions. Demandez ensuite à systemd quel processus tourne et quelles restrictions lui sont appliquées. Ce n’est qu’une fois ces deux faits établis qu’il vaut la peine de lister les nœuds que ce processus peut voir.

openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random

Exécutez ces lectures sur le même processus, non sur le shell qui se trouve ouvert. Comparer le /dev de l’hôte avec la vue d’un processus sans rapport, c’est ainsi qu’on répare deux fois la mauvaise dépendance.

N’ajoutez la dépendance qu’après avoir pu la nommer

Lorsque les preuves nomment bien un chemin, la réparation est modeste : rendez ce seul chemin disponible dans la prison et ne touchez à rien d’autre. Un montage bind du nœud unique suffit généralement, et mknod avec les numéros majeur et mineur standard du nœud produit le même résultat sur les installations où le montage n’est pas possible. Élargir le bac à sable, accorder l’accès à tous les périphériques de caractères ou désactiver PrivateDevices échange un correctif ciblé contre une régression de sécurité permanente.

Un démon d’entropie ne remplace pas cette réparation. Des paquets comme haveged changent la manière dont le pool du noyau est alimenté ; ils ne peuvent pas créer un chemin que le processus emprisonné est autorisé à ouvrir. En installer un peut embellir une courbe de santé alors que l’appel open échoue toujours. Gardez les deux problèmes séparés, sinon la prochaine panne sera de nouveau attribuée à la mauvaise couche.

Vérifier séparément le générateur et le tunnel

Un redémarrage est le seul test qui réutilise la même configuration, le même fichier d’unité et le même cloisonnement que ceux ayant produit la panne. Exécutez-le, puis lisez les entrées les plus récentes du journal plutôt qu’un échantillon d’un démarrage antérieur.

sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'

Cherchez deux choses distinctes dans cette sortie : le message sur la source aléatoire qui disparaît, et le tunnel qui atteint son jalon de démarrage habituel. Un générateur qui remarche supprime un échec local et ne dit rien sur l’identité du serveur, les identifiants ou le routage. Testez cela avec la même configuration client qui échouait auparavant, afin que le résultat soit comparable et non simplement meilleur.

Articles similaires