2026년 하루 평균 보고된 CVE가 전년 대비 131% 증가했습니다.

Yocto

Yocto SBOM과 CRACI 빌드

Yocto는 모든 이미지에 대해 상세한 SPDX SBOM을 작성할 수 있습니다. 나란히 빌드해 비교한 결과, CRACI가 기록한 SBOM에는 Yocto SBOM의 모든 구성 요소와 Yocto가 놓친 88개가 포함되었고, Yocto가 패키지 URL 없이 나열한 Rust 크레이트 653개 모두에 패키지 URL이 있었으며, 빌드 시간은 43% 짧았습니다.

업데이트

나란히 빌드한 결과: core-image-sato

나열된 구성 요소: CRACI SBOM에 10% 더 많음

CRACI SBOM
953
Yocto SBOM
865

호스트 패키지, GitHub Actions 등 Yocto SBOM이 놓친 구성 요소 88개, Yocto SBOM에만 있는 항목은 없음

취약점을 확인할 수 있도록 패키지 URL이 있는 Rust 크레이트

CRACI SBOM
653
Yocto SBOM
0

둘 다 같은 653개를 나열하지만, Yocto는 파일 이름과 다운로드 URL로만 나열

빌드 시간과 빌드당 비용, 32 vCPU ARM64

CRACI
1 h 29 min $5.68
CRACI + Yocto SBOM
2 h 36 min $9.96
GitHub + Yocto SBOM*
5 h 11 min $15.60
43% 비용 절감: CRACI 대 CRACI + Yocto SBOM
64% 비용 절감: CRACI 대 GitHub + Yocto SBOM*

*분당 $0.050인 GitHub 호스팅 32코어 ARM64 러너 기준 추정치이며, CRACI가 약 2배 빠르다고 가정했습니다.

전체 비교 자료 받기 ↓

Yocto로 SBOM을 생성하는 방법

OpenEmbedded 빌드 시스템은 create-spdx 클래스를 통해 SPDX SBOM을 작성합니다. 활성화 여부와 작성되는 SPDX 버전은 Yocto 릴리스에 따라 다릅니다.

  • Kirkstone(4.0): 기본적으로 꺼져 있습니다. INHERIT += "create-spdx"를 추가하세요. SPDX 2.2.
  • Nanbield(4.3): 이 릴리스부터 SBOM 생성이 기본적으로 켜져 있습니다.
  • Scarthgap(5.0): 기본적으로 켜져 있으며 SPDX 2.2입니다. SPDX 3.0은 create-spdx-3.0 클래스로 사용할 수 있습니다.
  • Styhead(5.1) 이후: 기본적으로 켜져 있으며 SPDX 3.0입니다.

conf/local.conf 같은 구성 파일에서 설정합니다. 최신 릴리스에서는 대개 추가할 것이 없으며, 끄려면 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"

다른 SPDX_ 변수로 세부 정보를 추가할 수 있습니다. SPDX_INCLUDE_SOURCES는 각 호스트 도구와 대상 패키지의 바탕이 되는 소스 파일을 기술하며, 출력이 훨씬 커집니다. 최근 릴리스에는 커널 구성, PACKAGECONFIG 기능, 공급업체 정보, 그리고 Cargo, Go, PyPI, npm, CPAN 소스의 패키지 URL을 위한 옵션이 추가되었습니다.

SBOM 파일이 생성되는 위치

이미지를 빌드하면 최상위 SBOM이 IMAGE-MACHINE.spdx.json이라는 이름으로 이미지 옆, 즉 빌드 디렉터리 안의 tmp/deploy/images/MACHINE/에 생성됩니다. 관련 파일은 같은 디렉터리와 tmp/deploy/spdx에 있습니다. Kirkstone에서는 레시피별 문서가 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

meta-cyclonedx로 CycloneDX 생성

Yocto 자체는 SPDX만 작성합니다. CycloneDX가 필요하면 meta-cyclonedx 레이어가 이미지의 루트 파일 시스템에서 SBOM을 생성하고, 빌드 시스템이 알고 있는 패치된 CVE와 무시된 CVE를 담은 별도의 VEX 파일도 만듭니다. 사용 중인 릴리스에 맞는 레이어 브랜치를 체크아웃하고, 레이어에 추가한 뒤 클래스를 상속하세요.

# 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"

