O 123% więcej zgłoszonych CVE dziennie w 2026 niż przed rokiem.

Yocto

SBOM Yocto i buildy w CRACI

Yocto potrafi zapisać szczegółowy SBOM w formacie SPDX dla każdego obrazu. W porównaniu buildów SBOM zarejestrowany przez CRACI zawierał każdy komponent z SBOM Yocto, 88 pominiętych przez Yocto i package URL dla każdego z 653 crate'ów Rust, które Yocto wymienia bez niego, przy czasie buildu krótszym o 43%.

Zaktualizowano

Porównanie buildów: core-image-sato

Wymienione komponenty: o 10% więcej w SBOM z CRACI

SBOM z CRACI
953
SBOM z Yocto
865

88 komponentów pominiętych przez Yocto, takich jak pakiety hosta i GitHub Actions; żadnego tylko w SBOM Yocto

Crate'y Rust z package URL, które można sprawdzić pod kątem podatności

SBOM z CRACI
653
SBOM z Yocto
0

Oba wymieniają te same 653; Yocto tylko z nazwy pliku i adresu URL pobierania

Czas i koszt buildu, 32 vCPU ARM64

CRACI
1 h 29 min $5.68
CRACI + SBOM Yocto
2 h 36 min $9.96
GitHub + SBOM Yocto*
5 h 11 min $15.60
43% niższy koszt: CRACI wobec CRACI + SBOM Yocto
64% niższy koszt: CRACI wobec GitHub + SBOM Yocto*

*Szacunek dla runnera hostowanego przez GitHub z 32 rdzeniami ARM64 w cenie $0.050 za minutę, przy CRACI około dwa razy szybszym.

Pełne porównanie ↓

Jak wygenerować SBOM w Yocto

System buildu OpenEmbedded zapisuje SBOM-y w formacie SPDX za pomocą klasy create-spdx. To, czy jest ona włączona i którą wersję SPDX zapisuje, zależy od wydania Yocto:

  • Kirkstone (4.0): domyślnie wyłączona. Należy dodać INHERIT += "create-spdx". SPDX 2.2.
  • Nanbield (4.3): od tego wydania generowanie SBOM jest domyślnie włączone.
  • Scarthgap (5.0): domyślnie włączona, SPDX 2.2. SPDX 3.0 jest dostępne przez klasę create-spdx-3.0.
  • Styhead (5.1) i nowsze: domyślnie włączona, SPDX 3.0.

Ustawia się to w pliku konfiguracyjnym, takim jak conf/local.conf. W aktualnym wydaniu zwykle nie trzeba niczego dodawać; aby wyłączyć generowanie, należy użyć INHERIT_DISTRO:remove = "create-spdx".

# conf/local.conf

# Kirkstone (4.0): SBOM generation is off by default, so turn it on
INHERIT += "create-spdx"

# Scarthgap (5.0): switch the output from SPDX 2.2 to SPDX 3.0
INHERIT_DISTRO:remove = "create-spdx"
INHERIT_DISTRO:append = " create-spdx-3.0"

# Any release: indented JSON you can read in an editor
SPDX_PRETTY = "1"

Inne zmienne SPDX_ dodają szczegóły. SPDX_INCLUDE_SOURCES opisuje pliki źródłowe każdego narzędzia hosta i pakietu docelowego, co znacznie powiększa wynik. Nowsze wydania dodają opcje dla konfiguracji jądra, funkcji PACKAGECONFIG, informacji o dostawcy oraz package URL dla źródeł Cargo, Go, PyPI, npm i CPAN.

Gdzie trafiają pliki SBOM

Po zbudowaniu obrazu główny SBOM pojawia się obok niego jako IMAGE-MACHINE.spdx.json w katalogu tmp/deploy/images/MACHINE/ wewnątrz katalogu buildu. Powiązane pliki znajdują się w tym samym katalogu oraz w tmp/deploy/spdx. W Kirkstone dokumenty dla poszczególnych receptur trafiają do archiwum IMAGE-MACHINE.spdx.tar.zst.

bitbake core-image-minimal

# The image SBOM
ls tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.spdx.json

# Per-recipe and package documents
ls tmp/deploy/spdx/

# Current releases: an SBOM for one recipe, from its metadata only
bitbake busybox -c create_recipe_sbom

CycloneDX z meta-cyclonedx

