콘텐츠로 이동

공급사 SBOM 검증 가이드

협력사나 다른 팀에서 받은 SBOM(JSON)이 요구사항을 충족하는지 검증하는 방법을 설명합니다. 검증에 이어 라이선스와 취약점을 분석하고, 위험 보고서까지 만듭니다. 소스 코드가 없어도 SBOM 파일 하나만 있으면 됩니다.

언제 쓰나

협력사나 다른 팀이 소스 대신 SBOM 파일을 전달했고, 그 SBOM이 품질 기준을 갖췄는지 확인한 뒤 라이선스와 취약점을 점검해야 할 때 씁니다. 입력은 CycloneDX(JSON, XML)와 SPDX(JSON, Tag-Value) 모두 가능하며, 내부에서 CycloneDX로 변환해 분석합니다. SPDX RDF/XML은 아직 지원하지 않습니다.

BomLens는 SK텔레콤의 공급사 SBOM 제출을 위해 만든 도구이며, 아래 표는 그 요구사항을 따릅니다. 검증 기준은 SBOM이 의존성 점검에 쓸 만한 품질을 갖췄는지를 보는 항목들입니다. 조직마다 요구사항이 다를 수 있으니, 참고 사례로 SK텔레콤 공급망 보안 가이드의 SBOM 요구사항을 둘 수 있습니다.

구분 기준
포맷 CycloneDX v1.3~1.7 또는 SPDX v2.2~2.3
필수 메타데이터 timestamp, 생성 도구 정보, 최상위 컴포넌트 이름과 버전
필수 컴포넌트 필드 name, version, 표준 pkg:type/name@version 형식의 PURL. 타입이 요구하는 네임스페이스 포함(pkg:maven/<groupId>/<artifactId>, pkg:rpm/<배포판>/<이름>), purl-spec에 정의된 타입 사용, pkg:generic 금지
완전성 직접 의존성과 추이적(transitive) 의존성 모두 포함
권장 supplier, 라이선스(SPDX ID), hash

위 허용 포맷 범위는 SK텔레콤 제출 기준의 기본값입니다. 조직이 다른 범위를 허용한다면 CYCLONEDX_SPEC_VERSIONS, AI_CYCLONEDX_SPEC_VERSIONS(AI SBOM), SPDX_SPEC_VERSIONS 환경 변수(공백으로 구분한 목록)로 덮어쓸 수 있습니다. 목록은 Docker 이미지 환경 변수에 있습니다.

위 표의 pkg:generic 금지 항목은 도구 자체의 기본값이 아니라 skt-submission 적합성 검사 기준(--conformance-profile skt-submission)입니다. 기본 검사 기준은 pkg:generic을 권고 사항으로만 다루고 PURL 포함률도 100%가 아니라 90%를 기준으로 삼습니다. 웹 UI의 제출 전 점검 화면은 이미 skt-submission을 기본값으로 쓰지만 CLI는 그렇지 않으므로, 이 표 기준으로 검사하려면 플래그를 직접 붙여야 합니다.

한 번에 실행하기

웹 UI에서

웹 UI를 열고 SBOM 업로드를 골라 받은 파일을 올린 뒤, 프로젝트 이름과 버전을 입력하고 스캔을 실행합니다. Yocto SPDX 2.2 빌드는 문서가 아니라 <image>.spdx.tar.zst를 건네는데, 그 빌드가 만드는 유일한 SBOM이므로 이 아카이브도 그대로 올릴 수 있습니다.

Java(Maven) 비중이 큰 SBOM이라면 스캔 옵션에서 심층 CVE 매칭 (NVD CPE)을 켜세요. 오래된 Maven 라이브러리를 NVD 전용 취약점까지 대조해 다른 출처가 놓치는 항목을 찾아내며, 대신 스캔이 더 오래 걸립니다. CLI의 --deep-cve와 같은 매칭입니다. 어느 스캔 모드에서 이 옵션이 나타나는지, 처음 실행할 때 무엇을 내려받는지는 정밀 CVE 대조를 참고하세요.

./scripts/scan-sbom.sh --ui     # http://localhost:8080 이 열립니다
#   Windows: scripts\sbom-ui.bat 더블클릭

설치는 시작하기를 참고하세요.

CLI에서

명령줄 없이 하고 싶다면 비개발자 빠른 시작을 먼저 보세요. 아래는 CLI 기준입니다.

스캐너 이미지를 한 번 받아 두고(docker pull ghcr.io/sktelecom/bomlens:latest), 받은 SBOM 파일을 --analyze에 넘깁니다.