파일은 이미지 옆 DEPLOY_DIR_IMAGE에 .cyclonedx.bom.json과 .cyclonedx.vex.json 접미사로 생성됩니다. 기본값은 CycloneDX 1.6이며 CYCLONEDX_SPEC_VERSION으로 설정합니다. 기본적으로 런타임 패키지만 포함되므로 SBOM은 작아지지만, 패키지로 설치되지 않고 이미지에 들어가는 구성 요소는 빠질 수 있습니다.

Yocto SBOM이 놓치는 것

Yocto의 SBOM은 BitBake가 빌드하는 대상에 대해서는 철저합니다. SPDX 3에서는 이미지, 빌드 시점 네이티브 레시피를 포함한 모든 레시피, 그 소스, 적용된 패치, 수정됨으로 표시된 취약점을 다룹니다. core-image-sato의 경우 별도 파일 1,632개에 달했습니다. 무엇이 빠지는지 확인하기 위해 32 vCPU 네이티브 ARM64 CRACI 러너에서 이미지를 빌드하고, 모든 파일에 걸쳐 이름을 정규화한 뒤 Yocto의 SBOM과 CRACI가 기록한 SBOM을 구성 요소 단위로 비교했습니다.

CRACI SBOM의 구성 요소 953개 중 865개가 Yocto SBOM에도 있었습니다. Yocto SBOM에만 있는 구성 요소는 없었습니다. 차이는 Yocto가 볼 수 없는 부분과, Yocto가 나열하는 항목을 식별하는 방식에 있습니다.

패키지 URL이 없는 Rust 크레이트

두 SBOM 모두 cairo-rs, zune-jpeg 등 Rust 크레이트 559개의 같은 버전 653개를 담고 있으며, 이 크레이트들은 librsvg가 컴파일해 포함합니다. Yocto는 각 크레이트를 이를 사용하는 레시피 안에서 .crate 파일과 crates.io 다운로드 URL로만 나열합니다. pkg:cargo 패키지 URL이 있는 항목은 하나도 없습니다. CRACI는 모든 크레이트를 패키지 URL과 함께 기록합니다.

이것이 취약점 모니터링 가능 여부를 결정합니다. 취약점 매칭은 패키지 URL을 기준으로 이루어집니다. 크레이트에 대한 권고는 이를 pkg:cargo/...로 지칭하는데, 다른 레시피의 소스 목록 안에 있는 파일 이름만으로는 SBOM 및 취약점 도구가 대조할 대상이 없습니다. Yocto의 SBOM만 사용하면 이미지에 포함된 취약한 크레이트는 보고되지 않습니다.

CRACI의 SBOM을 사용하면 모든 크레이트가 권고와 대조되고, 빌드의 각 패키지에 취약점 상태가 표시되며, 빌드가 끝난 지 오래 지나도 새로운 권고가 게시될 때마다 CRACI가 SBOM을 계속 재평가합니다.

CRACI만 찾아낸 것

Yocto SBOM에 빠진 구성 요소 88개는 BitBake 메타데이터 밖에서 왔습니다.

  • Ubuntu의 cpio 2.15, libc6, locales, python3-jinja2 등 빌드 머신에 설치된 호스트 패키지 23개. BitBake는 이를 사용해 실행되지만, Yocto의 SBOM에는 나열되지 않습니다.
  • patchelf, btrfs-progs, GitHub Action actions/upload-artifact 등 워크플로가 실행한 커밋에 고정된 GitHub 소스 10개
  • pseudo-prebuilt, tzdata, 그리고 hatchling, setuptools_scm 같은 Python 빌드 도구 등 빌드 중에 가져온 기타 소스와 도구

이들 중 어느 것도 이미지에 설치되지 않지만, 모두 빌드의 핵심 경로에 있습니다. 침해된 호스트 도구나 Action은 이미지의 일부가 되지 않고도 이미지를 침해할 수 있습니다. CRACI는 빌드로 들어오는 트래픽을 보기 때문에 이들을 나열합니다.

기본 SBOM 생성의 비용

Yocto의 SBOM 생성은 공짜가 아닙니다. 같은 32 vCPU 러너에서 SBOM 생성을 켠 빌드는 155 min 40 s 걸렸고, SBOM을 별도의 SPDX 파일 1,632개로 작성했습니다. SBOM 생성을 끄고 CRACI가 기록한 빌드는 88 min 48 s 걸렸습니다. CRACI의 요금인 vCPU 분당 $0.002로 계산하면 빌드당 약 $9.96 대 $5.68이며, 팀이 기다리는 시간은 포함하지 않은 금액입니다.

