Powtarzalne buildy to argument o łańcuchu dostaw

Open source mówi, co mówi kod źródłowy. Nie mówi, że binarka na Twoim urządzeniu została z niego zbudowana. To są różne twierdzenia, a w luce między nimi mieszkają najskuteczniejsze ataki ostatniej dekady — nie w kodzie, który każdy może przeczytać, tylko w maszynerii między tym kodem a artefaktem, który ludzie faktycznie uruchamiają.

Luka, w którą nikt nie patrzy

Między publicznym repozytorium a działającym systemem jest maszyna budująca, łańcuch narzędzi, zestaw zależności pobieranych w trakcie budowania, klucz podpisujący i kanał dystrybucji. Każde z tych miejsc może sprawić, że artefakt różni się od źródła, a prawie żadnego z nich nie audytują ludzie polegający na wyniku.

Niewygodne jest to, że nie jest to hipotetyczne. Skompromitowana infrastruktura budowania i zatrute zależności należą do najskuteczniejszych ataków, jakie istnieją — właśnie dlatego, że dziedziczą całe zaufanie, na które zapracował projekt open source.

Co właściwie twierdzi powtarzalność

Build jest powtarzalny, gdy to samo źródło, z tymi samymi zadeklarowanymi wejściami, produkuje identyczne co do bitu wyjście u każdego, kto go uruchomi.

Brzmi akademicko, dopóki nie zauważysz, co to umożliwia: niezależną weryfikację. Jeśli trzy strony zbudują obraz i dostaną tę samą sumę kontrolną co opublikowany artefakt, to opublikowany artefakt jest tym, co mówi źródło. Nikt nie musi ufać maszynie budującej, bo jej wynik może sprawdzić każdy, kto ma źródło i komputer.

Zamienia to „zaufaj nam” w „sprawdź nas”, co jest jedyną trwałą formą zaufania w infrastrukturze.

Dlaczego to trudne

Bo oprogramowanie jest pełne przypadkowego niedeterminizmu i każdy jego kawałek trzeba znaleźć.

Znaczniki czasu wbudowane w archiwa i binarki. Ścieżki budowania wkompilowane w informacje debugowe. Kolejność plików zależna od systemu plików. Ustawienia lokalne i strefa czasowa wyciekające do generowanych tekstów. Równoległe buildy przeplatające się inaczej przy każdym uruchomieniu. Numery wersji wyprowadzane z momentu budowania zamiast ze źródła.

Żadna z tych rzeczy nie jest trudna z osobna. Jest ich dużo i ukrywają się, dopóki nie porównasz dwóch buildów bajt po bajcie — właśnie dlatego tę dyscyplinę trzeba wbudować od początku, a nie doklejać później.

Co to daje małemu projektowi

Argument zwykle stawia się w kategoriach atakujących na poziomie państwa, przez co brzmi jak czyjś problem. Dla małego projektu codzienne korzyści są przyziemniejsze i bardziej użyteczne.

Debugowanie. „Maszyna budująca miała inną wersję biblioteki” przestaje być możliwym wyjaśnieniem, co usuwa całą kategorię nieodtwarzalnych błędów.

Zaufanie bez etatów. Mały zespół nie może prosić nikogo, żeby ufał jego infrastrukturze. Może opublikować definicję i sumę kontrolną i zaprosić do sprawdzenia — a to twierdzenie, które mały zespół faktycznie udźwignie.

Audytowalność. Regulowany klient pytający, co działa na urządzeniu, dostaje definicję obrazu, sumę kontrolną i sposób samodzielnej weryfikacji zamiast listu z zapewnieniem.

Prawdziwy fork. Open source, którego nie da się niezależnie odbudować, jest licencją tylko do odczytu. Powtarzalność jest tym, co czyni prawo do forka realnym.

Do czego się zobowiązujemy

Jawna definicja obrazu, jawny potok budowania, podpisane artefakty, opublikowane sumy kontrolne i powtarzalny build, żeby każdy mógł potwierdzić, że jedno odpowiada drugiemu.

Nie dlatego, że ktoś czyha na dystrybucję Linuksa przed startem, tylko dlatego, że twierdzenia tego projektu — minimalny, utwardzony, suwerenny — są w całości twierdzeniami o tym, czego w obrazie nie ma. Jedynym uczciwym sposobem na stawianie takich tez jest pozwolenie ludziom sprawdzić je samodzielnie.