./scripts/scan-sbom.sh --project supplier-app --version 2.0.0 \
  --analyze "./supplier-sbom.json" \
  --conformance-profile skt-submission \
  --generate-only

--analyze는 고지문과 보안 분석을 자동으로 켜므로 --all을 따로 붙일 필요가 없습니다. --generate-only는 산출물만 현재 디렉터리 아래 {Project}_{Version}/ 하위 폴더에 남기고 임시 작업본은 정리합니다. 나머지 옵션은 CLI 레퍼런스를 참고하세요.

산출물 4종

산출물 파일 의미
적합성 검사 보고서 {Project}_{Version}_conformance.{json,md,html} 품질 기준 충족 여부와 누락 항목
SBOM(변환본) {Project}_{Version}_bom.json SPDX 입력은 CycloneDX 1.6으로 변환, CycloneDX 입력은 원본 spec 버전 유지
오픈소스 고지문 {Project}_{Version}_NOTICE.{txt,html} 라이선스별 구성요소 고지문
오픈소스 위험 보고서 {Project}_{Version}_risk-report.{md,html} 적합성·취약점·라이선스 종합과 대응 기한

자체 생성 스캔도 이제 기본으로 같은 적합성 검사 보고서 파일을 만듭니다(입력 시나리오별 처리 참고). 어느 쪽이든 그 요약은 오픈소스 위험 보고서 1절에 들어갑니다. 다만 아래에서 설명하는 판정 화면은 --analyze 경로에서만 나타납니다. 자기가 만든 SBOM이 자기를 채점하는 건 대부분의 검사 항목에서 의미 있는 신호가 아니기 때문입니다. 자체 생성한 SBOM을 화면으로 보려면 그 산출물을 다시 --analyze로 넣으세요.

적합성 검사 보고서 읽기