GitHub 호스팅 러너와 비교하면 격차는 더 커집니다. CRACI는 더 빠른 하드웨어, 더 짧은 대기 시간, 캐싱 덕분에 빌드를 약 2배 빠르게 실행하므로, Yocto SBOM을 켠 같은 빌드를 GitHub 호스팅 32코어 ARM64 러너에서 실행하면 약 5 h 11 min 걸립니다. 분당 $0.050으로 계산하면 $15.60입니다. CRACI 빌드 비용은 $5.68로, 64% 적으며 약 2.7배 저렴합니다. GitHub 정가는 2026년 9월 기준이며 포함 사용량을 반영하기 전 금액입니다.

Yocto의 SPDX 출력에는 레시피가 적용하는 패치나 수정됨으로 표시한 CVE처럼 CRACI가 기록하지 않는 정보가 있습니다. 프로세스가 이에 의존한다면 create-spdx를 켜 두고 CRACI의 SBOM을 함께 사용하세요. 그렇지 않다면 CRACI의 SBOM만으로 Yocto SBOM의 모든 구성 요소와 그 이상을 다룹니다.

공급망 보안에서 이것이 중요한 이유

빌드에 들어가는 것이 빌드에서 나오는 것을 결정하며, 이는 이미지에 설치되는지와 관계없습니다. 공격자도 이를 알고 있으며, 최근의 공급망 공격은 빌드를 통해 침투했습니다.

  • 공격은 빌드 안에 숨습니다. xz utils 백도어(CVE-2024-3094)는 5.6.0과 5.6.1 버전에 있었습니다. 트리거는 Git 리포지토리가 아니라 릴리스 tarball에 있었고, 악성 코드는 라이브러리가 빌드되는 동안 들어갔습니다. 소스를 읽어서는 드러나지 않았지만, 빌드가 정확히 어떤 tarball을 가져왔는지 알면 드러납니다.
  • CI 종속성도 표적입니다. 2025년 3월 CISA는 GitHub Action tj-actions/changed-files의 모든 버전이 3일 동안 침해되었다고 보고했습니다. Action은 빌드 작업 안에서 실행되므로, CRACI는 워크플로가 사용한 Action을 실행된 커밋에 고정해 나열합니다.
  • Rust 크레이트는 바이너리 속으로 사라집니다. Cargo는 크레이트를 이를 사용하는 프로그램에 컴파일해 넣으므로, 취약한 크레이트는 패키지로 나타나지 않은 채 이미지에 포함되어 출시됩니다. SBOM이 이를 파일 이름으로만 나열하면 취약점 도구도 매칭할 수 없습니다. 완성된 바이너리를 사후에 스캔하면 무엇이 들어갔는지 추측해야 하지만, 빌드를 기록하면 그럴 필요가 없습니다.
  • 보이지 않는 것에는 대응할 수 없습니다. 크레이트나 빌드 도구에 대한 권고가 나오면 어떤 빌드가 이를 사용했는지 알아야 합니다. CRACI는 모든 빌드의 SBOM을 보관하고, 직접이든 전이적이든 취약한 종속성이 포함된 빌드를 보여 주므로 영향을 받은 기간을 알 수 있습니다. 이는 모든 구성 요소에 매칭할 패키지 URL이 있을 때에만 가능합니다.
  • 빌드는 필요한 곳에만 접속해야 합니다. CRACI의 이그레스 정책은 빌드에 필요 없는 호스트로의 연결을 차단하므로, 시크릿을 공격자의 서버로 보내려는 침해된 종속성은 아무도 본 적 없는 공격이라도 차단됩니다.

고객과 Cyber Resilience Act 같은 규정도 커넥티드 기기 제조사에 제품에 무엇이 들어가는지 파악하도록 요구합니다. 빌드 전체를 다루는 SBOM은 그러한 요구에 대응할 수 있는 증거가 됩니다.

전체 비교 자료 받기

이 수치의 바탕이 된 구성 요소 목록, 두 SBOM 파일, 그리고 빌드 및 비교 방법을 담았습니다.

  • CRACI만 찾아낸 구성 요소 88개와 두 SBOM 모두에 나열된 865개
  • 각 SBOM이 Rust 크레이트 버전 653개를 식별하는 방식
  • 두 SBOM 파일: CRACI의 CycloneDX와 Yocto의 SPDX
  • 빌드 구성, 러너 크기, 소요 시간

