- Se demostró que la ISO mínima de instalación de NixOS puede reconstruirse de forma independiente y quedar idéntica bit por bit a la distribuida por Hydra, lo que permite verificar si los binarios distribuidos coinciden con el código fuente
- Esta verificación reproduce no solo los paquetes incluidos en la ISO, sino también el propio proceso de generación de la ISO, por lo que cubre un alcance mayor que la simple reproducibilidad de paquetes
- La reconstrucción comenzó desde un appliance de NixOS 20.03 para VirtualBox, usando la revisión
63678e9f3d3adenixpkgs, y con--option substitute falsepara desactivar la dependencia de la caché binaria - Si la OVA de 2020 o el
gitdescargado hubieran tenido una puerta trasera sofisticada, seguirían siendo un vector de ataque, así que aún falta una verificación basada en un sistema totalmente bootstrappeado - La reconstrucción de la ISO mínima es un hito importante, pero los siguientes retos son eliminar soluciones temporales, reproducir más medios de instalación, contar con infraestructura de reconstrucción independiente periódica y herramientas de prueba de build
Reproducibilidad verificada en la ISO mínima
- Se volvió a construir de forma independiente el build de la ISO
nixos-minimalpublicado por Hydra y se obtuvo un resultado idéntico bit por bit - El alcance de la reproducibilidad se divide en dos ejes
- Todos los paquetes que entran en la ISO
- El propio proceso de build que crea la ISO
- También se construyeron los paquetes necesarios para generar la ISO aunque no queden incluidos dentro de ella, y sin depender de binarios en caché
- Los builds reproducibles ofrecen una ruta de confianza para comprobar si los binarios distribuidos son fieles al código fuente y si no fueron alterados en pipelines de build como Hydra
Procedimiento de reconstrucción y limitaciones
- La reconstrucción se realizó partiendo de un appliance nuevo de NixOS 20.03 para VirtualBox
- Se asignó suficiente CPU y memoria, y se expandió el disco a unos 65GB
- Después de instalar
git, se clonónixpkgsy se hizo checkout de la revisión63678e9f3d3a - Con
--option substitute false, los elementos necesarios se construyeron en la máquina local en lugar de obtenerse desde la caché binaria
- El procedimiento incluye medidas temporales para rodear problemas conocidos
- Siguen existiendo limitaciones desde la perspectiva de confianza en la cadena de suministro
- Si la OVA de 2020 o el
gitdescargado hubieran tenido una puerta trasera sofisticada, eso seguiría siendo un vector de ataque - Sería mejor reconstruir desde un sistema completamente bootstrapped, pero todavía no se ha llegado a ese punto
- Los avances relacionados continúan en el hilo del proyecto de seguridad de la cadena de suministro de nixpkgs
- Si la OVA de 2020 o el
Diferencia entre el anuncio de 2021 y este resultado
- En 2021 hubo un anuncio de que la ISO mínima era 100% reproducible, pero en ese momento solo se habían reproducido individualmente los paquetes necesarios para el build de la ISO, y aún quedaban diferencias en la reconstrucción real de la ISO
- La causa eran problemas pendientes con la caché de Hydra y la forma de generar la ISO
- Después, mientras se corregían esos problemas, aparecieron regresiones como un problema upstream de Python 3.10, y recién esta semana volvió a haber un estado en el que se pudo verificar toda la cadena
- Los siguientes pasos incluyen eliminar las soluciones temporales, reproducir más paquetes y reproducir otros medios de instalación como la ISO de Gnome
- También se necesita infraestructura periódica de reconstrucción independiente y herramientas para compartir y consumir pruebas de build, como trustix
1 comentarios
Opiniones de Hacker News
Haber reconstruido la ISO mínima desde el código fuente es un hito impresionante en el camino hacia un sistema que se pueda compilar de forma reproducible a partir del código fuente
Guix también logró recientemente un avance ortogonal, pero igual de impresionante, en ese mismo camino: arrancó toda la cadena de herramientas de compilación a partir de un único binario reproducible de 357 bytes, sin ningún otro blob binario de compilador
Quizá algún día pronto ambos esfuerzos se combinen y permitan compilar de forma reproducible toda una distribución desde el código fuente
https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-...
Lo que mucha gente no entiende es que el punto no es demostrar que el resultado sea 100% confiable, sino demostrar que el resultado es 100% fiel al código fuente
Es decir, si se descubre algo sospechoso, como una puerta trasera oculta, siempre podrá reproducirse de forma concluyente
Para los malos, eso significa que no habrá dónde correr ni dónde esconderse
Parece que se podrían documentar a mano los 357 bytes completos de código máquina para que una persona pudiera entenderlos
Puede que sea una pregunta tonta porque nunca he hecho algo así, pero me pregunto por qué la reproducibilidad no es el comportamiento predeterminado
Si compilaste dos copias de software desde el mismo código fuente, no entiendo bien qué impide que salgan exactamente iguales cada vez
Sé que hay muchas piezas móviles, pero sigo sin entender cómo aparecen las diferencias
Aquí se puede ver una lista de problemas frecuentes: https://reproducible-builds.org/docs/
La clave general es que los desarrolladores no prueban si las compilaciones son reproducibles
Si se incluye en las pruebas de lanzamiento, por lo general se mantienen reproducibles
Entre los ejemplos típicos que explícitamente hacen que algo no sea reproducible están las marcas de tiempo y la información del autor
También hay lugares donde se rompe implícitamente la reproducibilidad por defecto; por ejemplo, muchos runtimes no definen el orden de las entradas de un hashmap, y a veces el compilador recorre ese hashmap para construir el binario
Puede haber tareas cuyo orden sí importe, y según el estado de la CPU podrían salir binarios ligeramente distintos, aunque todos sean resultados correctos
A veces también se debe a metadatos que dependen del tiempo o del entorno, o al orden de ejecución de los hilos
Perdón por la ignorancia, pero pensaba que una de las principales razones de existir de NixOS era la reproducibilidad
Creía que estos problemas ya estaban resueltos
Solo usé NixOS unas 2 horas y quería probar Hyprland; como Hyprland requiere algo de configuración, pensé que sería más fácil tomar la configuración de otra persona en NixOS que en otras distribuciones
Pero fue difícil encontrar configuraciones, encontré unas 3 en gists aleatorios de GitHub y ninguna funcionó, así que me rendí
Como no depende de todo el entorno del sistema, a diferencia de una distribución común, en muchos casos ya produce el mismo binario cada vez
Pero el proceso de compilación en sí puede ser no determinista en muchos paquetes, así que eso por sí solo no da inmediatamente una reproducibilidad completa
El significado en el que estás pensando es que, al reconstruir fácilmente paquetes binarios, se usen las mismas versiones de dependencias, las mismas opciones de compilación, etc.
Significa que no debería haber margen para que aparezcan errores de compilación del tipo “en mi laptop sí funcionaba”
El significado del que se habla aquí es que todos los artefactos de compilación sean binarios idénticos byte por byte
No deben depender del nombre de la máquina, de la hora de compilación, del orden en que terminan de compilarse los archivos en una compilación paralela, etc.; y esto último es mucho más difícil
Si no estás familiarizado con ella, casi nunca es la herramienta que elegirías en una situación de “quiero que esto funcione ahora mismo”
En NixOS, decir que algo es “reproducible” se parece más a “con el mismo código Nix obtengo el mismo comportamiento del programa”
Es parecido a lo que la gente espera de un Dockerfile, y apunta a resolver problemas como “en mi máquina funcionaba” o “la vez pasada funcionaba”
En cambio, las “compilaciones reproducibles” buscan que los artefactos creados en máquinas distintas sean idénticos bit a bit
Eso agrega una capa de seguridad, porque permite verificar si el código se compiló a partir de un conjunto específico de fuentes
También me da curiosidad qué términos de búsqueda usaste para encontrar configuraciones
Si buscas “nixos configuration”, aparecen resultados como https://github.com/search?q=nixos%20configuration&type=repos..., y solo para Hyprland también se ven bastantes, como https://github.com/search?q=wayland.windowManager.hyprland&t...
Conviene ver https://github.com/donovanglover/nix-config
Es una configuración basada en Flake e incluye Hyprland y varias cosas buenas
Actualmente NixOS no es una herramienta para gente débil o con poco tiempo
Espero que algún día cambie, pero si aguantas y superas la curva, puedes obtener beneficios
Me pregunto si usaste la búsqueda de código de GitHub
Las opciones relacionadas de Home Manager se pueden encontrar aquí: https://mipmip.github.io/home-manager-option-search/?query=h...
Luego puedes buscar en GitHub: https://github.com/search?utf8=%E2%9C%93&q=lang%3Anix+hyprla...
Algunas búsquedas de opciones pueden apuntar a usuarios más casuales o más avanzados
Hay que recordar que la reproducibilidad de Nix / NixOS / Nixpkgs es reproducibilidad de las fuentes
Si las fuentes cambian, recibes una advertencia, pero eso no es lo mismo que la reproducibilidad de binarios que pueden cambiar en cada compilación
La reproducibilidad binaria de Nix / NixOS / Nixpkgs, al menos de forma sistemática, no suele estar muy bien probada
Guix, Arch Linux y Debian manejan la reproducibilidad binaria mejor que Nix / NixOS / Nixpkgs
Fuentes: 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, puede tardar en cargar; copia en caché en https://archive.is/lTuPk)
Reproducibilidad de entradas significa “invalidación perfecta de caché respecto de las entradas”
Nix y Guix lo hacen perfectamente por diseño y, a veces, provocan demasiadas recompilaciones
Debian y Arch Linux no lo tienen como preocupación principal, y manejan el problema de qué paquetes reconstruir cuando se actualiza un archivo fuente específico con métodos provisionales como disparadores manuales de recompilación
Reproducibilidad de salidas significa que “el proceso de compilación es determinista y siempre produce el mismo binario”, y es el tema del artículo original
Nix compila paquetes en un sandbox, lo cual ayuda, pero no es una solución mágica
En ese aspecto, Nix está en el mismo barco que Debian y Arch Linux
De hecho, las distribuciones suelen enviar upstream parches que mejoran la reproducibilidad, y otras distribuciones también se benefician de ello
En este contexto, https://reproducible.nixos.org es la contraparte de los otros enlaces presentados, y coincido en que el informe de Nix es menos detallado, pero eso no significa que la reproducibilidad binaria de Nix sea peor
Si se lee como “Nix solo es bueno en reproducibilidad de entradas y no en reproducibilidad binaria”, eso es incorrecto
Justamente estamos celebrando ese hito aquí
Trata de reproducir bit a bit no solo los binarios, sino también la forma en que se empaquetan como ISO
r13y.com está desactualizado, y, si no recuerdo mal, ese menos de 1% faltante también se debía a una regresión upstream de Python
La reproducibilidad de los binarios en sí, excluyendo el empaquetado de la ISO, ya se había logrado hace unos años
Cuando se pasa a paquetes más allá de la ISO básica, la comparación se vuelve complicada
La forma en que se manejan los paquetes es sutilmente distinta, pero importante en este contexto, y muchos paquetes que probablemente estarían en AUR de Arch están en Nix como paquetes normales; además, la mayoría de los paquetes upstream -bin simplemente no son necesarios en Nix
En general, Nix facilita crear compilaciones reproducibles, pero eso no siempre es posible independientemente de Nix y a menudo requiere parches
Si además consideramos que el repositorio base de paquetes de Nix tiene más de 80 mil paquetes, mientras que Arch tiene menos de 15 mil excluyendo AUR, las comparaciones porcentuales no son muy útiles
Un malentendido muy común es pensar que el hash de las rutas del Nix store se basa en la salida de la compilación, pero en realidad se basa en el conjunto completo de todas las fuentes y entradas usadas para compilar el binario en un entorno aislado, sin importar si son binarios o no
Por eso no ofrece tal cual los beneficios de seguridad que la gente espera, pero a cambio permite usar software que no se compila de forma reproducible en una forma de distribución razonablemente reproducible, con las mismas funciones, configuración del compilador, versiones de dependencias, usuario, configuración, etc.
Se trata de verificar si el binario es el mismo al compilar desde las mismas fuentes en máquinas distintas
El punto es que el binario no cambie cada vez que se compila
El método de prueba también dice que cada compilación se ejecuta dos veces en distintos momentos, distinto hardware y distintos kernels
Veo que aparece como 85.6% reproducible: https://reproducible.archlinux.org
Me pregunto cuánto trabajo hará falta en NixOS, que tiene más de 80 mil paquetes en sus repositorios oficiales
Considerando los objetivos o la realidad de nixpkgs, eso no es cierto en absoluto
El artículo original trata de reproducir una ISO mínima binaria que incluye varios paquetes binarios
Me da risa la ironía de que el proyecto OpenBSD esté avanzando con tanto empeño en la dirección opuesta
OpenBSD tiene offsets de direcciones únicos y aleatorizados en cada instalación
Entiendo que los dos objetivos —compilaciones reproducibles e instalaciones únicas— son ortogonales y pueden lograrse al mismo tiempo, pero esa dualidad igual me parece graciosa
Otra opción sería aleatorizar los offsets al iniciar el programa, lo que aumentaría la seguridad sin perder reproducibilidad
Así, el offset cambiaría en cada ejecución
Los paquetes en sí aún pueden ser reproducibles
Toda la aleatorización se realiza localmente después de descargar los paquetes y verificar sus checksums
Ahora solo faltaría que los mantenedores firmen los paquetes, como han hecho casi todas las demás distribuciones de Linux desde los 90
Así todos podríamos tener cierta certeza de que el código que compilamos es el mismo código enviado y revisado por personas conocidas
Hasta que las firmas estén estandarizadas, me cuesta imaginar usar Nix en producción para proteger algo valioso
La mayoría no da ninguna garantía sobre el contenido de los paquetes
Esperar garantías significativas de sus firmas se siente parecido a esperar soporte del producto por parte del repartidor
Ni siquiera hace falta confiar en que no lo empaquetaron de forma maliciosa
Como Nix hace compilaciones reproducibles, si no quieres depender de la caché de binarios, puedes revisar la derivation y compilarla tú mismo
Si el contenido de fondo es malicioso, eso al final es un asunto entre el desarrollador y el usuario
Si otras distribuciones te hicieron creer lo contrario, diría que eso es casi una forma de engaño
La excepción que se me ocurre es Tails, aunque Tails no es tan amplio como Nix
Por lo que veo, Debian ya no lo hace y es el sistema de compilación el que firma las builds; Fedora tampoco lo hace, y con Arch no estoy seguro, pero creo que tampoco
El sistema de compilación de NixOS firma todos los artefactos de build con su propia clave y verifica las firmas al descargar
Si quieres ser paranoico, Nix al menos facilita compilarlo todo directamente desde el código fuente
Es un hito muy impresionante, y felicidades a quienes lo hicieron posible
El texto dice que incluso al recompilar realmente la ISO aparecieron diferencias, y que las causas fueron problemas pendientes en la caché de Hydra y la forma en que se generaba la ISO
Me pregunto si alguien puede explicar cómo corrigieron “la forma en que se generó la ISO”
Hace tiempo intenté crear una ISO reproducible, pero no pude hacer que el sistema de archivos generara extents de manera determinista
El último paso de ese proceso genera la ISO en el directorio
./result/isoParece que lo que buscas es el comando que invocó esa build, aunque no estoy muy seguro de qué paso estás buscando
Por ejemplo, la invocación a
xorrisoestá aquí: https://github.com/NixOS/nixpkgs/blob/master/nixos/lib/make-...¿No habría que falsear la hora del sistema para hacer esto?
La hora suele meterse en los binarios de una u otra forma
Son tan comunes que muchos compiladores implementan SOURCE_DATE_EPOCH, una variable de facto estándar para falsear timestamps: https://reproducible-builds.org/docs/source-date-epoch/
¿Esto no ayuda a resolver el problema que Ken Thompson describió en “Reflections on Trusting Trust”?
Si se puede bootstrappear por completo todo el sistema desde el código fuente, parecería más difícil colar algo como un compilador con backdoor
En teoría, también podría haber un backdoor sofisticado dentro del entorno en el que se compila la ISO
Si de verdad quieres resolver ese problema, puedes ver Diverse Double Compiling (https://dwheeler.com/trusting-trust/) o el bootstrap de todo el entorno (https://bootstrappable.org/)
La sección del artículo “¿el enfoque anterior no tiene un problema de bootstrap?” también es relevante
Aun así, solo reproducir las builds ayuda mucho a que ese tipo de ataque sea cada vez menos probable
Por trabajo reciente estuve dentro del ecosistema de Red Hat
Me pregunto cómo se compara esto con cosas como Fedora Silverblue, Ansible o Fedora Silverblue + Ansible
Imagebuilder afirma ser reproducible, pero hasta donde sé instala la mayoría de los paquetes rpm como binarios, no desde el código fuente
Así que, si todos los paquetes de entrada no son también reproducibles, no es reproducibilidad estricta
Si la explicación sobre compilar paquetes desde el código fuente, crear una imagen de distribución y tratar la reproducibilidad no te resonó, probablemente no seas el lector principal al que va dirigida
En cambio, Ansible especifica los pasos que debe seguir el sistema operativo
Silverblue y Nix son ortogonales entre sí, más allá de que ambos son distribuciones de Linux
Silverblue es un intento de cambiar la forma de entregar software usando solo contenedores sobre un host inmutable
Si buscas una alternativa a Ansible que imite en cierta medida a Nix usando Jsonnet y seguimiento de estado, vale la pena ver Etcha: https://etcha.dev
Nix es inmutable
Los cambios nuevos se crean desde cero y, solo después de que la compilación tiene éxito, todos los paquetes se “enlazan simbólicamente” al sistema actual
Fedora Silverblue está basado en ostree https://github.com/ostreedev/ostree
Funciona de manera similar a git para el árbol raíz, pero para aplicar cambios hay que reiniciar todo el sistema
Como Nix funciona enlazando simbólicamente los paquetes, no es necesario reiniciar el sistema
Hay una explicación más detallada aquí: https://dataswamp.org/~solene/2023-07-12-intro-to-immutable-...