적합성 검사 보고서는 받은 SBOM이 품질 기준을 갖췄는지 항목별로 점검한 결과입니다. 검증은 변환 전 원본을 기준으로 하므로, SPDX를 넣어도 원본 SPDX의 필드를 그대로 확인합니다.

  • 필수 항목이 하나라도 미달이면 fail입니다. 필수 항목은 언제 쓰나의 기준 표와 같습니다. 스펙 버전 범위(CycloneDX v1.3~1.7, SPDX v2.2~2.3), timestamp, 도구 정보, 최상위 컴포넌트, name/version 커버리지, PURL 커버리지와 문법(표준 pkg:type/name@version 형식, pkg:generic 금지), 타입이 요구하는 PURL 네임스페이스, 추이적 의존성입니다.
  • 네임스페이스 검사는 OS 패키지뿐 아니라 purl-spec이 네임스페이스를 필수로 규정한 모든 타입을 봅니다. groupId가 빠진 pkg:maven 식별자나 배포판을 ?distro= 한정자로만 적은 pkg:rpm 식별자는 형식은 맞지만 어떤 패키지에도 연결되지 않습니다. pkg:golang과 pkg:huggingface는 네임스페이스가 없어도 올바른 식별자일 수 있어(Go 모듈 경로는 호스트 이름 하나일 수 있고, 조직 없이 공개된 모델에는 소유자 구간이 없습니다) 권고 항목으로 따로 보고합니다.
  • 최상위 구성요소 이름은 제품을 가리켜야 합니다. 일부 생성 도구는 제품명 대신 고정값(., .., /, 스캔한 디렉터리인 /scan)을 적고, 그러면 서로 다른 제품의 SBOM이 충돌합니다. skt-submission에서는 이 이름이 "Top-level component name+version" 행을 실패시키고, 기본 프로필에서는 경고합니다. 다른 제출물과 이름이 겹치는지는 접수 시스템이 판단할 일이라 이 검사로는 알 수 없습니다.
  • 검사하지 않는 것: 서버 납품에 OS 패키지가 들어 있는지, OS 패키지 purl이 실제 설치된 배포판을 가리키는지(RHEL 서버에 pkg:deb/debian/...이 붙어 있어도 형식이 맞아 통과합니다), 파일 기본 점검(확장자, 크기, JSON 문법)입니다. 이런 항목은 점검표로 확인하세요.
  • --resolve-purl을 붙이면 항목이 하나 더 붙습니다. 적합성 검사에서 네트워크를 쓰는 유일한 부분입니다. 식별자가 실제 있는 패키지를 가리키는지 각 패키지 저장소에 조회하는데, 형식 검사로는 볼 수 없는 것을 잡습니다. pkg:maven/org.drools/org.drools.drools-core-dynamic@…은 artifactId 안에 groupId가 한 번 더 들어갔고, pkg:maven/The%2BApache%2BSoftware%2BFoundation/poi@…은 groupId 자리에 회사 표시 이름이 들어갔습니다. 둘 다 형식은 맞지만 저장소에는 없습니다. 이 항목은 권고이며 판정을 바꾸지 않습니다. 사내 저장소에만 올린 패키지도 같은 결과가 나오기 때문입니다. 사내 네임스페이스는 PURL_RESOLVE_IGNORE로 제외하세요. 버전이 아니라 좌표만 확인합니다. 벤더가 다시 빌드한 버전은 정상이면서도 공개 저장소에 없기 때문입니다.
  • PURL 타입은 purl-spec에 정의된 타입인지 확인합니다. 표시용 이름에서 식별자를 되돌려 만드는 생성 도구는 규격에 없는 타입을 만들어 내기도 하는데(pkg:applications/java@11.0.25), 다른 검사 항목으로는 드러나지 않습니다. 기본 기준에서는 경고, skt-submission에서는 실패로 다룹니다. 타입 목록은 docker/lib/purl-types.json에 있습니다. skt-submission은 SourceForge나 GNU 사이트에 공개된 프로젝트의 릴리스를 가리키는 pkg:sourceforge와 pkg:gnu도 받아들입니다.
  • skt-submission에서는 무엇을 고칠지 알려 주는 항목 두 개가 더 붙습니다. "버전 보충 필요"는 필수 항목이며, 버전도 사유도 없는 컴포넌트가 있을 때만 실패합니다. 공급사가 버전 대신 사유(own-code, not-open-source, version-unknown)를 적은 컴포넌트는 .md와 .html 보고서의 "공급사 소명" 절(JSON에서는 explained)에 사유와 함께 나오며, 이 목록이 비어 있지 않아도 항목은 통과할 수 있습니다. --analyze에서는 공급사 SBOM의 bomlens:versionReason 속성으로 같은 목록을 보여 줍니다. "upstream purl 없음"은 버전은 있지만 소스 저장소를 가리키는 purl이 없는 컴포넌트 목록이며 경고로 나옵니다. 공급사가 고칠 항목이 아니고 제출을 막지 않으며, 해당 컴포넌트는 SK텔레콤이 따로 확인합니다. --analyze로 공급사 SBOM을 점검하면 "버전 보충 필요"는 공급사에 고친 SBOM을 요청하라고, "upstream purl 없음"은 최신 BomLens로 다시 스캔해 달라고 요청하라고 안내합니다. 공급사가 BomLens로 펌웨어, 루트 파일시스템, 바이너리를 스캔했다면 {Project}_{Version}_component-versions.template.csv에 버전이나 사유를 적고 --component-versions로 다시 스캔하며(펌웨어 가이드 참고), 스캔은 변환표가 다루는 프로젝트에 upstream purl을 붙입니다. BomLens가 직접 실행한 스캔이면 제출할 파일이 {Project}_{Version}_bom.json 하나라는 점도 요약에 적습니다.
  • 펌웨어, 루트 파일시스템, 바이너리, Yocto 빌드 디렉터리 스캔을 skt-submission으로 점검하면 일반 항목이 위 두 항목이 이미 다루는 컴포넌트 때문에 실패하지 않고, 경고로 바뀐 이유를 상세 내용에 적습니다. name/version 포함률은 버전이 없는 컴포넌트에 모두 사유가 있으면 경고입니다. PURL 포함률은 purl이 없는 컴포넌트가 모두 소명되었거나 버전이 있으면(그래서 "upstream purl 없음"에 나오면) 경고입니다. "추적 가능한 PURL (pkg:generic 없음)"은 pkg:generic 컴포넌트가 모두 버전이나 사유가 있는 패키지이면 경고입니다. 전이 의존성 항목도 경고입니다. 이런 스캔은 의존성 그래프가 아니라 찾은 패키지를 기록하기 때문입니다. 버전도 사유도 없는 컴포넌트가 하나라도 있거나 SBOM에 패키지가 하나도 없으면 이 항목들은 완화하지 않습니다. 이런 스캔은 metadata.properties에 bomlens:scanMode(FIRMWARE, ROOTFS, BINARY, YOCTO)를 기록하고, --analyze도 이 값이 있는 SBOM을 같은 방식으로 판정하며 그 사실을 보고서 요약에 적습니다. 소스 스캔과, --analyze로 점검하는 다른 SBOM(다른 도구로 만들었거나 이 값을 기록하기 전 BomLens 버전으로 만든 SBOM)은 이 항목들을 측정한 그대로 판정합니다. 기본 기준은 달라지지 않습니다.
  • 자체 빌드 산출물은 패키지 저장소에 없으므로 purl이 없습니다. 선언 파일(--components, 또는 스캔 루트의 sbom-declared.cdx.json)에 bomlens:origin을 first-party로 적고 공급자와 bomlens:artifact의 빌드 산출물(여기서 SHA-512를 얻음)을 함께 적은 구성요소는 PURL 포함률, "추적 가능한 PURL (pkg:generic 없음)", "upstream purl 없음" 항목에서 빠지고, 권고 항목 "purl 대신 공급자와 SHA-512로 식별한 자체개발 구성요소"에 이름이 표시됩니다. 이 예외는 선언 파일을 읽은 그 스캔에서만 적용됩니다. --analyze로 점검하는 SBOM에서 first-party로 표시된 구성요소와, 선언 파일의 third-party 구성요소에는 여전히 purl이 필요합니다.
  • 권장 항목이 미달이면 warn이며, fail로 보지는 않습니다. 라이선스와 hash 커버리지 외에, 규제 기준선이 요구하는 컴포넌트별 권고 필드도 여기에 포함됩니다 — SHA-512 체크섬 커버리지, 컴포넌트 작성 주체, 컴포넌트 파일명, 소스·배포 URI, 전달 파일 속성(스캔으로 확인할 수 없으면 검토 필요로 표시), 그리고 아래에서 설명하는 파일 구성요소 식별자 포함률.
  • name/version과 PURL 커버리지는 패키지 구성요소만을 대상으로 잽니다. 바이너리와 펌웨어 SBOM은 전달된 파일도 파일 구성요소로 함께 싣는데, 디스크 위의 파일에는 패키지 버전도 PURL 타입도 없습니다. 이런 파일을 분모에 넣으면 존재할 수 없는 필드를 두고 미달 판정을 내리게 됩니다. 그렇다고 파일을 식별에서 면제하지는 않고, 파일이 실제로 지니는 식별자인 해시를 파일 구성요소 식별자 검사가 확인합니다. 패키지 없이 파일만 실린 SBOM은 fail입니다. 취약점 매칭이 패키지 식별자를 키로 삼기 때문에 파일 목록만으로는 아무것도 답할 수 없습니다.
  • 2026년 최소 요소 중에는 필드가 비어 있을 때 그 이유를 밝히라는 항목이 있습니다. 값을 확인하지 못한 것인지, 알면서 공개하지 않은 것인지를 구분하라는 요구입니다. BomLens가 생성한 SBOM은 문서 전체에 대해 그 진술을 담습니다. 스캔은 확인하지 못하는 경우만 만들기 때문입니다. 받은 SBOM이 자기 공백에 대해 아무 말도 하지 않으면 이 항목은 공백으로 보고됩니다.
  • HTML 보고서 상단 카드에 적합/부적합과 누락 목록이 표시됩니다.
  • 규제 기준선과 대응되는 검사에는 행 아래에 참고 규정이 붙고, 크로스워크 절이 프레임워크별 충족 현황을 집계합니다 — BSI TR-03183-2(EU 사이버복원력법을 위한 독일 기술지침)와 미국 SBOM 최소 요소(2026년판)입니다. 크로스워크는 참고 자료이며 준수 판정을 하지 않습니다. 동작 방식은 AI 모델 SBOM 가이드에서 설명합니다.