Yocto 빌드를 CI에서 실행하기 어려운 이유

전체 이미지 빌드는 툴체인, 커널, 수백 개의 패키지를 소스에서 컴파일합니다. 대부분의 CI 서비스가 제공하는 표준 2코어 러너에서는 몇 시간이 걸릴 수 있어, 많은 임베디드 팀이 책상 아래나 랙에 전용 빌드 서버를 둡니다. 그 서버는 패치하고, 백업하고, 감사인에게 설명해야 하는 머신이 하나 더 늘어나는 셈입니다.

Yocto 빌드는 업스트림 프로젝트와 미러에서 소스 tarball, Git 리포지토리, 패치 등 많은 것을 내려받습니다. SBOM이 설명해야 하는 것이 바로 이 다운로드이며, Cyber Resilience Act 같은 규정이 커넥티드 기기 제조사에 파악하고 추적하도록 요구하는 것도 이것입니다.

CRACI가 Yocto 빌드에 제공하는 것

BitBake에 맞는 크기의 러너

CRACI 러너는 1~32 컴퓨팅 유닛으로 확장되며, 각 유닛은 1 vCPU와 3GB RAM입니다. Yocto 빌드는 워크플로에서 직접 가장 큰 크기인 32 vCPU와 96GB RAM을 요청할 수 있습니다. 작업은 격리된 가상 머신에서 실행되며, 실행 결과는 다른 Actions 작업과 마찬가지로 GitHub에 표시됩니다.

사용 시간은 초 단위로 측정되고 vCPU 분 단위로 청구되므로, 큰 러너는 분당 비용이 더 높지만 더 빨리 끝납니다. 현재 요율은 요금을 참조하세요.

직접 정하는 네트워크 접근

BitBake는 이미 BB_ALLOWED_NETWORKS로 페처를 호스트 목록으로 제한할 수 있습니다. CRACI는 러너에 두 번째 통제 수단을 더합니다. 작업 시작 전에 검사되며 실패 시 차단(fail closed) 방식으로 동작하는 이그레스 정책으로, 페처를 우회하는 레시피, 스크립트, 침해된 도구도 허용하지 않은 호스트에는 접속할 수 없습니다. CRACI는 정책 위반 시 알림을 보냅니다.

빌드가 가져온 항목의 기록

CRACI는 작업이 패키지 및 소스 호스트로 보내는 트래픽을 관찰하고 이를 빌드 증거로 기록합니다. Yocto 빌드의 경우 Yocto가 직접 작성하는 SBOM과 별도로, 실제로 네트워크를 통해 들어온 소스에 대한 독립적인 기록을 얻게 됩니다.

최소 워크플로

CRACI 문서의 Yocto 예시는 core-image-sato를 qemux86-64용으로 빌드합니다. CRACI에서 중요한 부분은 러너 크기와, 공식 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

문서 가이드에는 호스트 종속성과 로캘 설정을 포함한 전체 워크플로가 있으며, 러너 구성 레퍼런스에는 모든 설정 옵션이 나와 있습니다.

알아 두어야 할 사항

  • 빌드는 GitHub Actions에서 유럽 인프라의 CRACI 관리형 러너로 실행됩니다. 고객 호스팅 러너와 다른 CI 시스템은 로드맵에 있습니다.
  • BitBake가 임의의 호스트가 아니라 공식 Yocto 소스 미러처럼 CRACI가 볼 수 있는 미러를 사용하도록 설정하세요. 문서 가이드에 작동하는 설정이 나와 있습니다.
  • 다운로드 디렉터리와 공유 상태 캐시를 실행 간에 유지하면 반복 빌드가 빨라집니다.
  • 네이티브 ARM64 러너를 x86-64와 같은 요율로 사용할 수 있습니다.

EU 시장용 커넥티드 기기를 개발하고 계신가요? CRA가 요구하는 사항과 산업용 IoT 및 소비자 가전 분야에서 CRACI가 어떻게 작동하는지 읽어 보세요. Black Duck을 사용하고 계신가요? Black Duck의 BitBake 디텍터가 어떻게 다른지 읽어 보세요. Yocto SBOM 도구를 비교하고 계신가요? 참고: CRACI vs Timesys Vigiles.

Yocto SBOM과 CRACI: 자주 묻는 질문

Yocto는 SBOM을 생성합니까?