Samo Yocto zapisuje tylko SPDX. Dla CycloneDX warstwa meta-cyclonedx generuje SBOM z głównego systemu plików obrazu oraz osobny plik VEX z CVE, które system buildu zna jako załatane lub ignorowane. Należy pobrać gałąź warstwy dla swojego wydania, dodać ją do warstw i dziedziczyć jej klasę:

# In your sources directory, on the branch for your release
git clone https://github.com/iris-GmbH/meta-cyclonedx.git
cd meta-cyclonedx
git checkout scarthgap

# conf/bblayers.conf
BBLAYERS += "${BSPDIR}/sources/meta-cyclonedx"

# conf/local.conf
INHERIT += "cyclonedx-export"
# Optional: include build-time packages, not only what is in the image
CYCLONEDX_RUNTIME_PACKAGES_ONLY = "0"

Pliki trafiają obok obrazu do DEPLOY_DIR_IMAGE, z przyrostkami .cyclonedx.bom.json i .cyclonedx.vex.json. Domyślnie jest to CycloneDX 1.6, ustawiane przez CYCLONEDX_SPEC_VERSION. Domyślnie uwzględniane są tylko pakiety uruchomieniowe, co utrzymuje mały rozmiar SBOM, ale może pominąć komponenty, które trafiają do obrazu bez instalacji jako pakiety.

Czego nie obejmuje SBOM z Yocto

SBOM z Yocto dokładnie opisuje to, co buduje BitBake. W SPDX 3 obejmuje obraz, każdą recepturę, łącznie z natywnymi recepturami czasu buildu, ich źródła, nałożone łatki i podatności oznaczone jako naprawione. Dla core-image-sato dało to 1,632 osobnych plików. Aby sprawdzić, czego w nim brakuje, zbudowaliśmy obraz na runnerze CRACI, natywnym ARM64 z 32 vCPU, i porównaliśmy SBOM z Yocto z tym zarejestrowanym przez CRACI, komponent po komponencie, po znormalizowaniu nazw we wszystkich tych plikach.

Spośród 953 komponentów w SBOM z CRACI 865 znalazło się także w SBOM Yocto. Żaden nie występował wyłącznie w SBOM Yocto. Różnice dotyczą tego, czego Yocto nie widzi, oraz tego, jak identyfikuje to, co wymienia.

Crate'y Rust bez package URL

Oba SBOM-y zawierają te same 653 wersje 559 crate'ów Rust, takich jak cairo-rs i zune-jpeg, które kompiluje librsvg. Yocto wymienia każdy z nich tylko jako plik .crate i adres pobierania z crates.io, wewnątrz receptury, która go używa. Żaden nie ma package URL pkg:cargo. CRACI rejestruje każdy crate z package URL.

To przesądza o tym, czy można monitorować je pod kątem podatności. Dopasowywanie podatności działa na podstawie package URL: komunikat bezpieczeństwa dla crate'a określa go jako pkg:cargo/..., a nazwa pliku na liście źródeł innej receptury nie daje narzędziom SBOM ani narzędziom do podatności niczego, do czego można by ją dopasować. Przy samym SBOM z Yocto podatny crate w Państwa obrazie pozostaje niezgłoszony.

Z SBOM z CRACI każdy crate jest dopasowywany do komunikatów bezpieczeństwa, każdy pakiet w buildzie pokazuje swój status podatności, a CRACI na bieżąco ponownie ocenia SBOM w miarę publikowania nowych komunikatów, długo po zakończeniu buildu.

Co znalazł tylko CRACI

88 komponentów, których brakowało w SBOM z Yocto, pochodziło spoza metadanych BitBake:

  • 23 pakiety hosta zainstalowane na maszynie buildu, takie jak cpio 2.15 z Ubuntu, libc6, locales i python3-jinja2. BitBake z nich korzysta, a SBOM z Yocto ich nie wymienia.
  • 10 źródeł z GitHub, w tym patchelf, btrfs-progs i akcja GitHub actions/upload-artifact, przypięte do commita, na którym działał workflow
  • Inne źródła i narzędzia pobrane w trakcie buildu, takie jak pseudo-prebuilt, tzdata i narzędzia buildu Pythona, na przykład hatchling i setuptools_scm

Żaden z nich nie jest zainstalowany w obrazie, ale wszystkie leżą na ścieżce krytycznej buildu: przejęte narzędzie hosta lub akcja mogą przejąć Państwa obraz, nigdy nie będąc jego częścią. CRACI je wymienia, ponieważ widzi ruch wchodzący do buildu.