fail이 나오면 SBOM을 보낸 쪽에 어떤 필드가 빠졌는지 알려 보완을 요청합니다. 가장 흔한 미충족 항목은 PURL 누락, pkg:generic 사용, 패키지 매니저가 아니라 컴포넌트 표시 이름에서 만들어 네임스페이스가 빠진 PURL, 추이적 의존성 누락(직접 의존성만 포함)입니다.

오픈소스 위험 보고서 읽기

오픈소스 위험 보고서(_risk-report)는 새로 스캔하지 않고 위의 산출물을 재집계해 만든 문서입니다. 네 부분으로 구성됩니다.

  1. 요구사항 충족 — 적합성 결과 표. fail이면 미충족 항목을 명시합니다.
  2. 취약점 집계와 대응 기한 — 심각도별 집계와 함께 권고 대응 기한(Critical 7일, High 30일 이내 대응 계획이나 위험 정당화 마련)을 표로 정리합니다.
  3. 라이선스 요약 — 고지문과 라이선스 커버리지.
  4. 다음 단계 — 대응 계획 안내.

SPDX 입력

CycloneDX XML 문서는 검증 전에 CycloneDX JSON으로 다시 쓰며, 컴포넌트 해시와 루트 컴포넌트, 루트에서 이어지는 의존성 연결은 그대로 보존합니다. services, vulnerabilities, pedigree, evidence 절은 옮기지 않으며 건너뛴 절은 스캔 로그에 이름이 남습니다. DTD나 엔티티를 선언한 문서는 거부합니다. SPDX(JSON, Tag-Value)를 넣으면 내부에서 syft convert로 CycloneDX로 바꾼 뒤 동일한 파이프라인으로 분석합니다. 적합성 검증은 변환 전 SPDX 원본을 기준으로 합니다. 변환 과정에서 timestamp나 도구, 추이적 의존성 같은 메타데이터가 정규화되거나 사라질 수 있기 때문입니다. SPDX의 라이선스 표현 일부는 CycloneDX로 옮기면서 단순화될 수 있습니다.