생성합니다. OpenEmbedded 빌드 시스템은 Yocto 4.3(Nanbield)부터 create-spdx 클래스를 통해 기본적으로 SPDX SBOM을 생성합니다. 이미지의 경우 IMAGE-MACHINE.spdx.json을 tmp/deploy/images/MACHINE/에 기록하며, 구성 요소, 라이선스, 종속성, 소스, 적용된 패치, 수정된 취약점을 담습니다. Kirkstone(4.0)에서는 INHERIT += "create-spdx"를 추가해 활성화합니다.

Yocto는 어떤 SPDX 버전을 생성합니까?

Yocto 5.1(Styhead)부터는 기본값이 2.2에서 SPDX 3.0으로 바뀌었습니다. Scarthgap(5.0)은 기본적으로 SPDX 2.2를 생성하며, create-spdx-3.0 클래스로 3.0으로 전환할 수 있습니다.

Yocto에서 CycloneDX SBOM을 얻으려면 어떻게 해야 합니까?

사용 중인 릴리스에 맞는 브랜치의 meta-cyclonedx 레이어를 추가하고 cyclonedx-export를 local.conf에서 상속하세요. 이미지 옆에 .cyclonedx.bom.json SBOM과 .cyclonedx.vex.json 파일이 기본적으로 CycloneDX 1.6 형식으로 생성됩니다.

Yocto SBOM은 무엇을 놓칩니까?

core-image-sato를 나란히 빌드해 비교한 결과, CRACI가 기록한 SBOM에는 Yocto SBOM의 구성 요소 865개가 모두 포함되었고 88개가 더 있었습니다. Ubuntu의 cpio 같은 빌드 머신의 호스트 패키지, GitHub 소스와 Actions, 빌드 중에 가져온 기타 소스입니다. 또한 Yocto는 653개의 Rust 크레이트 버전을 파일 이름과 다운로드 URL로만 나열하며, 취약점 매칭에 필요한 패키지 URL은 없습니다. 범용 스캐너가 더 많이 놓치는 이유는 SBOM 스캐너가 Yocto 빌드의 구성 요소를 놓치는 이유를 참고하세요.

Yocto 빌드의 취약점을 모니터링할 수 있습니까?

CRACI로 가능합니다. 취약점 매칭은 패키지 URL을 기준으로 이루어지는데, Yocto의 기본 SBOM은 Rust 크레이트를 파일 이름과 다운로드 URL로만 나열하므로 매칭할 수 없습니다. CRACI는 Rust 크레이트와 빌드 머신의 패키지를 권고가 게시되는 패키지 URL(pkg:cargo, pkg:deb)과 함께 기록하며, core-image-sato의 크레이트 버전 653개도 모두 포함됩니다. 각 패키지의 취약점 상태를 보여 주고, 새로운 권고가 게시될 때마다 SBOM을 계속 재평가합니다.

CRACI가 Yocto SBOM을 대체할 수 있습니까?

공급망 커버리지 측면에서는 가능합니다. 같은 비교에서 CRACI의 SBOM에는 Yocto 기본 SBOM의 모든 구성 요소와 88개의 추가 구성 요소가 있었고, 모든 Rust 크레이트에 패키지 URL이 있었으며, Yocto SBOM 생성 없이 실행한 빌드는 시간이 43% 덜 걸렸습니다. 다만 Yocto의 SPDX 출력에는 적용된 패치나 레시피가 수정됨으로 표시한 CVE처럼 CRACI가 기록하지 않는 레시피 메타데이터가 있습니다. 이에 의존한다면 create-spdx를 켜 두세요.

CRACI 러너로 전체 Yocto 이미지 빌드를 처리할 수 있습니까?

CRACI 러너는 워크플로에서 설정해 최대 32 vCPU와 96GB RAM까지 사용할 수 있습니다. CRACI 문서에는 가장 큰 크기로 core-image-sato를 빌드하는 Yocto 예시가 있습니다.

CRACI에서 Yocto 빌드는 어떤 CI를 사용합니까?

GitHub Actions를 사용합니다. 워크플로는 CRACI의 관리형 러너에서 실행되며, 실행 결과는 다른 Actions 작업과 마찬가지로 GitHub에 표시됩니다. 다른 CI 시스템과 고객 호스팅 러너는 로드맵에 있습니다.

데모에 Yocto 빌드를 가져오세요

데모를 예약하시면 BitBake 빌드 하나를 CRACI 러너에서 실행하고, 빌드가 가져온 항목을 함께 살펴봅니다.

데모 예약