Dlaczego CI
Dlaczego bezpieczeństwo łańcucha dostaw należy do Państwa CI
Dostarczane przez Państwa oprogramowanie to to, co wytworzył build CI, z tego, co w danej chwili pobrał. Ten build to jedyne miejsce, w którym można zobaczyć, co weszło, zdecydować, co ma prawo wejść, i zapisać, co trafiło do wydania.
Zaktualizowano
What software supply chain security means
Robocza definicja z wystąpienia: Państwa oprogramowanie to własny kod plus wszystko, od czego zależy, a łańcuch dostaw to każdy krok, który wprowadza te elementy do wydania.
Petteri Pulkkinen i Erika Marttinen na Kubernetes Community Days Helsinki 2026, od 2:35 do 4:28 nagrania SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
Państwa build produkcyjny to nie build z laptopa
Większość zespołów zakłada, że kod przetestowany lokalnie to kod, który trafia do klientów. Źródło jest to samo, ale oprogramowanie często nie. Build to kod źródłowy plus wszystko, co pobiera, i wszystko, co go otacza w chwili uruchomienia, a bardzo niewiele z tego jest stałe.
Nieprzypięte zależności są rozwiązywane inaczej
Zakresy wersji to norma. W npm ^1.0.4 akceptuje każde późniejsze wydanie 1.x, więc ten sam package.json instaluje różne wersje w różne dni. Lockfile je przypina, ale tylko jeśli został zatwierdzony, a build go respektuje: npm ci kończy się błędem, gdy lockfile i package.json się nie zgadzają, natomiast npm install może po cichu zaktualizować lockfile. Wiele projektów w ogóle go nie zatwierdza. Express 5.2.1, szeroko stosowany framework webowy, tego nie robi.
Nawet przypięta wersja to nazwa, a nie plik. Dokumentacja pip wyjaśnia, że samo przypięcie wersji nie powstrzymuje indeksu pakietów przed serwowaniem różnych plików dla tej samej wersji i dlatego pip oferuje tryb sprawdzania hashy.
Czas zmienia wejścia
Rejestry zmieniają się między buildami. Publikowane są nowe wersje, stare są wycofywane, a zakres, który w poniedziałek został rozwiązany bezpiecznie, we wtorek może pobrać przejęte wydanie. Tagi kontenerów też się przesuwają: dokumentacja Dockera ostrzega, że tagi obrazów są zmienne i wydawca może przestawić tag na nowy obraz, więc FROM node:20 nie jest tym samym obrazem bazowym z miesiąca na miesiąc, chyba że przypną go Państwo przez digest.
Czas trafia też do samego wyniku. Projekt Reproducible Builds uznaje znaczniki czasu za największe źródło problemów z odtwarzalnością, ponieważ tak wiele narzędzi zapisuje bieżącą datę i godzinę w tym, co buduje.
Środowisko jest inne
- System operacyjny i architektura. Laptop z macOS i ARM oraz runner CI z Linuksem i x86-64 instalują różne gotowe pliki binarne dla tego samego pakietu. Wiele narzędzi npm jest dziś dostarczanych jako pakiety specyficzne dla platformy, opakowujące skompilowany plik binarny.
- Łańcuchy narzędzi. Wersje kompilatora, środowiska uruchomieniowego i menedżera pakietów rozjeżdżają się między maszynami, chyba że każda z nich jest przypięta.
- Cache. Państwa maszyna i CI przywracają różne cache, utworzone w różnym czasie z różnych rozwiązań zależności.
- Skrypty instalacyjne i kroki buildu. Hooki post-install, akcje konfiguracyjne i skrypty buildu pobierają narzędzia i dane w czasie buildu. Nic z tego nie pojawia się w manifeście.
- Konfiguracja. Zmienne środowiskowe, flagi buildu i sekrety istnieją w CI i nigdzie indziej.
Projekt Reproducible Builds definiuje build odtwarzalny jako taki, w którym przy tym samym kodzie źródłowym, środowisku buildu i instrukcjach buildu każdy może odtworzyć identyczne bit po bicie kopie wszystkich wskazanych artefaktów. Ta definicja pokazuje, jak wiele trzeba utrzymać bez zmian. Buildy większości zespołów tego nie osiągają, a te, które osiągają, ciężko na to zapracowały. Dopóki tak nie jest, jedynym wiarygodnym opisem tego, co dostarczono, jest ten zarejestrowany podczas działania buildu, który to dostarczył.
A software supply chain, walked end to end
Petteri Pulkkinen i Erika Marttinen na Kubernetes Community Days Helsinki 2026, od 15:20 do 16:38 nagrania SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains.
Gdzie można sprawdzać i co widać w każdym z tych miejsc
Kontrole bezpieczeństwa mogą działać w czterech miejscach. Każde ma swoją rolę, ale tylko jedno widzi build, który faktycznie wytworzył Państwa wydanie.
| Funkcja | W buildzie CI | Maszyna programisty | Skan repozytorium | Skan artefaktu |
|---|---|---|---|---|
| Widzi wersje, które faktycznie trafiły na produkcję | Rejestrowane w chwili pobrania | Inna instalacja | Tylko jeśli przypina je lockfile | To, co potrafi rozpoznać |
| Widzi pakiety przechodnie i przywrócone z cache | Własny cache, nie cache CI | Tylko lockfile | ||
| Widzi, co pobierają skrypty instalacyjne | ||||
| Może zatrzymać złośliwe połączenie wychodzące | Polityka ruchu wychodzącego na runnerze | |||
| Wyłapuje problemy przed wypchnięciem kodu | Przy pull requestach |
- W zestawie
- Częściowo
- Brak
Skan repozytorium zgłasza to, co projekt deklaruje. Skan gotowego artefaktu zgłasza to, co potrafi w nim rozpoznać. Żaden nie widział przebiegu buildu. Express 5.2.1 nie zatwierdza lockfile, więc skaner uruchomiony na czystym checkoucie nie ma żadnych zależności npm projektu do rozwiązania i zgłasza to, co jeszcze rozpozna. Gdy to samo narzędzie uruchomi się na zainstalowanej kopii tego samego repozytorium, jedna flaga katalogera znów zmienia odpowiedź. Wynik zależy od tego, co zainstalowano przed skanem, czyli właśnie od tego, czego skan nie kontroluje. Strona SBOM-y z czasu buildu wyjaśnia, dlaczego skany się różnią i co zmienia rejestrowanie buildu.
Pipeline to samodzielny cel ataku
CI to miejsce, w którym spotykają się kod źródłowy, zależności i sekrety, dlatego warto je atakować.
- tj-actions/changed-files (2025). Szeroko stosowana GitHub Action została przejęta i wypisywała sekrety CI do logów buildu.
- Codecov Bash Uploader (2021). Zmodyfikowany skrypt, uruchamiany w CI klientów, wysyłał zmienne środowiskowe na serwer napastnika.
- Robak npm Shai-Hulud (2025). Przejęte pakiety kradły poświadczenia podczas instalacji i używały ich do publikowania kolejnych przejętych pakietów.
- xz utils (2024). Tylną furtkę ukryto w archiwach wydań i w samym procesie buildu, a nie w widocznym kodzie źródłowym.
Każdy z tych ataków uruchamiał kod podczas buildu lub instalacji. Ani skan repozytorium wykonany przed nimi, ani skan artefaktu wykonany po nich nie zobaczyłby, co zrobił proces buildu. Kontrole, które obserwują i ograniczają to, dokąd zadanie może się połączyć, muszą znajdować się tam, gdzie zadanie działa. Dotyczy to także aplikacji wewnętrznych i mało eksponowanych: takie ataki celują w pipeline i pakiety wspólne dla wszystkich aplikacji, a nie w to, co robi dana aplikacja. Zob. bezpieczeństwo łańcucha dostaw oprogramowania wewnętrznego i niskiego ryzyka.
Więcej kodu, więcej zależności, mniej ludzi, którzy je czytają
Agenci AI do kodowania piszą i zmieniają kod szybciej, niż zespoły mogą przejrzeć każdy wiersz, a po drodze dodają zależności. Podają też nazwy pakietów, które nie istnieją: badanie z USENIX Security 2025 obejmujące 576 000 wygenerowanych próbek kodu wykazało odsetek zmyślonych pakietów wynoszący co najmniej 5,2% dla modeli komercyjnych i 21,7% dla modeli open source. Gdy napastnik zarejestruje jedną z tych nazw, jego pakiet zainstaluje następny build, który jej zaufa.
Każda zmiana, niezależnie od tego, kto lub co ją napisało, przechodzi przez build w drodze na produkcję. Dlatego build to jedyny punkt kontrolny, który nie zależy od tego, czy ktoś coś obejrzał.
Dowody muszą opisywać to, co dostarczono
Regulacje i klienci żądają dowodów, a nie deklaracji. Unijny Cyber Resilience Act wymaga od producentów identyfikowania i dokumentowania komponentów ich produktów oraz obsługi ich podatności przez okres wsparcia produktu. SBOM wygenerowany z manifestu opisuje to, o co prosił projekt. SBOM zarejestrowany z buildu opisuje to, co trafiło do wydania, za które Państwo odpowiadają. Gdy publikowana jest nowa podatność, ten drugi mówi, których wydań to dotyczy. Zob. czego wymaga CRA.
Co powinno oznaczać „w CI”
Uruchomienie skanera jako kroku CI to początek, ale nadal analizuje on pliki po ich dotarciu. W CI, jeśli zrobić to właściwie, oznacza:
- Rejestrować, nie wnioskować. Zapisywać każdy pakiet i każde pobranie faktycznie wykonane przez zadanie, łącznie z zależnościami przechodnimi i wszystkim, co przywrócono z cache.
- Określać kompletność zapisu. SBOM powinien podawać, czy obejmuje wszystko, co pobrało zadanie, a nie tylko wymieniać to, co znalazł.
- Kontrolować ruch wychodzący. Decydować, z którymi hostami zadanie może się łączyć, i zatrzymywać resztę, zanim przejęta zależność zdoła nawiązać połączenie z napastnikiem.
- Obserwować także po wydaniu. Ponownie sprawdzać to, co dostarczono, w miarę pojawiania się nowych podatności, i zamieniać znaleziska w poprawki.
To właśnie robi CRACI. To runner dla Państwa zadań GitHub Actions, więc rejestruje to, co pobiera każdy build, stosuje politykę ruchu wychodzącego i monitoruje to, co Państwo dostarczyli. Przeniesienie workflow to jeden wiersz: runs-on: craci. Zob. jak działa CRACI.
Czego CI nie zastępuje
Umieszczenie bezpieczeństwa łańcucha dostaw w buildzie nie czyni innych warstw opcjonalnymi.
- Maszyny programistów nadal przechowują poświadczenia i uruchamiają skrypty instalacyjne. Je także należy chronić; przejęty laptop może wypchnąć kod, zanim uruchomi się jakikolwiek build.
- Przegląd kodu i analiza statyczna znajdują błędy w Państwa własnym kodzie, czego zapis zależności nie robi.
- Przypinanie, lockfile i digesty pozostają dobrą praktyką. Zmniejszają różnice między buildami; rejestrowanie buildu mówi, co i tak się wydarzyło.
Build nie jest jedynym miejscem kontroli. Jest jedynym miejscem, które widzi oprogramowanie faktycznie przez Państwa dostarczane.
CRACI w Państwa własnym pipeline
Prosimy umówić demo, a wspólnie przejdziemy przez Państwa buildy, SBOM-y i dowody zgodności.
Umów demo