Yocto 이미지

Yocto 빌드는 자체 SPDX SBOM을 만들 수 있고, BomLens는 이를 일반 SPDX 경로가 아니라 전용 파서로 읽습니다. Yocto 문서에는 일반 경로가 잃어버리는 정보가 두 가지 들어 있기 때문입니다.

SBOM을 만들려면 local.conf에 다음을 넣고 평소대로 빌드합니다.

INHERIT += "create-spdx-3.0"
INHERIT += "vex"

어떤 SPDX 버전을 만들 수 있는지는 릴리스마다 다릅니다.

릴리스 기본 SPDX create-spdx-3.0 사용
4.0 Kirkstone (LTS) 2.2 불가 — 이 릴리스에는 해당 클래스가 없습니다
5.0 Scarthgap (LTS) 2.2 가능
5.1 Styhead 이후 3.0 가능(기본값)

Kirkstone에서는 위 설정을 쓸 수 없습니다. 그 빌드는 SPDX 2.2를 만들고, 아래에 적은 방식으로 읽습니다.

그다음 빌드 디렉터리를 그대로 스캔 대상으로 지정합니다. 빌드가 SBOM을 어디에 두었는지 알 필요가 없습니다.

./scripts/scan-sbom.sh --project my-image --version 1.0.0 \
  --target ~/poky/build --generate-only

빌드 디렉터리로 인식하고, 빌드가 만든 이미지 SBOM인 tmp/deploy/images/<machine>/<image>.rootfs.spdx.json(OpenEmbedded 빌드는 tmp-glibc/…)을 분석합니다. 빌드 트리 자체는 훑지 않습니다. 디렉터리로 스캔하면 이미지에 들어가지 않는 sysroot와 빌드용 도구까지 결과에 섞이기 때문입니다.

머신이나 이미지를 여럿 빌드해 SBOM이 여러 개면 가장 최근에 쓰인 것을 분석하고 후보 전체를 로그에 남깁니다. 다른 것을 고르려면 --analyze <파일>로 직접 지정합니다. DEPLOY_DIR를 옮겨 이미지를 완전히 다른 위치에 쓰는 빌드도 이 방법으로는 찾지 못하니 같은 방식으로 지정합니다. SBOM 파일 하나만 받은 경우에는 그 파일을 웹 UI에 올리거나 --analyze로 넘기면 됩니다.

웹 UI도 같은 폴더를 읽습니다. 디렉터리 입력으로 그 폴더를 고르면 됩니다(--ui --mount ~/poky/build로 먼저 마운트하거나 데스크톱 앱의 폴더 추가 사용). 감지는 명령줄과 똑같이 동작합니다.

빌드 디렉터리 스캔의 적합성 검사 보고서는 빌드가 만든 문서가 아니라 스캔이 쓴 SBOM(<Project>_<Version>_bom.json)을 점검합니다. 제출할 파일이 이것이기 때문입니다. 이 SBOM에는 bomlens:scanMode로 YOCTO가 기록되고, --conformance-profile skt-submission에서는 펌웨어 스캔과 같은 방식으로 판정합니다. 의존 관계 그래프가 아니라 설치된 패키지를 기록하기 때문입니다. --analyze로 넘긴 Yocto 문서는 적힌 그대로 판정합니다.