Ile kosztuje wbudowany SBOM

Generowanie SBOM w Yocto nie jest darmowe. Na tym samym runnerze z 32 vCPU build z tą funkcją trwał 155 min 40 s i zapisał SBOM jako 1,632 osobnych plików SPDX. Build bez niej, z rejestrowaniem przez CRACI, trwał 88 min 48 s. Przy stawce CRACI $0.002 za vCPU-minutę to około $9.96 wobec $5.68 za build, nie licząc czasu, który Państwa zespół spędza na czekaniu.

W porównaniu z runnerami hostowanymi przez GitHub różnica jest większa. CRACI wykonuje buildy około dwa razy szybciej dzięki szybszemu sprzętowi, krótszemu czasowi oczekiwania w kolejce i cache, więc ten sam build z SBOM Yocto na runnerze hostowanym przez GitHub z 32 rdzeniami ARM64 trwałby około 5 h 11 min. Przy $0.050 za minutę to $15.60. Build w CRACI kosztuje $5.68: o 64% mniej, czyli około 2,7 raza taniej. Cennik GitHub według stanu na wrzesień 2026; minuty wliczone w plan nie obejmują większych runnerów.

Wynik SPDX z Yocto zawiera jednak informacje, których CRACI nie rejestruje, takie jak łatki nakładane przez recepturę i CVE oznaczone w niej jako naprawione. Jeśli Państwa proces od nich zależy, warto pozostawić create-spdx włączone i korzystać z SBOM z CRACI równolegle. Jeśli nie, SBOM z CRACI sam obejmuje każdy komponent z SBOM Yocto, a nawet więcej.

Dlaczego ma to znaczenie dla bezpieczeństwa łańcucha dostaw

To, co trafia do buildu, decyduje o tym, co z niego wychodzi, niezależnie od tego, czy jest zainstalowane w obrazie. Atakujący o tym wiedzą, a to właśnie przez build wchodziły ostatnie ataki na łańcuch dostaw:

  • Ataki ukrywają się w buildzie. Backdoor w xz utils (CVE-2024-3094) występował w wersjach 5.6.0 i 5.6.1. Jego wyzwalacz znajdował się w archiwach tarball wydania, a nie w repozytorium Git, a złośliwy kod trafiał do biblioteki w trakcie jej budowania. Czytanie kodu źródłowego tego nie ujawniło; ujawnia to wiedza o tym, który dokładnie tarball pobrał build.
  • Zależności CI też są celem. W marcu 2025 r. CISA poinformowała, że każda wersja akcji GitHub tj-actions/changed-files była przejęta przez trzy dni. Akcja działa wewnątrz zadania buildu, dlatego CRACI wymienia akcje użyte przez Państwa workflow, przypięte do commita, który został uruchomiony.
  • Crate'y Rust znikają w plikach binarnych. Cargo kompiluje crate'y do programów, które z nich korzystają, więc podatny crate trafia do obrazu, nigdy nie pojawiając się jako pakiet. Jeśli SBOM wymienia go tylko z nazwy pliku, narzędzia do podatności również nie mogą go dopasować. Skanowanie gotowego pliku binarnego po fakcie musi zgadywać, co do niego trafiło; rejestrowanie buildu nie musi.
  • Nie można reagować na to, czego się nie widzi. Gdy pojawia się komunikat bezpieczeństwa dla crate'a lub narzędzia buildu, trzeba wiedzieć, które buildy z niego korzystały. CRACI przechowuje SBOM każdego buildu i pokazuje, które buildy zawierały podatną zależność, bezpośrednią lub przechodnią, więc wiedzą Państwo, w jakim okresie byli narażeni. Działa to tylko wtedy, gdy każdy komponent ma package URL, do którego można go dopasować.
  • Build powinien sięgać tylko tam, gdzie musi. Polityka ruchu wychodzącego CRACI blokuje połączenia z hostami, których build nie potrzebuje, więc przejęta zależność, która próbuje wysłać Państwa sekrety na serwer atakującego, zostaje zatrzymana, nawet w ataku, którego nikt wcześniej nie widział.

Klienci i regulacje, takie jak Cyber Resilience Act, również wymagają od producentów urządzeń podłączonych do sieci wiedzy o tym, co trafia do ich produktów. SBOM obejmujący cały build to dowód, który się obroni, gdy o to zapytają.

Pełne porównanie

