- L’ISO d’installation minimale de NixOS a pu être reconstruite indépendamment de façon strictement identique bit à bit à la version distribuée par Hydra, montrant qu’il est possible de vérifier la correspondance entre les binaires publiés et le code source
- Cette vérification ne couvre pas seulement les paquets inclus dans l’ISO, mais aussi le processus de génération de l’ISO lui-même, ce qui confirme un périmètre plus large qu’une simple reproductibilité des paquets
- La reconstruction a commencé depuis l’appliance VirtualBox de NixOS 20.03, en utilisant la révision
63678e9f3d3adenixpkgs, avec--option substitute falsepour désactiver la dépendance au cache binaire - Si l’OVA de 2020 ou le
gittéléchargé contenait une porte dérobée sophistiquée, cela resterait malgré tout un vecteur d’attaque ; une vérification reposant sur un système entièrement bootstrapped reste donc à faire - La reconstruction de l’ISO minimale constitue une étape importante, mais la suppression des contournements temporaires, la reproductibilité d’un plus grand nombre de supports d’installation, une infrastructure de reconstructions indépendantes régulières et des outils de preuve de build restent les prochaines tâches
Reproductibilité vérifiée sur l’ISO minimale
- Le build ISO
nixos-minimalpublié par Hydra a été reconstruit indépendamment, avec un résultat strictement identique bit à bit - Le périmètre de la reproductibilité se divise en deux axes
- tous les paquets inclus dans l’ISO
- le processus de build de l’ISO lui-même
- Des paquets nécessaires au build de l’ISO mais non inclus dans l’ISO ont également été compilés, sans dépendre de binaires mis en cache
- Les builds reproductibles offrent une chaîne de confiance permettant de vérifier que les binaires distribués correspondent fidèlement au code source et n’ont pas été altérés dans un pipeline de build comme Hydra
Procédure de reconstruction et limites
- La reconstruction a été effectuée en partant d’une nouvelle appliance VirtualBox avec NixOS 20.03
- suffisamment de CPU et de mémoire ont été alloués, et le disque a été étendu à environ 65 Go
- après l’installation de
git,nixpkgsa été cloné puis la révision63678e9f3d3aa été checkoutée - avec
--option substitute false, les éléments nécessaires ont été compilés sur la machine locale au lieu d’être récupérés depuis le cache binaire
- La procédure inclut des mesures temporaires pour contourner des problèmes connus
- Des limites subsistent du point de vue de la confiance dans la supply chain
- si l’OVA de 2020 ou le
gittéléchargé contenait une porte dérobée sophistiquée, cela resterait un vecteur d’attaque - reconstruire depuis un système entièrement bootstrapped serait préférable, mais ce stade n’a pas encore été atteint
- les avancées associées se poursuivent dans le fil du projet nixpkgs supply-chain security
- si l’OVA de 2020 ou le
Différence entre l’annonce de 2021 et ce résultat
- En 2021, une annonce indiquait que l’ISO minimale était reproductible à 100 %, mais à l’époque seuls les paquets nécessaires au build de l’ISO avaient été reproduits individuellement, et des écarts subsistaient encore lors de la reconstruction de l’ISO elle-même
- la cause venait de problèmes restants liés au cache Hydra et à la manière de générer l’ISO
- ensuite, alors que ces problèmes étaient corrigés, des régressions sont apparues, comme un problème upstream dans Python 3.10, et ce n’est que cette semaine que toute la chaîne a de nouveau pu être vérifiée
- Les prochaines étapes consistent à supprimer les contournements temporaires, reproduire davantage de paquets et étendre la démarche à d’autres supports d’installation, comme l’ISO Gnome
- Une infrastructure de reconstructions indépendantes régulières et des outils de partage et de consommation de preuves de build, comme trustix, sont également nécessaires
1 commentaires
Commentaires sur Hacker News
Reconstruire à nouveau l’ISO minimale à partir des sources constitue une étape impressionnante dans le parcours vers un système pouvant être compilé de manière reproductible à partir des sources
Guix a récemment accompli, dans le même parcours, une avancée orthogonale mais tout aussi impressionnante, en amorçant toute la chaîne d’outils du compilateur à partir d’un unique binaire reproductible de 357 octets, sans autre blob de compilateur binaire
Peut-être qu’un jour prochain, les deux seront combinés pour permettre de reconstruire de manière reproductible une distribution entière à partir des sources
https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-...
Le point clé que beaucoup ne comprennent pas, c’est qu’il ne s’agit pas de prouver que le résultat est fiable à 100 %, mais de prouver qu’il est fidèle à 100 % au code source
Autrement dit, si quelque chose de suspect comme une backdoor furtive est découvert, on peut alors toujours le reproduire de façon déterministe
Du point de vue des acteurs malveillants, il n’y a plus nulle part où fuir ni se cacher
On pourrait probablement documenter à la main l’intégralité de ces 357 octets de code machine pour les rendre compréhensibles par un humain
C’est peut-être une question naïve, car je n’ai jamais fait ce genre de chose, mais je me demande pourquoi la reproductibilité n’est pas le comportement par défaut
Si l’on compile deux fois un logiciel à partir du même code source, je ne vois pas très bien ce qui empêche d’obtenir exactement le même résultat à chaque fois
Je sais qu’il y a beaucoup d’éléments en mouvement, mais j’ai encore du mal à comprendre comment les différences apparaissent
On peut voir ici une liste des problèmes fréquents : https://reproducible-builds.org/docs/
Le fond du problème, de manière générale, c’est que les développeurs ne testent pas si la compilation est reproductible
Quand cela fait partie des tests de release, cela reste généralement reproductible dans le temps
Parmi les exemples classiques qui rendent explicitement une compilation non reproductible, il y a les horodatages et les informations sur l’auteur
Il existe aussi des endroits où la reproductibilité est rompue implicitement : par exemple, beaucoup de runtimes ne définissent pas l’ordre des éléments d’une table de hachage, et le compilateur peut parcourir cette table pour produire le binaire
Il peut y avoir des opérations qui ne sont pas indépendantes de l’ordre, et selon l’état du CPU, on peut obtenir des binaires légèrement différents tout en restant corrects dans tous les cas
Parfois aussi, la cause est une métadonnée dépendante du temps ou de l’environnement, ou encore l’ordre d’exécution des threads
Désolé si je me trompe, mais je pensais que l’une des principales raisons d’être de NixOS était justement la reproductibilité
Je croyais que ces problèmes avaient déjà été résolus
Je n’ai utilisé NixOS qu’environ deux heures, je voulais essayer Hyprland, et comme Hyprland demande un peu de configuration, je pensais qu’il serait plus facile de reprendre la configuration de quelqu’un d’autre sur NixOS que sur d’autres distributions
Mais il était difficile de trouver une configuration, j’ai trouvé trois gist GitHub au hasard, aucun ne fonctionnait, alors j’ai abandonné
Contrairement aux distributions classiques, il ne dépend pas de l’environnement global du système, donc dans bien des cas on obtient déjà le même binaire à chaque fois
Mais le processus de build lui-même peut rester non déterministe dans de nombreux paquets, donc cela ne suffit pas à garantir immédiatement une reproductibilité complète
Celui auquel vous pensez sans doute, c’est la possibilité de reconstruire facilement un paquet binaire en utilisant les mêmes versions de dépendances, les mêmes options de build, etc.
Autrement dit, il ne devrait pas y avoir de nouveaux échecs de compilation du type « chez moi ça marchait »
Le sens utilisé ici, c’est que tous les artefacts de build deviennent des binaires identiques octet par octet
Ils ne doivent pas dépendre du nom de la machine, de l’heure de compilation, de l’ordre dans lequel les fichiers finissent d’être compilés lors d’un build parallèle, etc., et c’est nettement plus difficile
Si l’on n’y est pas habitué, ce n’est pratiquement pas l’outil à choisir quand on veut simplement que « ça marche tout de suite »
Sur NixOS, quand on dit « reproductible », cela veut plutôt dire « obtenir le même comportement logiciel à partir du même code Nix »
C’est assez proche de ce que les gens attendent d’un Dockerfile, et vise à résoudre les problèmes du type « ça marchait sur ma machine » ou « ça marchait la dernière fois »
En revanche, les « builds reproductibles » visent à ce que les artefacts produits sur des machines différentes soient identiques bit à bit
Cela ajoute une couche de sécurité, car on peut alors vérifier qu’un code a bien été compilé à partir d’un ensemble précis de sources
Je suis aussi curieux de savoir quels mots-clés ont été utilisés pour chercher une configuration
En recherchant « nixos configuration », on obtient des résultats comme https://github.com/search?q=nixos%20configuration&type=repos..., et rien que pour Hyprland il y en a déjà pas mal, par exemple https://github.com/search?q=wayland.windowManager.hyprland&t...
Jeter un œil à https://github.com/donovanglover/nix-config peut être utile
C’est une configuration basée sur Flake, avec Hyprland et plusieurs autres choses intéressantes
À l’heure actuelle, NixOS n’est pas vraiment un outil pour les personnes peu endurantes ou qui manquent de temps
J’espère que cela changera un jour, mais si on tient bon et qu’on passe le cap, on peut en tirer des avantages
Je me demande si la recherche de code GitHub a été utilisée
On peut trouver les options Home Manager correspondantes ici : https://mipmip.github.io/home-manager-option-search/?query=h...
Puis faire une recherche sur GitHub : https://github.com/search?utf8=%E2%9C%93&q=lang%3Anix+hyprla...
Certaines recherches d’options peuvent suggérer un public plus casual ou plus avancé
Il faut se rappeler que la reproductibilité de Nix / NixOS / Nixpkgs est une reproductibilité des sources
Si les sources changent, on en est averti, mais ce n’est pas la même chose que la reproductibilité des binaires, qui peuvent varier d’un build à l’autre
La reproductibilité binaire de Nix / NixOS / Nixpkgs n’est, au moins de manière systématique, pas particulièrement bien testée
Guix, Arch Linux et Debian traitent mieux la reproductibilité binaire que Nix / NixOS / Nixpkgs
Références : https://r13y.com/ (Nix*) / https://tests.reproducible-builds.org/debian/reproducible.ht... (Debian) / https://tests.reproducible-builds.org/archlinux/archlinux.ht... (Arch Linux) / https://data.guix.gnu.org/repository/1/branch/master/latest-... (Guix, le chargement peut être lent et une copie en cache est disponible sur https://archive.is/lTuPk)
La reproductibilité des entrées signifie une « invalidation de cache parfaite des entrées »
Nix et Guix le font parfaitement par conception, au point de provoquer parfois trop de rebuilds
Debian et Arch Linux n’en font pas une préoccupation principale et gèrent la question de savoir quels paquets reconstruire lorsqu’un fichier source donné est mis à jour via des méthodes ad hoc comme des déclencheurs manuels de rebuild
La reproductibilité des sorties signifie que « le processus de build est déterministe et produit toujours le même binaire », et c’est le sujet du billet d’origine
Nix aide sur ce point en construisant les paquets dans un bac à sable, mais ce n’est pas une solution miracle
Sur cet aspect, Nix est dans le même bateau que Debian et Arch Linux
En pratique, les distributions envoient souvent en amont des correctifs pour améliorer la reproductibilité, et les autres distributions en profitent aussi
Dans ce contexte, https://reproducible.nixos.org est l’équivalent des autres liens présentés ; et je suis d’accord pour dire que le rapport Nix est moins détaillé, mais cela ne veut pas dire que la reproductibilité binaire de Nix est pire
Lire cela comme « Nix ne gère bien que la reproductibilité des entrées et mal la reproductibilité binaire » serait incorrect
C’est précisément ce jalon qu’on est en train de célébrer ici
Il parle de reproduire bit à bit non seulement les binaires, mais aussi la manière dont ils sont empaquetés en ISO
r13y.com est obsolète, et de mémoire les moins de 1 % manquants venaient d’une régression upstream de Python
La reproductibilité des binaires eux-mêmes, en dehors de l’empaquetage ISO, avait déjà été atteinte il y a plusieurs années
Dès qu’on va au-delà de l’ISO de base vers les autres paquets, la comparaison devient plus compliquée
La manière de traiter les paquets est subtilement, mais de façon importante, différente dans ce contexte, et beaucoup de paquets qui seraient probablement sur l’AUR d’Arch sont des paquets ordinaires dans Nix, tandis que la plupart des paquets upstream en
-binne sont tout simplement pas nécessaires dans NixEn général, Nix facilite la création de builds reproductibles, mais ce n’est pas toujours possible indépendamment de Nix et cela nécessite souvent des correctifs
Si on ajoute à cela que le dépôt principal de paquets de Nix en compte plus de 80 000, contre moins de 15 000 pour Arch hors AUR, comparer les pourcentages n’est pas très utile
Une confusion très fréquente consiste à penser que le hash des chemins du Nix store est basé sur les sorties du build, alors qu’en réalité il est basé sur l’ensemble des sources et des entrées utilisées pour construire les binaires dans un environnement isolé, qu’il s’agisse ou non de binaires
Cela signifie qu’on n’obtient pas exactement les avantages de sécurité que certains imaginent, mais qu’en contrepartie on peut utiliser, sous une forme de distribution raisonnablement reproductible, même des logiciels qui ne se buildent pas de manière reproductible, dès lors que les fonctionnalités, les options du compilateur, les versions des dépendances, l’utilisateur, la configuration, etc. restent identiques
Il s’agit de vérifier si, à partir des mêmes sources, des builds effectués sur des machines différentes produisent les mêmes binaires
L’idée essentielle est que les binaires ne changent pas d’un build à l’autre
La méthode de test indique aussi que chaque build est exécuté deux fois, à des moments différents, sur du matériel différent et avec des noyaux différents
Je vois que cela indique 85,6 % de reproductibilité : https://reproducible.archlinux.org
Je me demande quelle quantité de travail cela demanderait pour NixOS, avec plus de 80 000 paquets dans les dépôts officiels
Ce n’est absolument pas vrai, que l’on considère les objectifs de nixpkgs ou la réalité
Le billet d’origine parle de la reproduction d’une ISO minimale binaire contenant plusieurs paquets binaires
Il est assez ironique, et amusant, que le projet OpenBSD avance avec énergie dans la direction exactement opposée
OpenBSD donne à chaque installation des décalages d’adresses uniques et aléatoires
Je comprends que les deux objectifs, builds reproductibles et installations uniques, soient orthogonaux et puissent être atteints simultanément, mais cette dualité reste drôle
Ou alors on peut aléatoiriser les décalages au démarrage du programme, ce qui préserverait la reproductibilité tout en améliorant encore la sécurité
Dans ce cas, les décalages changeraient à chaque exécution
Les paquets eux-mêmes peuvent donc toujours être reproductibles
Toute l’aléatoirisation est effectuée en local après le téléchargement du paquet et la vérification de sa somme de contrôle
J’aimerais maintenant que, comme presque toutes les autres distributions Linux le font depuis les années 1990, les mainteneurs se contentent de signer les paquets
Ainsi, tout le monde pourrait au moins savoir dans une certaine mesure que le code qu’il compile est bien le même code soumis et relu par des personnes connues
Tant que la signature ne sera pas standardisée, j’ai du mal à imaginer utiliser Nix en production pour protéger quelque chose qui a de la valeur
Pour la plupart, ils n’offrent aucune garantie sur le contenu des paquets
Attendre de leur signature une garantie significative me semble un peu comme attendre du support produit d’un livreur
Il n’est même pas nécessaire de leur faire confiance pour ne pas empaqueter quelque chose de malveillant
Nix fait des builds reproductibles, donc si vous ne voulez pas dépendre du cache binaire, il suffit d’examiner la derivation et de builder vous-même
Le caractère fondamentalement malveillant ou non du contenu reste au final une question entre le développeur et l’utilisateur
Si d’autres distributions vous ont amené à croire le contraire, je pense que c’est assez trompeur
La seule exception qui me vienne à l’esprit serait Tails, mais Tails n’est pas aussi large dans son périmètre que Nix
De ce que j’ai vu, Debian ne le fait plus et c’est le système de build qui signe les builds, Fedora ne le fait pas non plus, et pour Arch je ne suis pas certain mais j’ai l’impression que non
Le système de build de NixOS signe tous les artefacts de build avec sa propre clé et vérifie les signatures au téléchargement
Si l’on veut être paranoïaque, Nix permet au moins de tout builder directement depuis les sources
C’est une étape très impressionnante, bravo à toutes les personnes qui l’ont rendue possible
Il est indiqué qu’au moment de rebuilder réellement l’ISO, il y avait encore des différences, dues à des problèmes restants dans le cache Hydra ainsi qu’à la manière dont l’ISO était générée
Je me demande si quelqu’un peut expliquer comment ils ont corrigé « la manière dont l’ISO était générée »
J’avais essayé autrefois de produire une ISO reproductible, mais je n’arrivais pas à forcer le système de fichiers à créer les extents de manière déterministe
La dernière étape de ce processus génère l’ISO dans le répertoire
./result/isoJ’imagine que ce que vous cherchez, c’est la commande invoquée par ce build, mais je ne sais pas exactement quelle étape vous cherchez
Par exemple, l’appel à
xorrisose trouve ici : https://github.com/NixOS/nixpkgs/blob/master/nixos/lib/make-...Pour faire ça, ne faut-il pas truquer l’heure système ?
Le temps finit souvent intégré dans les binaires d’une manière ou d’une autre
C’est tellement courant que de nombreux compilateurs implémentent SOURCE_DATE_EPOCH, une variable devenue un standard de fait pour falsifier les horodatages : https://reproducible-builds.org/docs/source-date-epoch/
Est-ce que cela n’aide pas à résoudre le problème décrit par Ken Thompson dans « Reflections on Trusting Trust » ?
Si l’on peut bootstrap entièrement tout le système à partir du code source, il me semble qu’il devient plus difficile d’y glisser quelque chose comme un compilateur backdooré
En théorie, il pourrait toujours y avoir une backdoor sophistiquée dans l’environnement où l’ISO est buildée
Si vous voulez vraiment traiter ce problème, vous pouvez regarder le Diverse Double Compiling(https://dwheeler.com/trusting-trust/) ou le bootstrap de l’environnement complet(https://bootstrappable.org/)
La section « cette approche n’a-t-elle pas un problème de bootstrap ? » du billet est également pertinente
Cela dit, le simple fait de reproduire le build aide déjà beaucoup à rendre ce type d’attaque de moins en moins plausible
J’ai récemment passé du temps dans l’écosystème Red Hat pour le travail
Je me demande comment cela se compare à Fedora Silverblue, Ansible, ou Fedora Silverblue + Ansible
Imagebuilder revendique la reproductibilité, mais à ma connaissance il installe la plupart des paquets rpm sous forme binaire et non depuis les sources
Donc, à moins que tous les paquets d’entrée ne soient eux aussi reproductibles, il ne s’agit pas d’une reproductibilité stricte
Si les explications sur le build de paquets depuis les sources, la création d’images de distribution et la question de la reproductibilité ne vous parlent pas vraiment, il est probable que vous ne soyez pas le public principal visé
À l’inverse, Ansible indique les étapes que l’OS doit suivre
Silverblue et Nix sont orthogonaux, hormis le fait que ce sont tous deux des distributions Linux
Silverblue est une tentative de changer la manière de distribuer les logiciels en n’utilisant que des conteneurs sur un hôte immuable
Si vous cherchez une alternative à Ansible qui imite dans une certaine mesure Nix avec Jsonnet et le suivi d’état, Etcha vaut le détour : https://etcha.dev
Nix est immuable
Les nouveaux changements sont construits entièrement à neuf, et ce n’est qu’une fois la compilation réussie que tous les paquets sont « liés symboliquement » au système actuel
Fedora Silverblue repose sur ostree https://github.com/ostreedev/ostree
Cela fonctionne un peu comme git pour l’arborescence racine, mais il faut redémarrer tout le système pour appliquer les changements
Nix, lui, fonctionne en liant symboliquement les paquets, il n’est donc pas nécessaire de redémarrer le système
Une explication plus détaillée est disponible ici : https://dataswamp.org/~solene/2023-07-12-intro-to-immutable-...