이 SBOM은 스캔이 직접 만든 것이므로 다른 스캔이 만든 SBOM과 같은 방식으로 정보를 채웁니다. --sbom-author, --supplier, --license(concluded)를 기록하고, 도구 목록에 BomLens를, 수명 주기 단계로 build를 적습니다. 이미지는 빌드가 정한 이름을 그대로 두고 bom-ref를 받으며, 빌드가 버전을 적지 않았으면 --version을 받고, 설치된 모든 패키지에 의존하는 것으로 기록됩니다. 빌드가 생성 시각을 적지 않았으면(매니페스트에는 없음) 스캔 시각을 적습니다. 이 세 옵션을 주면 bsi-tr-03183-2의 SBOM 작성자, 의존 관계 그래프, 최상위 구성요소 항목이 통과할 수 있습니다. --analyze로 따로 넘긴 Yocto 문서는 다른 사람이 만든 SBOM이므로 이 처리를 하지 않습니다.

자체 레시피와 공급사 바이너리

빌드는 설치한 패키지를 모두 기록합니다. 사내 레시피와 칩 제조사의 바이너리 레시피도 여기에 들어 있지만, 어느 것이 자체개발이고 누가 공급했는지는 빌드 기록에 없습니다. 이 정보는 선언 파일에 적어 --components로 넘깁니다. 산출물 경로는 머신과 작업 디렉터리마다 다르므로, 구성요소에는 파일 경로 대신 bomlens:yocto-recipe에 레시피 이름(버전을 뺀 PN)을 적습니다.

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "components": [
    {
      "type": "application",
      "name": "media-daemon",
      "supplier": { "name": "Example Corp", "url": ["https://example.com"] },
      "licenses": [ { "license": { "name": "LicenseRef-ExampleCorp-Proprietary" } } ],
      "properties": [
        { "name": "bomlens:origin", "value": "first-party" },
        { "name": "bomlens:yocto-recipe", "value": "media-daemon" }
      ]
    }
  ]
}
./scripts/scan-sbom.sh --project my-image --version 1.0.0 \
  --target ~/poky/build --components meta-example/sbom-declared.cdx.json

선언은 이미지에 설치된 그 레시피의 패키지 전부(예: media-daemon과 media-daemon-cli)에 적용됩니다. 각 패키지는 빌드가 기록한 이름, 버전, purl, CPE를 그대로 두고, 선언한 유형, 공급자, 라이선스(concluded), bomlens:origin을 받으며 bomlens:declared로 표시됩니다. SPDX 문서가 그 패키지에 기록한 파일은 해시, 파일 이름과 함께 패키지 아래 하위 구성요소로 들어갑니다. Yocto는 패키지가 아니라 파일 단위로 해시를 냅니다. SPDX 3.0은 SHA-256을, Yocto 6.1부터는 SHA-512도 기록하고, SPDX 2.2는 SHA-1과 SHA-256을 기록하며, 매니페스트에는 파일 목록이 없습니다. BomLens는 패키지 해시를 따로 만들지 않습니다. 그래서 --conformance-profile bsi-tr-03183-2에서는 빌드가 기록하지 않은 SHA-512와 파일 이름, Yocto 기록에 없는 파일 속성을 원본 SBOM에 없음으로 보고하고 경고로 표시합니다. skt-submission에서 자체개발 구성요소가 PURL 항목에서 빠지려면 SHA-512가 있어야 하므로, 6.1 이전 빌드에서는 자체 패키지에도 purl이 필요합니다(이 패키지의 pkg:yocto purl은 upstream 저장소가 없는 purl로 셉니다).

선언한 레시피가 이미지에 패키지를 하나도 설치하지 않았으면 스캔은 레시피 이름을 알리며 실패하고, 그때까지 만든 SBOM을 <Project>_<Version>_bom.refused.json으로 남깁니다. 레시피 선언에는 bomlens:artifact를 함께 적을 수 없고, 빌드가 정하는 hashes, purl, cpe도 적을 수 없습니다. 레시피도 파일도 없는 구성요소(예: 장치가 실행 중에 불러오는 바이너리)는 소스 스캔과 같은 방식으로 추가됩니다. 다만 이미지에 설치된 패키지와 이름이 같으면 거부하며, 그 패키지는 레시피로 선언합니다.

패키지는 빌드가 기록한 레시피로만 맞춥니다(SPDX 문서, SPDX가 없는 빌드에서는 license.manifest). 빌드가 레시피를 기록하지 않은 패키지는 이름이 같아도 맞추지 않으며, 거부 메시지에 그 패키지 이름이 나옵니다. 레시피의 멀티립과 SDK 변형(lib32-media-daemon, nativesdk-media-daemon)은 별도 레시피이므로 따로 선언하며, 이미지에 설치된 변형이 있으면 로그에 경고가 나옵니다. 선언은 --target으로 준 빌드 디렉터리에 적용됩니다. --analyze로 준 SBOM은 받은 SBOM이므로 바꾸지 않으며, --components와 함께 쓰면 거부합니다. 웹 UI에서는 아직 Yocto 레시피를 선언할 수 없습니다.