Listy komponentów stojące za tymi liczbami, oba SBOM-y oraz opis tego, jak je zbudowaliśmy i porównaliśmy.

  • 88 komponentów znalezionych tylko przez CRACI i 865 wymienionych w obu SBOM-ach
  • Jak każdy SBOM identyfikuje 653 wersje crate'ów Rust
  • Oba pliki SBOM: CycloneDX z CRACI i SPDX z Yocto
  • Konfiguracja buildu, rozmiar runnera i czasy

Dlaczego buildy Yocto trudno uruchamiać w CI

Pełny build obrazu kompiluje ze źródeł toolchain, jądro i setki pakietów. Na standardowych runnerach z 2 rdzeniami, które oferuje większość usług CI, może to trwać godzinami, dlatego wiele zespołów embedded trzyma dedykowany serwer buildów pod biurkiem lub w szafie serwerowej, a ten serwer staje się kolejną maszyną do łatania, tworzenia kopii zapasowych i tłumaczenia audytorowi.

Build Yocto pobiera też bardzo dużo: archiwa źródeł, repozytoria Git i łatki z projektów upstream i mirrorów. To właśnie te pobrania musi uwzględniać Państwa SBOM i to o nich, zgodnie z regulacjami takimi jak Cyber Resilience Act, producenci urządzeń podłączonych do sieci muszą wiedzieć i je śledzić.

Co CRACI daje buildom Yocto

Runnery dopasowane do BitBake

Runnery CRACI skalują się od 1 do 32 jednostek obliczeniowych, gdzie każda jednostka to 1 vCPU i 3 GB RAM. Build Yocto może zażądać największego rozmiaru, 32 vCPU i 96 GB RAM, bezpośrednio z workflow. Zadania działają w izolowanych maszynach wirtualnych, a uruchomienia nadal pojawiają się w GitHub jak każde inne zadanie Actions.

Minuty są naliczane co do sekundy i rozliczane za vCPU-minutę, więc duży runner kosztuje więcej za minutę i kończy szybciej. Aktualne stawki podaje cennik.

Dostęp do sieci, o którym decydują Państwo

BitBake już teraz może ograniczyć swój fetcher do listy hostów za pomocą BB_ALLOWED_NETWORKS. CRACI dodaje drugą kontrolę na runnerze: politykę ruchu wychodzącego, sprawdzaną przed startem zadania i blokującą ruch w razie awarii (fail closed), więc receptura, skrypt lub przejęte narzędzie, które omija fetcher, nadal nie dotrze do hosta, na który Państwo nie zezwolili. CRACI wysyła alerty o naruszeniach polityki.

Zapis tego, co pobrał build

CRACI obserwuje ruch, który zadanie wysyła do hostów pakietów i źródeł, i rejestruje go jako dowód z buildu. Dla buildu Yocto oznacza to niezależny zapis źródeł, które faktycznie przyszły przez sieć, obok SBOM, który Yocto zapisuje sam.

Minimalny workflow

Przykład Yocto w dokumentacji CRACI buduje core-image-sato dla qemux86-64. Z punktu widzenia CRACI liczą się rozmiar runnera i konfiguracja fetchera korzystająca z oficjalnego mirrora źródeł Yocto:

jobs:
  build:
    runs-on: craci
    steps:
      - uses: cracicorp/setup@v1
        with:
          size: "32"
      # install the host packages from the Yocto quick start, then:
      - run: |
          echo 'SOURCE_MIRROR_URL = "https://downloads.yoctoproject.org/mirror/sources/"' >> conf/local.conf
          echo 'BB_ALLOWED_NETWORKS = "downloads.yoctoproject.org"' >> conf/local.conf
          bitbake core-image-sato

Przewodnik w dokumentacji zawiera pełny workflow, łącznie z zależnościami hosta i konfiguracją ustawień regionalnych, a dokumentacja konfiguracji runnera wymienia wszystkie opcje.

Warto wiedzieć

  • Buildy działają na zarządzanych runnerach CRACI na europejskiej infrastrukturze, uruchamiane z GitHub Actions. Runnery hostowane przez klienta i inne systemy CI są w planach rozwoju.
  • Warto kierować BitBake do mirrorów, które CRACI widzi, takich jak oficjalny mirror źródeł Yocto, a nie do dowolnych hostów. Przewodnik w dokumentacji pokazuje działającą konfigurację.
  • Zachowywanie katalogu pobrań i cache shared state między uruchomieniami sprawia, że kolejne buildy są szybkie.
  • Natywne runnery ARM64 są dostępne według tej samej stawki co x86-64.

