SBOM
SBOM은 실제로 출시된 빌드를 설명해야 합니다
빌드 시점 SBOM은 빌드가 실행되는 동안, 실제로 빌드에 들어온 트래픽을 바탕으로 기록됩니다. 반면 대부분의 SBOM 생성 도구는 나중에 잠금 파일이나 결과물에서 목록을 재구성하므로, 빌드가 스스로 가져오는 숨은 종속성을 놓칩니다. 그 이유와 빌드를 기록하면 무엇이 달라지는지 설명합니다.
업데이트
빌드 SBOM, 소스 SBOM, 분석 SBOM
SBOM 유형에 관한 CISA의 지침은 SBOM을 언제, 어떻게 만드는지에 따라 분류합니다. 그중 세 가지 유형이 현재 쓰이는 거의 모든 SBOM 생성 도구를 포괄합니다.
| 유형 | 생성 방식 | 놓칠 수 있는 것 |
|---|---|---|
| 소스 | 소스 파일, 매니페스트, 잠금 파일에서 생성하며, 대개 SCA 도구가 만듭니다 | 런타임, 플러그인, 플랫폼 구성 요소 등 파일에 선언되지 않은 모든 것 |
| 빌드 | 출시 가능한 아티팩트를 만드는 빌드 과정의 일부로 생성합니다 | 빌드 환경이 볼 수 없는 것. 그래서 완전성을 명시해야 합니다 |
| 분석 | 빌드 후 실행 파일, 패키지, 컨테이너 이미지를 분석해 생성합니다 | 도구가 인식하지 못하는 구성 요소. 결과는 휴리스틱에 좌우됩니다 |
CISA는 빌드 SBOM의 장점으로 두 가지를 꼽습니다. 빌드와 CI/CD 과정에서 얻을 수 있는 정보 덕분에 SBOM이 아티팩트를
정확히 나타낸다는 확신이 높아지고, 같은 빌드 워크플로가 SBOM과 아티팩트에 모두 서명할 수 있어 신뢰가 높아진다는
것입니다. 단점으로는 SBOM을 생성하려면 빌드 프로세스를 바꿔야 할 수 있다는 점을 듭니다. CRACI에서는 그 변경이
runs-on: craci 한 줄이며, 기록은 러너와 함께 제공됩니다.
폴더 스캔과 빌드 기록의 차이
대부분의 SBOM 생성 도구는 스캐너입니다. 소스 트리나 컨테이너 이미지를 지정하면, 매니페스트, 잠금 파일, 설치된 패키지, 바이너리를 읽어 무엇이 들어갔을지 추정합니다. 이는 유용하며, 직접 빌드하지 않은 소프트웨어라면 대개 유일한 방법입니다.
약점은 스캐너가 눈앞에 있는 것만 본다는 점입니다. 잠금 파일이 커밋되지 않았거나, 스캔 전에 종속성을 설치하지 않았거나, 제품이 컴파일된 바이너리로 출시된다면, 스캐너가 다룰 수 있는 정보는 빌드가 가졌던 정보보다 적습니다. 구성 요소를 하나도 찾지 못한 스캔도 여전히 유효한 SBOM 문서를 만들어 낸다는 점이 많은 사람이 놓치는 부분입니다.
CRACI는 다른 방식을 취합니다. CRACI의 CI 러너 안에서 SBOM을 생성하므로, 출시된 아티팩트가 곧 SBOM이 설명하는 아티팩트입니다. 근처 어딘가에서 실행된 스캔이 아닙니다.
SBOM basics: SPDX, CycloneDX and OpenVEX
SBOM이 기록하는 내용, SPDX와 CycloneDX 형식이 실제로 어떻게 다른지, 그리고 취약점이 실제로 제품에 영향을 주는지에 대해 OpenVEX가 더하는 정보를 설명합니다.
Kubernetes Community Days Helsinki 2026의 Petteri Pulkkinen 및 Erika Marttinen, SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains 중 16:50~22:05.
스캔이 의존하는 것
Syft, Trivy, cdxgen, Microsoft SBOM Tool, GitHub 종속성 그래프 내보내기, Socket CLI는 모두 읽을 수 있는 것에서 SBOM을 추론합니다. 아래의 패턴은 이 도구들의 문서에 설명된 작동 방식에서 비롯됩니다.
무엇을 구성 요소로 볼지 도구마다 다릅니다
각 생성 도구는 무엇을 구성 요소로 볼지, 어떤 파일을 신뢰할지 스스로 정하므로, 같은 고정 커밋에서도 도구마다 서로 다른 목록이 나옵니다.
그중 일부는 명명 방식의 문제입니다. 도구들은 같은 GitHub Action을 서로 다른 패키지 URL 유형으로 식별하므로, 같은 것을 나열해도 일치하지 않을 수 있습니다. 이것도 문제의 일부입니다. 구성 요소에 다른 식별자를 쓰는 SBOM은 취약점 데이터와 매칭하기가 더 어렵습니다.
먼저 설치했는지가 도구보다 더 중요할 수 있습니다
Express 5.2.1은 잠금 파일을 커밋하지 않습니다. 깨끗한 체크아웃을 대상으로 하면, 잠금 파일이나 설치된 트리에서
종속성을 해석하는 생성 도구는 둘 다 찾을 수 없으므로 package.json에 선언된 npm 종속성이 하나도 문서에
들어가지 않습니다. 그래도 GitHub Actions와 이를 참조하는 워크플로 파일처럼 인식할 수 있는 다른 것으로 목록을 반환할
수는 있습니다. 여기서 고장 난 도구는 없습니다.
같은 리포지토리를 설치한 사본에서는 Syft 플래그 하나로 답이 또 달라집니다. 같은 도구, 같은 트리, 같은 버전인데도 그렇습니다. Syft의 디렉터리 스캔은 설계상 프로젝트가 선언한 것을 보고하며, 설치된 패키지를 읽는 카탈로거는 디렉터리용 기본 설정에 포함되어 있지 않습니다.
읽을 매니페스트가 없는 소프트웨어도 있습니다
v2.1.259 시점의 anthropics/claude-code 리포지토리에는 어떤 종류의 종속성 매니페스트도 없습니다.
package.json도, 잠금 파일도, 그에 상응하는 파일도 없습니다. 각 생성 도구가 반환하는 결과는 다른 파일
유형에서 조합한 것이므로, 그 답은 프로젝트보다 도구에 대해 더 많은 것을 말해 줍니다.
게시된 npm 패키지도 크게 다르지 않습니다. @anthropic-ai/claude-code는 런타임 종속성을 하나도 선언하지 않으며, 사전 빌드된 바이너리를 감싸는 플랫폼별
패키지 8개를 선언합니다. @openai/codex 0.149.1도 같은 구조입니다. 개발자 컴퓨터에서 실행되는 것은
어떤 매니페스트 리더도 들여다볼 수 없는 컴파일된 바이너리입니다. 이는 특정 도구의 결함이 아닙니다. 사후 스캔으로는
설명할 수 없는 배포 모델입니다.
버전과 공급자
두 도구가 같은 패키지를 찾더라도 버전이 항상 일치하지는 않습니다. 한 도구는 GitHub Action을 커밋 SHA로 고정하고, 다른 도구는 릴리스 태그를 보고할 수 있습니다. 잘못된 버전으로 취약점을 조회하면 확신에 찬 잘못된 답이 나옵니다.
NTIA 최소 요소 중 하나인 공급자 필드는 비어 있는 경우가 많습니다. 대부분의 생성 도구에 그 정보를 얻을 출처가 없기 때문입니다.
숨은 종속성: 어떤 스캔으로도 볼 수 없는 것
위의 모든 도구는 잠금 파일이나 빌드 결과물에서 출발해 무엇이 들어갔는지 추론합니다. 하지만 빌드는 그보다 더 많은 것을 가져옵니다. 이런 숨은 종속성은 어떤 잠금 파일에도 나열되지 않으므로 스캔으로 찾을 수 없습니다.
-
설치 훅. npm
preinstall및postinstall스크립트는 설치 중에 실행되며 추가 코드를 내려받을 수 있습니다. Shai-Hulud 웜도 이렇게 실행되었습니다. - 빌드 스크립트. Rust 빌드 스크립트 등은 빌드 시점에 필요한 것을 내려받습니다.
- 베이스 이미지. 컨테이너 빌드는 베이스 이미지와 그 운영체제 계층을 가져오며, 이는 어떤 언어의 잠금 파일에도 나열되지 않습니다.
- 캐시와 빌드 도구. CI 캐시에서 복원된 패키지와 설정 단계에서 설치된 도구도 잠금 파일 밖에서 들어옵니다.
나중에 결과물을 스캔해도 이 공백은 메워지지 않습니다. 완성된 바이너리, 특히 Rust 같은 컴파일된 코드는 무엇이 들어갔는지 스캐너가 추측하게 만듭니다.
두 번의 빌드, 두 개의 SBOM
스캔이 빌드를 대신할 수 없는 두 번째 이유가 있습니다. 대부분의 빌드는 재현 가능하지 않습니다. 같은 커밋을 연달아 두 번 빌드해도 같은 패키지를 얻는다는 보장이 없습니다. 패키지 관리자는 응답이 도착하는 순서대로 종속성을 해석하고 설치하며, 이는 많은 Python 프로젝트처럼 잠금 파일이 없을 때 가장 큰 영향을 미칩니다. 빌드 단계 자체에 무작위성이 들어갈 수도 있습니다. Nix 같은 도구로 바이트 단위까지 재현 가능한 빌드를 만들 수는 있지만 드뭅니다.
따라서 나중에 다른 머신이나 다른 빌드에서 생성한 SBOM은 실제로 출시된 적이 없을 수도 있는 빌드를 설명합니다. 릴리스를 만든 CI 빌드 중에 기록된 SBOM만이 프로덕션에 무엇이 있는지 증명합니다.
빌드를 기록하면 달라지는 것
CRACI는 트래픽을 보지만 스캐너는 보지 못합니다. CRACI는 GitHub Actions 작업을 CRACI 러너에서 실행하며 각 빌드로 들어오는 네트워크 트래픽을 보므로, SBOM에는 매니페스트상 필요하다고 적힌 것이 아니라 작업이 실제로 가져온 것이 전이적 종속성과 숨은 종속성까지 포함해 나열됩니다.
빌드 시점 기록이 어려워지는 지점은 캐시입니다. 캐시에서 복원된 패키지는 패키지 레지스트리를 거치지 않으므로 프록시만으로는 놓치게 됩니다. CRACI는 종속성 증거를 캐시와 함께 전달하므로, 캐시에서 복원된 패키지도 이를 복원한 작업의 SBOM에 그대로 남습니다. GitHub Actions 캐시가 숨기는 것을 참고하세요.
감지되는 생태계에는 npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk, Git 소스와 Yocto 및 OpenEmbedded 다운로드 프리셋이 포함됩니다. JFrog Artifactory의 npm 및 PyPI 미러도 작동합니다. 선언된 라이선스 메타데이터가 내보내기에 포함됩니다. SBOM은 CycloneDX와 SPDX로 내보낼 수 있습니다. 전체 기능은 SBOM 생성 페이지에서 다룹니다.
트래픽을 본다는 것은 반대 방향으로도 작동합니다. 빌드에는 알려진 소스의 패키지가 필요하고, 결과물은 알려진 곳에 게시됩니다. CRACI의 이그레스 정책은 그것만 허용하고 그 밖의 모든 외부 연결을 즉시 차단하므로, 시크릿을 공격자의 서버로 보내려는 악성 코드는 실패합니다. 이 정책은 알려진 악성 호스트를 찾는 대신 빌드에 필요한 것을 허용하므로, Shai-Hulud처럼 아무도 본 적 없는 공격의 첫 번째 표적이 되더라도 유지됩니다. 이그레스 정책이 데이터 유출을 막는 방법을 참고하세요.
컨테이너 및 Docker SBOM
차이가 가장 크게 드러나는 곳은 컨테이너 이미지입니다. Docker SBOM을 얻는 일반적인 방법은 모두 이미지를 분석합니다.
Syft와 Trivy는 이미지를 스캔하고, docker scout sbom은 이미지에 SBOM 증명이 없을 때 그 내용을 색인하며,
--sbom=true로 켜는 BuildKit의 SBOM 증명은 기본적으로 최종 이미지 단계에 Syft 기반 스캐너를 실행합니다.
예전의 docker sbom 플러그인은 지원 중단되었으며 docker scout sbom으로 대체되었습니다.
이 방법들은 모두 완성된 이미지를 읽으므로, 계층 안에 아직 인식 가능한 형태로 남아 있는 것만 봅니다. 빌드가 그 과정에서 가져온 것은 보지 못합니다. CRACI는 이미지를 빌드하는 작업을 기록합니다. 작업이 OCI 레지스트리와 패키지 소스에서 가져오는 이미지와 패키지는 빌드의 나머지 부분과 같은 SBOM에 들어갑니다. 직접 빌드하지 않은 이미지라면 여전히 스캔이 현실적인 방법입니다. Docker 이미지 SBOM이 놓치는 것을 참고하세요.
작업별로 명시되는 완전성
기록된 SBOM의 품질은 기록의 품질을 넘지 못합니다. CRACI는 모든 SBOM을 완전하다고 내세우는 대신, 작업과 캐시마다 완전성을 다섯 가지 상태 중 하나로 표시합니다.
- Complete. CRACI가 작업의 완전한 증거를 관찰했으며, 복원된 모든 캐시도 완전했습니다.
- Complete with connections. 요건은 충족했지만 작업이 하나 이상의 사용자 지정 네트워크 연결을 사용했으므로, 그 연결로 무엇이 들어왔는지 검토할 가치가 있습니다.
- Incomplete. CRACI가 종속성이 SBOM에서 누락될 수 있는 조건을 확인했습니다.
- Unavailable. CRACI가 증거 평가를 완료하지 못했습니다.
- Not recorded. 완전성 보고가 도입되기 전의 작업입니다.
완전성은 캐시를 거쳐 전이됩니다. 작업이 불완전한 캐시를 복원하면 그 작업의 SBOM도 불완전하며, 그 작업이 만드는 캐시도 불완전 상태를 이어받습니다. 어떤 SBOM을 신뢰할 수 있고 어떤 SBOM을 다시 확인해야 하는지 알 수 있습니다.
The hard parts: hooks, noise and staying current
발표에서 짚은 세 가지 문제: 어떤 매니페스트에도 없는 것을 가져오는 설치 후 훅, 긴 목록에서 중요한 종속성을 찾는 일, 그리고 SBOM을 최신으로 유지하는 일, 즉 모든 빌드마다 CI에서 SBOM을 생성해야 한다는 점입니다.
Kubernetes Community Days Helsinki 2026의 Petteri Pulkkinen 및 Erika Marttinen, SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains 중 25:39~27:22.
API로 제공되는 출처 증명
SBOM은 CRACI가 작업마다 기록하는 정보의 일부입니다. API는 같은 빌드에서 기록된 SBOM, 네트워크 추적, 출처 증명을 모두 반환합니다.
여전히 스캐너가 적합한 경우
빌드 시점 기록은 직접 빌드하는 소프트웨어를 대상으로 합니다. 직접 빌드하지 않은 서드파티 이미지나 바이너리에는 여전히 스캐너가 현실적인 선택이며, 위의 도구들은 성능이 뛰어나고 널리 쓰입니다. 요점은 스캐너가 나쁘다는 것이 아닙니다. 자사 릴리스의 SBOM은 그 릴리스를 만든 빌드에서 나와야 한다는 것입니다.
CRACI SBOM에도 나름의 한계가 있습니다. CRACI 러너에서 실행되는 작업을 대상으로 하며, 현재는 Linux의 GitHub Actions를 의미합니다. 다른 CI 시스템은 로드맵에 있습니다.
도구를 고르고 계십니까? SBOM 도구 비교를 참고하거나, 빌드 시점 SBOM이 CRA 컴플라이언스 업무에 어떻게 들어맞는지 확인하세요. Syft, Trivy, cdxgen을 나란히 비교한 내용은 오픈 소스 SBOM 생성 도구가 놓치는 것을 참고하세요.
빌드 시점 SBOM: 자주 묻는 질문
빌드 시점 SBOM이란 무엇입니까?
빌드 시점 SBOM은 CISA가 빌드 SBOM이라고 부르는 것으로, 출시 가능한 아티팩트를 빌드하는 과정의 일부로 생성됩니다. 나중에 파일에서 구성 요소 목록을 재구성하는 대신, 빌드 자체가 사용한 것을 설명합니다. CRACI는 각 GitHub Actions 작업이 실제로 가져온 패키지에서 이를 기록합니다.
빌드 SBOM과 분석 SBOM의 차이는 무엇입니까?
분석 SBOM은 빌드 후 실행 파일이나 컨테이너 이미지 같은 아티팩트를 분석해 생성하며, 일반적으로 휴리스틱이 필요합니다. 빌드 SBOM은 빌드 중에 빌드가 가진 정보로 생성합니다. 분석 SBOM은 빌드에 접근하지 않아도 작동하므로, 직접 빌드하지 않은 소프트웨어에 적합합니다.
Docker 이미지의 SBOM은 어떻게 생성합니까?
기존 이미지라면 Syft, Trivy, docker scout sbom 같은 생성 도구로 스캔하세요. BuildKit도 빌드할 때 최종 이미지를 스캔해 SBOM 증명을 첨부할 수 있습니다. 이미지 빌드가 가져온 것을 기록하려면 CRACI 러너에서 빌드를 실행하세요. 작업의 SBOM에 작업이 가져온 이미지와 패키지가 포함됩니다.
숨은 종속성이란 무엇입니까?
빌드가 가져오지만 어떤 잠금 파일에도 나열되지 않는 모든 것입니다. npm 설치 훅이 내려받는 코드, Rust 빌드 스크립트가 빌드 시점에 내려받는 파일, 컨테이너 빌드의 베이스 이미지와 그 운영체제 계층이 여기에 해당합니다. 잠금 파일을 읽거나 결과물을 스캔하는 도구는 이를 놓칩니다. CRACI는 빌드로 들어오는 트래픽을 보므로 이를 기록합니다.
같은 코드를 두 번 빌드하면 왜 SBOM이 달라집니까?
대부분의 빌드가 재현 가능하지 않기 때문입니다. 패키지 관리자는 특히 잠금 파일이 없을 때 응답이 도착하는 순서대로 패키지를 해석하고 설치하며, 빌드 단계에 무작위성이 들어갈 수도 있습니다. 같은 커밋을 연달아 두 번 빌드하면 두 번째 빌드에 다른 패키지가 들어갈 수 있습니다. 릴리스를 만든 빌드 중에 기록된 SBOM만이 그 릴리스에 무엇이 들어 있는지 증명합니다.
빌드 시점 SBOM은 항상 완전합니까?
자동으로 그렇지는 않습니다. 기록의 품질은 관찰할 수 있는 범위를 넘지 못하므로, CRACI는 모든 작업과 모든 캐시의 완전성을 Complete, Complete with connections, Incomplete, Unavailable, Not recorded 중 하나로 표시합니다. 어떤 SBOM을 신뢰할 수 있고 어떤 SBOM을 다시 확인해야 하는지 알 수 있습니다.
빌드 시점 SBOM이 SBOM 스캐너를 대체합니까?
직접 빌드하는 소프트웨어라면 그렇습니다. 릴리스의 SBOM은 그 릴리스를 만든 빌드에서 나와야 합니다. 직접 빌드하지 않은 서드파티 이미지와 바이너리에는 여전히 스캐너가 현실적인 선택입니다. 선택지는 SBOM 도구 비교에서 다룹니다.
CRACI는 어떤 SBOM 생성 도구를 사용합니까?
사용하지 않습니다. CRACI는 파일을 스캔하지 않습니다. CRACI 러너에 있는 패키지 인식 프록시가 각 작업이 npm, PyPI, RubyGems, Cargo, Go, Nix, OCI, apt, apk, Git 소스와 Yocto 및 OpenEmbedded 다운로드 프리셋에서 가져오는 패키지를 기록하고, 그 결과를 CycloneDX 또는 SPDX로 내보냅니다.
귀사 빌드의 SBOM을 비교해 보세요
데모를 예약하고 워크플로 하나를 CRACI에서 실행해 보세요. 그 SBOM을 현재 도구가 만든 SBOM과 나란히 놓고 차이를 확인하세요.
데모 예약