공급자만은 빌드에서 가져올 수도 있습니다. SPDX 3.0에서는 레이어에 레시피별로 다음과 같이 지정하고 다시 빌드합니다.

SPDX_PACKAGE_SUPPLIER_name:pn-media-daemon = "Example Corp"
SPDX_PACKAGE_SUPPLIER_type:pn-media-daemon = "organization"

Yocto는 이 값을 패키지의 suppliedBy로 기록하고, BomLens는 이를 공급자로 읽습니다. 다만 이름만 있고 BSI TR-03183-2가 제작자에 요구하는 URL이나 이메일은 없으며, 자체개발 여부도 표시하지 않습니다. 그래서 bomlens:origin은 여전히 선언 파일에 적습니다. SPDX 2.2는 SPDX_SUPPLIER를 기록하는데, 기본값이 실제 공급자가 아니라 OpenEmbedded이므로 BomLens는 이 값을 읽지 않습니다.

SPDX를 전혀 만들지 않은 빌드

create-spdx를 켜는 것은 빌드 설정을 바꾸는 일이라, 완료된 빌드 디렉터리만 가진 사람은 그렇게 하지 못할 수 있습니다. 빌드는 SPDX가 없어도 무엇을 넣었는지 기록해 두므로, 그 기록을 대신 읽습니다.

파일 위치 얻는 정보
이미지 패키지 매니페스트 tmp/deploy/images/<machine>/<image>.manifest 설치된 패키지와 버전
라이선스 매니페스트 tmp/deploy/licenses/**/license.manifest 패키지별 라이선스와 출처 레시피
cve-check 보고서 tmp/log/cve/cve-summary.json CVE별로 레시피가 패치했는지, 해당 없다고 판정했는지, 남았는지

세 가지 입력 중 가장 약한 경로이며, 이유를 알아 둘 만합니다. CPE가 없어 취약점 매칭이 패키지 이름과 버전에만 기댑니다. CVE 판정도 그 빌드가 실행한 cve-check 범위까지만 정확합니다(cve-check를 돌리지 않은 빌드는 판정이 없다고 보고하며, 없는 판정을 지어내지 않습니다). 적합성 검사 보고서는 다른 빌드 디렉터리 스캔처럼 이 기록에서 읽은 SBOM을 점검합니다. 위의 local.conf 두 줄을 넣고 다시 빌드하는 편이 여전히 낫습니다.

Yocto 빌드 디렉터리인데 SPDX 문서도 이미지 매니페스트도 없으면 디렉터리 스캔으로 넘어가지 않고 스캔을 멈춘 뒤 위 설정 두 줄을 안내합니다. 그대로 스캔하면 이미지 내용과 다른 결과가 나오기 때문입니다.

일반 SBOM 스캔과 결과가 세 가지 면에서 다릅니다.

구성 목록에는 이미지에 설치된 패키지만 담깁니다. Yocto 문서에는 빌드가 사용한 소스 압축 파일도 전부 기록되는데, 출처를 따질 때는 쓸모가 있지만 제품에 실제로 들어간 것과는 다릅니다. 그래서 목록에서 뺍니다.

취약점은 빌드가 판정한 결과를 그대로 씁니다. Yocto는 빌드하면서 CVE 분석을 돌리고 항목마다 판정을 기록하므로 레시피가 패치를 적용했는지 압니다. 그 판정을 빌드에서 패치한 것, 해당 없다고 판정한 것, 아직 남은 것 세 가지로 나눠 보여주고 남은 것만 발견 항목으로 셉니다. 기준 이미지인 core-image-minimal에서는 이 차이가 취약점 12255건을 보고하느냐 한 건도 없다고 보고하느냐를 가릅니다. 전부 빌드에서 이미 닫혔기 때문입니다.

컴포넌트에는 펌웨어 스캔과 같이 upstream 저장소 purl이 붙습니다. 패키지를 만든 레시피나, SPDX 2.2라면 레시피의 소스 내려받기 주소로 BomLens가 프로젝트를 알아낼 수 있는 경우입니다. 어떤 프로젝트를 다루는지는 upstream 저장소 purl을 참고하세요.

시작하기 전에 알아 둘 한계가 두 가지 있습니다.