Budują Państwo urządzenia podłączone do sieci na rynek UE? Proszę przeczytać, czego wymaga CRA, i jak CRACI działa w przemysłowym IoT i elektronice użytkowej. Porównują Państwo narzędzia SBOM dla Yocto? Zob. CRACI a Timesys Vigiles.

SBOM-y Yocto i CRACI: najczęściej zadawane pytania

Czy Yocto generuje SBOM?

Tak. Od Yocto 4.3 (Nanbield) system buildu OpenEmbedded domyślnie generuje SBOM w formacie SPDX za pomocą klasy create-spdx. Dla obrazu zapisuje plik IMAGE-MACHINE.spdx.json w katalogu tmp/deploy/images/MACHINE/, obejmujący komponenty, licencje, zależności, źródła, nałożone łatki i naprawione podatności. W Kirkstone (4.0) trzeba go włączyć, dodając INHERIT += "create-spdx".

Którą wersję SPDX generuje Yocto?

Od Yocto 5.1 (Styhead) domyślnie SPDX 3.0, która zastąpiła jako domyślną wersję 2.2. Scarthgap (5.0) domyślnie generuje SPDX 2.2, a na 3.0 można przejść za pomocą klasy create-spdx-3.0.

Jak uzyskać z Yocto SBOM w formacie CycloneDX?

Należy dodać warstwę meta-cyclonedx z gałęzi odpowiadającej Państwa wydaniu i dziedziczyć cyclonedx-export w local.conf. Obok obrazu powstaje wtedy SBOM .cyclonedx.bom.json i plik .cyclonedx.vex.json, domyślnie w formacie CycloneDX 1.6.

Czego brakuje w SBOM z Yocto?

W porównaniu buildów core-image-sato zarejestrowany przez CRACI SBOM zawierał wszystkie 865 komponentów z SBOM Yocto i 88 kolejnych: pakiety hosta na maszynie buildu, takie jak cpio z Ubuntu, źródła i akcje z GitHub oraz inne źródła pobrane w trakcie buildu. Yocto wymienia też 653 wersje crate'ów Rust tylko z nazwy pliku i adresu URL pobierania, bez package URL, na którym opiera się dopasowywanie podatności.

Czy można monitorować podatności w buildzie Yocto?

Tak, z CRACI. Dopasowywanie podatności działa na podstawie package URL, a wbudowany SBOM Yocto wymienia crate'y Rust tylko z nazwy pliku i adresu URL pobierania, więc nie da się ich dopasować. CRACI rejestruje crate'y Rust i pakiety maszyny buildu z package URL, względem których publikowane są komunikaty bezpieczeństwa (pkg:cargo, pkg:deb), łącznie ze wszystkimi 653 wersjami crate'ów w core-image-sato. Pokazuje status podatności każdego pakietu i na bieżąco ponownie ocenia SBOM w miarę publikowania nowych komunikatów.

Czy CRACI może zastąpić SBOM z Yocto?

Pod względem pokrycia łańcucha dostaw tak. W tym samym porównaniu SBOM z CRACI zawierał każdy komponent z wbudowanego SBOM Yocto, 88 dodatkowych i package URL dla każdego crate'a Rust, a build bez generowania SBOM przez Yocto trwał o 43% krócej. Wynik SPDX z Yocto nadal zawiera metadane receptur, których CRACI nie rejestruje, takie jak nałożone łatki i CVE oznaczone w recepturze jako naprawione. Jeśli Państwo na nich polegają, warto pozostawić create-spdx włączone.

Czy runner CRACI poradzi sobie z pełnym buildem obrazu Yocto?

Runnery CRACI mają do 32 vCPU i 96 GB RAM, a rozmiar ustawia się w workflow. Dokumentacja CRACI zawiera przykład Yocto, który buduje core-image-sato na największym rozmiarze.

Z jakiego CI korzysta build Yocto w CRACI?

Z GitHub Actions. Państwa workflow działa na zarządzanych runnerach CRACI, a uruchomienia pojawiają się w GitHub jak każde inne zadanie Actions. Inne systemy CI i runnery hostowane przez klienta są w planach rozwoju.

Proszę przynieść build Yocto na demo

Prosimy umówić demo: uruchomimy jeden z Państwa buildów BitBake na runnerze CRACI i omówimy, co pobrał.

Umów demo