SBOM
엔지니어링 팀 전반의 SBOM 생성: 하나의 정책, 모든 파이프라인
대부분의 조직에 있는 것은 SBOM 문제가 아니라 여섯 개의 SBOM 프로세스입니다. 먼저 결과물을 고정하세요. 하나의 포맷, 하나의 필드 집합, 하나의 생성 시점, 하나의 저장소입니다. 그런 다음 각 팀의 파이프라인을 그 기준에 맞게 옮기되, 릴리스 빌드 안에서 생성하는 방식을 우선하세요. 고객, 감사인, 그리고 CRA 같은 규제가 보는 것은 SBOM과 그 뒤의 프로세스이지, 어떤 스캐너를 구매했는지가 아닙니다.
업데이트
팀별 스캐너를 모아도 SBOM 프로그램이 되지 않는 이유
같은 제품에 다섯 가지 도구를 돌리면 다섯 개의 SBOM이 나옵니다. 그 차이는 버그가 아니라 구조적인 것입니다.
- 입력이 다르고, 읽는 시점도 다릅니다. 어떤 도구는 잠금 파일을, 어떤 도구는 설치된 종속성 트리를, 또 어떤 도구는 컨테이너 이미지를, 또 다른 도구는 바이너리를 읽습니다. 각각 제품의 서로 다른 단면을 봅니다.
- 같은 대상에 다른 이름이 붙습니다. 어떤 도구는 package URL로 구성 요소를 식별하고, 어떤 도구는 CPE로, 또 어떤 도구는 파일 이름만으로 식별합니다. 같은 라이브러리를 설명하는 두 SBOM을 공통 키로 연결할 수 없습니다.
- 깊이가 다릅니다. 직접 종속성만 나열하는 도구, 전이적 종속성 트리 전체를 나열하는 도구, 그리고 빌드 도구까지 나열하는 도구가 있습니다. 같은 리포지토리에 대해 생성 도구마다 결과가 다른 이유는 오픈 소스 SBOM 생성 도구에서 보여 줍니다.
- 다른 질문에 답하는 도구도 있습니다. 인프라 취약점 스캐너는 실행 중인 호스트에 무엇이 설치되어 있는지 보고합니다. 운영에는 유용하지만, 출시하는 제품을 설명하는 것은 아닙니다.
그 결과 제품 간에 SBOM을 병합하거나 중복을 제거하거나 비교할 수 없고, 감사인에게 하나의 프로세스를 보여 줄 수도 없습니다. 그런 프로세스가 없기 때문입니다.
| 방식 | 읽는 입력 | 시점 | 놓치는 것 | 일반적인 식별자 |
|---|---|---|---|---|
| 잠금 파일 또는 매니페스트 스캐너 | 체크아웃의 잠금 파일과 매니페스트 | 빌드 전 또는 후 | 어떤 잠금 파일에도 없는 것: 설치 훅, 빌드 스크립트의 다운로드, 베이스 이미지 | Package URL |
| 컨테이너 이미지 스캐너 | 이미지 안의 패키지 데이터베이스와 파일 | 빌드 후 | 빌드에만 쓰는 도구, 컴파일되어 포함된 코드, 패키지 기록이 없는 모든 것 | OS 및 언어 패키지는 Package URL |
| 바이너리 또는 펌웨어 스캐너 | 바이너리 안의 문자열과 시그니처 | 빌드 후 | 확실성: 버전과 구성 요소를 추정함 | CPE 또는 추정한 이름 |
| 호스트 취약점 스캐너 | 실행 중인 서버에 설치된 소프트웨어 | 운영 중 | 고객에게 출시되는 상태의 제품 | CPE 또는 벤더 제품 이름 |
| 빌드 중 기록 | 릴리스 빌드가 가져온 것 | 빌드 중 | 직접 빌드하지 않은 소프트웨어. 보지 못한 부분은 불완전으로 표시 | Package URL |
SBOM 정책: 무엇을 표준화할 것인가
스캐너가 아니라 SBOM을 표준화하세요. 정책은 결과물과 프로세스를 고정하고, 각 파이프라인은 실행할 수 있는 가장 좋은 생성 도구로 이를 충족합니다. 아래의 각 행은 모두 확인할 수 있는 항목입니다.
| 요구 사항 | 규칙 | 이유 | 확인 방법 |
|---|---|---|---|
| 범위 | 고객에게 출시되는 모든 제품 릴리스. 펌웨어와 컨테이너 이미지를 포함합니다. 내부 도구는 선택 사항입니다. | 고객과 규제 기관은 출시하는 제품에 대해 묻습니다. | 릴리스 대장의 각 릴리스에 SBOM이 있습니다. |
| 포맷과 버전 | 하나의 기본 포맷(CycloneDX 또는 SPDX)과 최소 버전. 다른 포맷은 요청 시 수용합니다. | 포맷이 하나면 파서, 검증 도구, 저장소도 하나입니다. BSI TR-03183-2는 CycloneDX 1.6 이상 또는 SPDX 3.0.1 이상을 요구하며, EU 고객을 위한 합리적인 하한선입니다. | 스키마 검증이 포맷과 버전을 보고합니다. |
| 최소 필드 | package URL이 있는 모든 구성 요소에 package URL, 없는 경우에만 CPE, 공급자, 버전, 선언된 라이선스, 종속성 관계, 도구 이름과 버전, 타임스탬프, 생성 컨텍스트. | 매칭, 라이선스 검토, 감사에 쓰이는 필드입니다. SBOM이란의 최소 요소와 맞추세요. | 파이프라인의 필드 검사가 누락된 값을 셉니다. |
| 생성 시점 | 릴리스를 만드는 CI 빌드 안에서 매번 생성합니다. 감사 시점에도, 노트북에서도 아닙니다. | 다시 빌드한 것은 같은 빌드가 아닙니다. 빌드 시점 SBOM을 참고하세요. | SBOM의 빌드 ID가 릴리스의 빌드 ID와 일치합니다. |
| 깊이 | 최상위만이 아니라 전이적 종속성 트리 전체. | CRA의 최소 요건은 최상위 종속성이지만, 취약점과 고객은 그보다 깊이 들어갑니다. | 첫 번째 단계 아래에도 종속성 관계가 존재합니다. |
| 저장 위치 | 릴리스 아티팩트와 함께 저장하고, 제품과 버전으로 조회할 수 있게 합니다. | 보안 권고가 나왔을 때 아무도 찾지 못하는 SBOM은 증거가 아닙니다. | 임의의 릴리스에 대한 SBOM을 제품과 버전으로 가져옵니다. |
| 보존 기간 | 최소한 제품의 지원 기간에, 적용되는 규정이 요구하는 문서 보존 기간을 더한 기간. | CRA는 기술 문서의 보존 기간을 정하고 있으며, SBOM은 그 일부입니다. | 정책의 기간과 각 도구의 보존 기간을 비교합니다. |
| 검증 | 모든 SBOM을 파이프라인에서 스키마 검증하고, 유효하지 않은 SBOM은 빌드나 릴리스 게이트를 실패시킵니다. | 유효하지 않은 SBOM은 고객의 도구에서 아무 표시 없이 실패합니다. | 릴리스 게이트 로그에 검증 단계가 나타납니다. |
| 책임 | 생성은 제품 팀이 맡고, 정책, 검증 규칙, 커버리지 보고는 제품 보안 팀이 맡습니다. | 생성에는 파이프라인 소유자가 필요하고, 일관성에는 규칙의 소유자 한 명이 필요합니다. | 각 파이프라인에 소유자가 지정되어 있습니다. |
| 예외 | 이름과 기한이 있는 예외 대장: 팀, 사유, 종료일. | 아직 준수할 수 없는 팀이 있어도 정책이 유지됩니다. | 종료일이 지난 예외가 없습니다. |
SBOM 모범 사례의 체크리스트는 개별 SBOM에 대한 규칙을 다루며, 이 정책은 그 위의 계층입니다. 각 팀은 자신의 파이프라인이 정책을 어떻게 충족하는지 파이프라인 옆의 파일에 선언합니다.
# sbom-policy.yaml, one per release pipeline
product: gateway-firmware
owner: team-gateway
format: cyclonedx
spec_version: "1.6"
generated_in: release-build
generator: build-time-recording
store: artifact-registry
validation: schema, fail-on-errors
exception: none
사후에 팀별로가 아니라 빌드 안에서 생성하세요
목표로 삼아야 할 표준은 빌드 시점 생성입니다. 출시된 빌드 자체를 설명하고, 어떤 잠금 파일에도 없는 숨은 종속성을 포함하며, 하나의 메커니즘으로 그 파이프라인의 모든 팀에 같은 형태의 SBOM을 만들어 냅니다. 차이는 주방에 비유하면 가장 쉽게 설명됩니다. 스캐너는 수프를 맛보고 레시피를 추측하고, 기록기는 주방에 무엇이 들어가는지 지켜봅니다.
직접 빌드하지 않은 이미지, 서드파티 바이너리, CI가 없는 레거시 제품에는 여전히 스캐너가 알맞은 도구입니다. 이를 정책에 명시하고 생성 컨텍스트를 기록해, 읽는 사람이 각 SBOM이 무엇을 보았는지 알 수 있게 하세요.
| 상황 | 생성 방식 | 기록할 생성 컨텍스트 |
|---|---|---|
| 직접 관리하는 CI에서 빌드한 릴리스 | 빌드를 기록하거나, 릴리스 작업 안에서 생성 도구를 실행 | "빌드 중 기록" 또는 "설치 후, 파일 기반" |
| CI에서 빌드한 컨테이너 이미지 | 이미지 빌드를 기록하고, 기록기가 OS 패키지를 다루지 않으면 결과물을 스캔해 OS 패키지를 확인 | 빌드 ID와 이미지 다이제스트 |
| 서드파티 이미지 또는 어플라이언스 | 이미지 스캐너, 그리고 있다면 벤더의 SBOM | "스캔 결과, 자체 빌드 아님" |
| 공급자 바이너리 | 공급자에게 빌드 SBOM을 요청하고, 바이너리 분석으로 확인 | 공급자, 버전, 입수 경로 |
| 파이프라인이 없는 레거시 제품 | 출시된 아티팩트를 스캔하고, 파이프라인을 계획 | "스캔 결과"와 종료일이 있는 예외 |
혼합 CI: 한 조직 안의 GitHub Actions, GitLab, Jenkins
이 정책은 의도적으로 CI에 구애받지 않도록 설계되었습니다. 결과물을 정의하므로 GitLab이나 Jenkins 파이프라인은 생성 도구 단계로 이를 충족할 수 있고, GitHub Actions 파이프라인은 빌드 중 기록을 사용할 수 있습니다. 생성 도구 단계의 규칙은 다음과 같습니다.
- 설치 단계 다음, 릴리스 작업 안에서 실행하세요. 다시 설치하는 별도 작업에서 실행하지 마세요.
- 생성 도구의 버전을 고정하고, CI 액션은 태그가 아니라 커밋에 고정하세요. 이것이 특히 스캐너에서 중요한 이유는 오픈 소스 SBOM 생성 도구에서 다룹니다.
- 생성 컨텍스트를 "설치 후, 파일 기반"으로 기록해, 읽는 사람이 무엇을 보았는지 알 수 있게 하세요.
- 결과물을 다른 모든 파이프라인과 같은 스키마로 검증하세요.
Syft, Trivy, cdxgen 같은 오픈 소스 생성 도구는 모두 CycloneDX와 SPDX를 출력할 수 있으므로, 포맷 규칙이 특정 도구를 강제하지 않습니다. 비교는 SBOM 도구 비교를 확인하세요.
CRACI는 현재 GitHub Actions를 지원하며, GitLab CI와 Jenkins는 로드맵에 있지만 일정은 정해지지 않았습니다. 도입 측면에서는 GitHub Actions를 쓰는 곳에서 빌드 중 기록을 시작하고, 나머지에서는 생성 도구 단계를 유지하며, 둘 다 같은 커버리지 보고서에서 추적하세요.
고객이 특정 포맷 버전을 원할 때
고객은 CycloneDX 1.6을 요청하는데 사내 도구는 1.7을 출력합니다. 고객의 수집 도구나 고객 자체의 정책이 특정 버전에 고정되어 있기 때문에 생기는 일입니다. BSI의 하한선이 1.6이어서 EU 고객은 이 버전을 자주 지정합니다. 선택지는 다음과 같습니다.
- 새 버전도 수용되는지 물어보세요. 수용되는 경우가 많습니다.
- CycloneDX CLI로 변환한 다음 대상 버전에 맞춰 검증하고, 무엇이 손실되었는지 확인하세요. 새 사양에만 있는 필드는 삭제됩니다.
- SPDX 요청이라면 같은 CLI로 SPDX JSON 2.3과 상호 변환할 수 있습니다. 해당 문서는 SPDX와 CycloneDX 간 변환이 "일부 정보가 손실될 수 있다"고 경고합니다.
cyclonedx convert --input-file bom.cdx.json --input-format json \
--output-file bom-1.6.cdx.json --output-format json --output-version v1_6
cyclonedx validate --input-file bom-1.6.cdx.json --input-format json \
--input-version v1_6 --fail-on-errors
--input-version을 지정하지 않으면 검증 도구는 CycloneDX 1.7 기준으로 검사합니다. 정책 규칙: 원본
SBOM을 기록으로 보관하세요. 변환한 사본은 파생 제공물이며, 파생 정보(도구, 버전, 날짜)를 함께
저장하세요. 이런 요청에 대응하는 방법은 고객 SBOM 요청에서, 두
포맷에 대해서는 CycloneDX vs SPDX에서 자세히 다룹니다.
법무 팀을 위한 라이선스 데이터
정책이 적절한 필드를 요구한다면 같은 SBOM을 법무 팀에도 활용할 수 있습니다. 법무 팀에 필요한 것은 모든 구성 요소의 라이선스, 선언된 라이선스(패키지가 밝힌 것)와 확정된 라이선스(누군가 검증한 것)의 구분, 카피레프트 의무, 그리고 라이선스가 없는 구성 요소 목록입니다. CycloneDX 1.6은 라이선스를 선언된 것과 확정된 것으로 표시하며, SPDX에는 두 가지 모두에 대한 별도 필드가 있습니다.
MIT나Apache-2.0 OR MIT같은 SPDX 라이선스 식별자 또는 표현식을 필수로 하세요.-
NOASSERTION과 누락된 라이선스를 표시해 검토로 넘기세요. SPDX에서NOASSERTION은 판단이 이루어지지 않았거나 정보가 제공되지 않았다는 뜻이며, 라이선스가 아닙니다. - 카피레프트 라이선스는 릴리스 후가 아니라 릴리스 전에 법무 팀으로 넘기세요.
SBOM에는 선언된 라이선스가 담깁니다. 확정된 라이선스, 고지, 의무를 다루는 라이선스 컴플라이언스 검토는 법무 업무이거나 전문 도구가 할 일입니다. 오픈 소스 라이선스 컴플라이언스를 확인하세요.
팀 단위로 도입하기
| 단계 | 담당 | 완료 기준 | 흔한 걸림돌 |
|---|---|---|---|
| 1. 현황 파악: 제품, 파이프라인, CI 시스템, 현재 생성 도구를 릴리스 파이프라인당 한 행으로 | 제품 보안 팀 | 출시되는 모든 제품에 행이 있음 | 어떤 파이프라인이 릴리스를 빌드하는지 아무도 모름 |
| 2. 예외 대장과 함께 정책 게시 | 제품 보안 팀 | 정책이 승인되고 게시됨 | 어떤 도구를 의무화할지에 대한 논쟁(정책은 도구를 의무화하지 않음) |
| 3. 이유가 있는 한두 팀으로 파일럿: 고객 요청, 마감 기한, 현재 도구로 처리할 수 없는 제품 | 파일럿 팀 | 파일럿 릴리스가 정책을 준수한 SBOM과 함께 출시됨 | 절박한 이유가 없는 팀은 우선순위를 낮춤 |
| 4. 파일럿 파이프라인에 검증 게이트 추가 | 파일럿 팀 | 유효하지 않은 SBOM이 릴리스를 실패시킴 | 릴리스가 막힐 것에 대한 우려. 경고부터 시작 |
| 5. CI 시스템별로 확대하고, 팀별 스캐너는 대체 수단이 정책을 충족할 때만 폐기 | 제품 팀 | CI 시스템별 커버리지 목표 달성 | 소유자가 없는 파이프라인 |
| 6. 매월 커버리지 보고 | 제품 보안 팀 | 보고서가 매월 경영진에게 전달됨 | 수작업으로 계산한 지표 |
1단계의 현황 파악 스프레드시트가 마지막 스프레드시트가 되어야 합니다. 스프레드시트에서 벗어나는 방법은 SBOM 자동화에서 다룹니다. 범용 스캐너가 다루기 어려워하기 때문에 Yocto 기반 제품은 흔한 파일럿 대상입니다. SBOM 스캐너가 Yocto 빌드를 놓치는 이유를 확인하세요.
커버리지 측정
경영진과 감사인이 요구하는 수치이며, 각각 비율로 정의합니다.
- 릴리스 커버리지: 정책을 준수한 SBOM과 함께 출시된 릴리스 ÷ 출시된 릴리스.
- 제품 커버리지: 현재 지원 기간에 준수 SBOM이 하나 이상 있는 제품 ÷ 지원 중인 제품.
- 검증 통과율: 검증을 통과한 SBOM ÷ 생성된 SBOM.
- 식별자 커버리지: package URL(또는 CPE)이 있는 구성 요소 ÷ 구성 요소.
- 라이선스 커버리지: 선언된 라이선스가 있는 구성 요소 ÷ 구성 요소.
- 완전성: 생성 도구가 완전하다고 밝힌 SBOM ÷ SBOM. 도구가 이를 보고하는 경우에만 가능합니다.
- SBOM까지 걸리는 시간: 릴리스부터 SBOM을 사용할 수 있게 될 때까지의 시간.
월간 보고서 예시(설명용 수치):
| 지표 | GitHub Actions 파이프라인 | GitLab 및 Jenkins 파이프라인 | 전체 |
|---|---|---|---|
| 릴리스 커버리지 | 46 / 48 | 19 / 27 | 65 / 75 |
| 검증 통과율 | 100% | 92% | 97% |
| 식별자 커버리지 | 99% | 88% | 95% |
| 미해결 예외 | 1 | 4 | 5 |
규제 기관이나 감사인에게 제출할 증거는 정책, 예외 대장, 커버리지 보고서, 몇 가지 SBOM 샘플로 구성됩니다. 이를 통해 적용되고 측정되는 하나의 프로세스를 보여 줍니다. CRA 측면은 CRA 가이드를 확인하세요.
CRACI의 역할
GitHub Actions 파이프라인에서는 CRACI가 러너입니다. runs-on: craci를 설정하면 모든 작업이 생성 도구 단계 없이
기록된 SBOM을 갖게 됩니다. 각 SBOM에는 완전성 상태, 전이적 종속성, 패키지별 package URL,
각 구성 요소의 선언된 라이선스가 담기며, CycloneDX 또는 SPDX로 내보낼 수 있습니다. 라이선스 정책 규칙으로 빌드를
차단할 수 있고, 모니터링 중인 SBOM은 지속적으로 재평가되며, 빌드 기록은 어떤 빌드에 취약한 종속성이 포함되었는지
보여 줍니다. 이를 통해 해당 팀은 정책의 "릴리스 빌드에서 생성", "식별자", "라이선스" 행을
기본으로 충족합니다. 서드파티 SBOM도 추가할 수 있어, 외부에서 들여온 구성 요소도 자체 빌드와 함께 모니터링됩니다.
CRACI의 SBOM 생성과 GitHub Actions의 SBOM을 확인하세요.
CRACI가 답이 아닌 경우
- GitLab CI 또는 Jenkins를 쓰는 팀: 현재는 지원하지 않으며 로드맵에 있습니다. 정책을 충족하는 생성 도구 단계를 사용하세요.
- GitHub Enterprise Server: 현재 지원하지 않습니다.
- 인프라 및 호스트 스캔, 즉 서버에 설치된 것과 잘못된 구성: 다른 일이므로 해당 도구를 계속 사용하세요.
- 직접 빌드하지 않는 공급자 이미지의 바이너리 또는 펌웨어 분석: CRACI는 빌드를 기록하며 바이너리를 스캔하지 않습니다.
- 장기 보존: CRACI는 빌드 데이터를 기본 180일 동안 보관하며, Enterprise에서는 보존 기간을 맞춤 설정할 수 있습니다. 정책상 SBOM을 더 오래 보관해야 한다면 자체 저장소로 내보내세요.
팀 전반의 SBOM 생성: 자주 묻는 질문
서로 다른 도구를 쓰는 팀 간에 SBOM 생성을 어떻게 표준화하나요?
도구가 아니라 결과물을 표준화하세요. 포맷과 버전, 최소 필드, SBOM 생성 시점, 저장 위치, 보존 기간, 검증 담당을 정하는 정책 하나를 작성하세요. 각 파이프라인이 실행할 수 있는 가장 좋은 생성 도구로 이를 충족하게 하고, 커버리지는 정책 기준으로 측정하세요.
SBOM 정책에는 무엇이 포함되어야 하나요?
범위, 포맷과 최소 버전, 최소 필드(package URL, 공급자, 버전, 선언된 라이선스, 종속성, 도구, 타임스탬프, 생성 컨텍스트), 릴리스 빌드에서의 생성, 전이적 종속성 전체 깊이, 릴리스와 함께 저장, 보존 기간, 파이프라인에서의 검증, 책임, 그리고 기한이 있는 예외 대장입니다.
팀마다 자체 스캐너를 실행해야 하나요, 아니면 SBOM이 빌드에서 나와야 하나요?
가능한 곳에서는 빌드에서 나와야 합니다. 빌드 시점 SBOM은 출시된 빌드를 설명하고, 그 파이프라인의 모든 팀에 같은 형태의 SBOM을 제공합니다. 스캐너는 직접 빌드하지 않은 것, 즉 서드파티 이미지, 공급자 바이너리, 파이프라인이 없는 레거시 제품에 계속 사용하세요.
고객이 이전 CycloneDX 버전의 SBOM을 원합니다. 어떻게 해야 하나요?
먼저 새 버전도 수용되는지 물어보세요. 수용되지 않으면 CycloneDX CLI(cyclonedx convert에 --output-version v1_6 지정)로 사본을 변환하고, 해당 버전 기준으로 검증한 뒤, 어떤 필드가 삭제되었는지 확인하세요. 원본을 기록으로 보관하고 사본을 어떻게 파생했는지 저장하세요.
SBOM의 라이선스 데이터를 법무 팀에 어떻게 전달하나요?
정책에서 SPDX 라이선스 식별자 또는 표현식을 필수로 하고, NOASSERTION과 누락된 라이선스를 표시해 검토로 넘기며, 카피레프트 라이선스는 릴리스 전에 법무 팀으로 보내세요. SBOM에는 선언된 라이선스가 담기며, 확정된 라이선스, 고지, 의무에는 라이선스 검토가 필요합니다.
제품 전반의 SBOM 커버리지는 어떻게 측정하나요?
비율로 측정합니다. 준수 SBOM과 함께 출시된 릴리스, 준수 SBOM이 있는 지원 중인 제품, 검증 통과율, package URL이 있는 구성 요소, 선언된 라이선스가 있는 구성 요소, 도구가 보고하는 경우의 완전한 SBOM, 그리고 릴리스부터 SBOM까지 걸리는 시간입니다. CI 시스템별로 매월 보고하세요.
SBOM 생성이 일관된다는 것을 감사인에게 보여 주려면 어떤 증거가 필요한가요?
정책, 예외 대장, 월간 커버리지 보고서, 그리고 생성 컨텍스트가 포함된 몇 가지 SBOM 샘플입니다. 이들을 함께 보면 모든 릴리스에 적용되고 측정되는 하나의 프로세스를 알 수 있으며, 이것이 바로 감사인이나 고객이 확인하는 부분입니다.
GitHub Actions 파이프라인 하나로 파일럿해 보세요
데모를 예약하고 릴리스 파이프라인 하나를 CRACI에서 실행해 보세요. 빌드에서 기록된 SBOM을 받아 정책에 맞는지 확인하세요.
데모 예약