SPDX 2.2도 읽지만 담기는 정보가 적습니다. Yocto 4.0 Kirkstone과 5.0 Scarthgap은 기본값이 SPDX 2.2인데, 이 형식은 문서 하나가 아닙니다. deploy 디렉터리에는 <image>.spdx.tar.zst 하나만 놓이고, 그 안에 이미지 문서와 설치 패키지별 문서, 레시피별 문서가 들어 있습니다. BomLens는 이 아카이브를 직접 읽습니다. 공개된 Yocto 5.0.14 core-image-minimal로 확인한 결과, 이미지 매니페스트가 나열한 36개 패키지를 라이선스와 CPE까지 그대로 얻었습니다.

없는 것은 빌드의 CVE 판정입니다. 레시피가 어떤 CVE를 패치했는지는 SPDX 3.0에만 기록되므로, --security를 켜면 취약점을 이미지에 들어 있는 NVD CPE 인덱스와 CPE로 대조합니다(벤더가 *인 CPE는 모든 벤더에서 제품명으로 찾으므로, 다른 프로젝트와 제품명이 같으면 그 프로젝트의 CVE도 나올 수 있음). 그래서 빌드가 이미 패치한 CVE가 열린 것으로 보일 수 있습니다. 아카이브에서 이미지 문서만 꺼내 따로 올리면 결과가 거의 비는데, 이때는 깨끗한 스캔처럼 보이게 두지 않고 그 사실을 알려 줍니다. 빌드 디렉터리에 두 형식이 함께 있으면 2.2 쪽이 더 최근이더라도 SPDX 3.0 문서를 분석합니다. --analyze로 넘긴 아카이브는 적합성 검사 보고서를 만들지 않습니다. 아카이브는 제출된 문서가 아니라 문서 묶음이라, 제출 기준과 대조할 대상이 아니기 때문입니다. 빌드 디렉터리에서 찾은 아카이브라면 거기서 읽은 SBOM을 대신 점검합니다.

PURL에 기대는 적합성 항목은 실패합니다. Yocto는 패키지를 PURL이 아니라 CPE로 식별하므로 PURL 적용률과 거기서 파생되는 항목은 통과할 수 없습니다. 보고서에는 몇 개가 CPE로 식별됐는지 함께 적히고, 그 행 아래에 두 식별자를 모두 인정하는 기준(BSI TR-03183-2, 미국 SBOM 최소 요소)이 표시됩니다. 즉 이 판정은 기준이 아니라 제출 요구사항의 것입니다. 기본 취약점 매칭이 PURL을 키로 쓰기 때문에 여기서는 PURL을 요구합니다.

필수 항목 하나가 더 실패하는데, 도구가 아니라 문서 쪽 사정입니다. 최상위 컴포넌트가 버전이 없어 실패합니다. bitbake가 이미지 패키지에 이름만 쓰고 software_packageVersion을 넣지 않습니다(기준 이미지 core-image-minimal에서 확인). 빌드 디렉터리를 스캔하면 이미지가 대신 --version을 받습니다.

업로드 크기는 100MB까지 받습니다. 참고로 기준 이미지인 core-image-minimal 문서는 설치 패키지 35개에 15.8MB입니다. --target으로 빌드 디렉터리를 스캔할 때는 디스크에서 파일을 읽으므로 이 제한이 적용되지 않습니다.

보완 요청하기

검증과 분석이 끝나면 오픈소스 위험 보고서(_risk-report.html)를 SBOM을 보낸 쪽에 전달하고 다음을 요청합니다.

  • 적합성 fail 항목 보완 후 SBOM 재전달.
  • Critical 취약점은 7일, High 취약점은 30일 이내에 대응 계획이나 위험 정당화 마련(권고 대응 기한).

대응 추적, 예외 승인, 이력 관리는 이 도구의 범위가 아니라 별도의 취약점·위험 관리 시스템의 몫입니다. 이 도구는 로컬에서 단일 SBOM을 검증하고 분석해 보고서를 만드는 데까지 담당합니다.

한계

  • 검증은 필수 필드의 존재와 커버리지를 기준으로 합니다. PURL이 실제 패키지를 정확히 가리키는지, 버전이 진짜인지 같은 의미적 정확성까지는 보장하지 못합니다.
  • 추이적 의존성 포함 여부는 의존성 그래프의 edge 유무로 추정하며, 그래프가 완전하다는 증명은 아닙니다.
  • 취약점과 라이선스 분석의 정확도는 입력 SBOM의 품질, 특히 PURL과 버전 정확성에 직접 좌우됩니다.

관련 문서: 시작하기 | 시나리오 가이드 | 고지문·보안 보고서 가이드 | 보고서 읽는 법