공급사 SBOM 제출 가이드
SK텔레콤에 소프트웨어를 공급하는 파트너사를 위한 SBOM 생성 및 제출 가이드입니다.
SK텔레콤은 소프트웨어 공급망의 투명성과 보안성을 강화하기 위해, 공급사로부터 납품받는 모든 소프트웨어 구성 요소 및 의존성에 대한 SBOM(Software Bill of Materials) 제출을 요청드리고 있습니다. 본 가이드는 공급사가 SK텔레콤의 보안 정책에 맞는 형식으로 SBOM을 생성하고 제출하는 방법을 안내합니다.
빠른 시작: 제출까지 5단계
- 제출 요구사항에서 허용 포맷(CycloneDX JSON 권장)과 필수 데이터 필드를 확인합니다.
- 자체 도구 체계를 이미 운영한다면 그 도구로 SBOM을 생성합니다(SBOM 생성 방법의 오픈소스 도구 안내 참고). 아직 없다면 BomLens로 생성합니다.
- OS 위에 애플리케이션을 얹어 납품하는 서버라면 SBOM 생성 방법의 서버 납품 절에 따라 층별로 생성해 함께 제출합니다.
- 검증 체크리스트로 PURL과 전이 의존성 포함 여부를 점검합니다.
- 제출 절차에 따라 파일명을 정하고 제출합니다.
타사가 제조한 상용 소프트웨어나 완제품을 공급해 소스코드에 접근할 수 없다면, 2~3단계 대신 상용 소프트웨어 공급에 따라 제조사로부터 SBOM을 받아 제출합니다. 제출한 SBOM이 반려되면 자주 발생하는 반려 사유에서 원인별 해결 방법을 확인합니다.
적용 대상
다음 형태의 소프트웨어를 납품하는 모든 공급사(개발사, 리셀러 포함)는 본 가이드라인의 적용을 받습니다.
- 소스코드: Java, Python, JavaScript, Go, C/C++ 등으로 작성된 애플리케이션
- 컨테이너 이미지: Docker 이미지 또는 OCI 호환 컨테이너
- 실행 파일: 컴파일된 바이너리(.jar, .dll, .so) 및 라이브러리
- 임베디드 시스템: 펌웨어 이미지, RootFS(추출한 루트 파일시스템), 디바이스 드라이버
- 서버: OS(rootfs와 설치 패키지) 위에 애플리케이션이 결합된 시스템
- 상용 소프트웨어·완제품: 타사가 제조한 패키지 소프트웨어 또는 어플라이언스 장비 (리셀러·총판 공급 포함)
SBOM 제출 프로세스
공급사는 계약 시점부터 최종 납품까지 아래의 절차에 따라 진행하시기 바랍니다.
flowchart TD
A[계약 검토] --> B["소프트웨어 개발/빌드"]
B --> C{SBOM 생성}
C -->|SKT 제공 도구 활용| D[BomLens 활용]
C -->|자체 도구 활용| E["오픈소스 도구 활용<br>(cdxgen, Syft 등)"]
C -->|상용 완제품 공급| K[제조사 SBOM 수령]
D --> F["데이터 검증 (PURL 확인)"]
E --> F
K --> F
F --> G["SBOM 제출 (이메일/지정 채널)"]
G --> H[SKT 보안성 검토]
H -->|승인| I[납품 완료]
H -->|반려| J[보완 및 재제출]
J --> F
classDef start fill:#F2F2F2,stroke:#171717,color:#171717,stroke-width:1.5px
classDef proc fill:#ffffff,stroke:#c8c8c8,color:#171717,stroke-width:1px
classDef decision fill:#FFF3CD,stroke:#E0A800,color:#5A4100,stroke-width:1.5px
classDef good fill:#D9F0E4,stroke:#00A651,color:#0A5A32,stroke-width:1.5px
classDef danger fill:#FDE1E7,stroke:#EA002C,color:#8A0019,stroke-width:1.5px
classDef vendor fill:#FFF3CD,stroke:#E0A800,color:#5A4100,stroke-width:1.5px
class A start
class B,E,F,G proc
class C,H decision
class D,I good
class J danger
class K vendor관련 문서
1 - SBOM 제출 요구사항
SK텔레콤 정책에 따른 표준 SBOM 형식, 필수 포함 정보, PURL 식별자 규칙을 상세히 정의합니다.
1. 표준 데이터 형식
SK텔레콤은 글로벌 표준으로 자리 잡은 두 가지 형식을 모두 지원합니다. 공급사는 사용하는 도구가 지원하는 형식을 선택하여 제출할 수 있습니다.
| 형식 | 버전 | 권장 용도 | 파일 형식 |
|---|
| CycloneDX | v1.3, v1.4, v1.5, v1.6, v1.7 | 애플리케이션 보안, 취약점 관리 중심 | JSON (권장), XML |
| SPDX | v2.2, v2.3 | 라이선스 컴플라이언스 중심 | JSON, Tag-Value |
참고: 두 형식 모두 동등하게 인정되나, 내부 시스템 연동성을 위해 CycloneDX (JSON) 형식을 권장합니다.
요구 수준 요약
각 항목의 요구 수준입니다. 필수 항목이 누락되면 반려됩니다. 권장 항목은 없어도 반려되지 않지만 포함을 권합니다.
| 항목 | 수준 | 상세 |
|---|
| 표준 포맷과 버전 (CycloneDX 또는 SPDX) | 필수 | 1. 표준 데이터 형식 |
| 메타데이터 (생성 일시, 생성 도구, 최상위 컴포넌트) | 필수 | 2.1 메타데이터 |
| 컴포넌트 이름과 버전 | 필수 | 2.2 컴포넌트 정보 |
| 직접·전이적 의존성 포함 | 필수 | 2.3 의존성 범위 |
PURL(Package URL, 소프트웨어 패키지를 표준 형식으로 가리키는 식별자. pkg: 형식, 규격에 정의된 타입, 네임스페이스 필수 타입은 생략 불가) | 필수 | 3. PURL 준수 |
| 개발 전용 의존성 | 권장 | 2.3 의존성 범위 |
| 라이선스 정보 | 권장 | 4. 샘플 문서 |
| 자체개발 구성요소 (공급사가 직접 만들어 배포하는 실행 파일, 라이브러리, 펌웨어, 압축 파일과 스캔으로 찾지 못하는 벤더 바이너리, 복사해 넣은 소스. 공급자, 라이선스, 해시 포함) | 권장 | 5. 자체개발 구성요소 |
합격 기준을 충족하는 예시 SBOM 파일 (CycloneDX 1.6 JSON)을 내려받아 구조를 비교해 보시기 바랍니다.
2. 필수 포함 정보
제출하는 SBOM 문서에는 다음 정보가 반드시 포함되어야 합니다. 정보가 누락되면 반려될 수 있습니다.
문서 자체와 생성 도구에 대한 정보입니다.
- Timestamp: 생성 일시 (ISO 8601 형식)
- Tool Info: 생성 도구의 벤더, 이름, 버전 (예:
CycloneDX-Maven-Plugin v2.7.9) - Component Info: 납품하는 최상위 소프트웨어의 명칭 및 버전
Component Info의 명칭 값은 장비·제품을 특정할 수 있는 고유한 값이어야 합니다. 빈 값, .처럼 의미 없는 값, 생성 도구가 자동으로 채우는 고정 경로 값(예: /scan)은 다른 제출 건과 값이 겹쳐 등록이 거부됩니다. SK텔레콤은 이 값을 제출 건 전체에서 고유해야 하는 식별자로 취급합니다.
파일 이름과 일치
여러 층(OS·애플리케이션 등)으로 나눠 제출하는 경우, 각 층의 최상위 컴포넌트 이름과 버전은 그 SBOM 파일 이름의 앞부분({이름}_{버전})과 같은 값이어야 합니다. 예를 들어 파일 이름이 myserver-os_1.0.0_bom.json이면 metadata.component.name(CycloneDX) 또는 DocumentName(SPDX)은 myserver-os, 버전은 1.0.0이어야 합니다.
재제출할 때는 이 이름을 그대로 유지하시기 바랍니다. 이 이름이 스캔의 식별자이므로, 이름이 바뀌면 이전 제출분이 지워지지 않고 남아 이미 조치한 취약점이 계속 집계됩니다.
BomLens로 생성하면 --project와 --version 값이 이 필드에 자동으로 채워지므로 따로 손댈 필요가 없습니다. 층별 파일 이름 규칙은 오픈소스 도구 활용의 층별로 제출 절을 참고하세요.
생성 도구 명시 형식
생성 도구 정보는 형식에 따라 다음 필드에 기재해야 합니다.
- SPDX:
creationInfo.creators 필드에 Tool: 접두어로 도구명과 버전 기재 - CycloneDX:
metadata.tools 배열에 vendor, name, version 기재
// SPDX creationInfo 예시
"creationInfo": {
"created": "2026-04-06T03:22:00Z",
"creators": ["Tool: Syft-0.98.0", "Organization: VendorName"]
}
2.2 컴포넌트 정보 (Components)
소프트웨어를 구성하는 개별 라이브러리와 패키지 정보입니다. 공급사가 직접 만든 구성요소도 여기에 함께 적을 수 있습니다(5. 자체개발 구성요소 참고).
- Name: 컴포넌트 이름 (예:
commons-lang3) - Version: 컴포넌트 버전 (예:
3.12.0) — 필수. SPDX는 versionInfo, CycloneDX는 version 필드에 정확한 버전을 기재합니다. 버전이 없으면 취약점 매핑이 불가능합니다. - PURL (Package URL): [필수] 패키지 식별자
2.3 의존성 범위 (Dependency Scope)
중요: 전이적 의존성(Transitive Dependencies)을 반드시 포함해야 합니다.
SK텔레콤은 제출된 SBOM을 기반으로 취약점을 분석합니다. 직접 의존성만 포함된 SBOM은 숨겨진 취약점을 놓칠 수 있으므로 반려될 수 있습니다.
| 의존성 종류 | 설명 | 포함 여부 |
|---|
| 직접 의존성 (Direct) | 프로젝트가 직접 선언한 라이브러리 | 필수 |
| 전이적 의존성 (Transitive) | 직접 의존성이 다시 의존하는 라이브러리 | 필수 |
| 개발 전용 의존성 (Dev-only) | 테스트, 빌드 도구 등 런타임 미포함 라이브러리 | 권장 포함 |
전이적 의존성이란?
예를 들어 프로젝트가 library-A를 직접 사용하고, library-A가 내부적으로 library-B를 사용하는 경우, library-B가 전이적 의존성입니다. library-B에 취약점이 있어도 SBOM에 포함되지 않으면 탐지할 수 없습니다.
올바른 SBOM 생성을 위한 전제 조건
전이적 의존성이 정확하게 포함되려면 빌드(또는 패키지 설치)가 완료된 상태에서 SBOM을 생성해야 합니다. 소스코드만 있는 상태에서는 전이적 의존성이 누락될 수 있습니다.
- Java (Maven):
mvn package 또는 mvn dependency:resolve 실행 후 생성 - Java (Gradle):
./gradlew dependencies 실행 후 생성 - Python:
pip install -r requirements.txt (가상환경 활성화) 후 생성 - Node.js:
npm install 또는 yarn install 실행 후 생성 - Go:
go mod download 실행 후 생성
각 도구별 전이적 의존성 포함 방법은 오픈소스 도구 활용 가이드를 참고하시기 바랍니다.
3. Package URL (PURL) 준수
PURL(Package URL)은 소프트웨어 패키지를 고유하게 식별하기 위한 표준 URL 형식입니다. SK텔레콤의 취약점 분석 시스템은 PURL을 기준으로 동작하므로, 모든 컴포넌트에 유효한 PURL이 포함되어야 합니다.
여기서 컴포넌트는 SBOM의 components 목록(개별 라이브러리·패키지)을 뜻하며, 최상위 제품 자체(SBOM 메타데이터의 컴포넌트 정보)에는 적용되지 않습니다. 공급자와 SHA-512 해시를 갖춘 자체개발 구성요소도 PURL 없이 제출할 수 있습니다(5. 자체개발 구성요소 참고).
PURL은 반드시 pkg: 접두어로 시작하는 표준 형식이어야 합니다. name:version, org/repo:tag 등 자유 텍스트는 허용되지 않으며, 이 경우 취약점 매핑이 불가능해 반려됩니다.
형식이 유효해 보여도 매칭에 실패하는 PURL이 있습니다. 아래 세 규칙은 스키마 검사로는 걸러지지 않으므로 특히 주의하시기 바랍니다.
3.1 규격에 정의된 타입
타입 자리에는 Package URL 규격이 정의한 타입만 쓸 수 있습니다. maven, npm, pypi, rpm처럼 생태계와 조회할 저장소를 특정하는 이름이며, 전체 목록은 규격 저장소의 purl-types-index.json에서 확인할 수 있습니다.
규격에 없는 이름을 임의로 넣으면(예: pkg:applications/java@11.0.25) 형식 검사는 통과하지만 어느 저장소를 조회해야 할지 판단할 수 없어 매칭이 실패합니다. 생태계를 특정하지 못하는 pkg:generic/도 같은 이유로 허용되지 않습니다.
3.2 네임스페이스가 필수인 타입
네임스페이스는 타입과 패키지 이름 사이의 자리입니다. 규격이 이 자리를 필수로 정한 타입은 다음과 같습니다.
alpm apk bitbucket composer deb git github golang huggingface maven qpkg rpm swift vscode-extension
이 자리가 비면 형식은 유효해 보여도 패키지를 특정할 수 없어 매칭이 되지 않고 반려됩니다. 실제 접수에서 가장 많이 발견되는 유형은 다음 두 가지입니다.
- Maven: groupId가 네임스페이스에 와야 합니다.
pkg:maven/org.slf4j/jcl-over-slf4j@2.0.15가 올바른 형태이고, groupId와 artifactId를 점으로 이어 붙인 pkg:maven/org.slf4j.jcl-over-slf4j@2.0.15는 저장소에 존재하지 않는 좌표라 반려됩니다. - OS 패키지(rpm, deb, apk): 배포판이 네임스페이스에 와야 합니다(
pkg:rpm/rhel/bind@9.11.36-16.el8_10.6). Red Hat 계열은 rhel과 redhat 표기를 모두 인정합니다.
배포판 값은 반드시 이 위치(네임스페이스)에 있어야 인식됩니다. 물음표 뒤 쿼리 파라미터(예: ?distro=rhel-8.10)에 넣는 것은 인정되지 않습니다. 이 값은 부가 정보로만 취급되어 매칭에 쓰이지 않으며, 네임스페이스가 비어 있으면 위와 똑같이 반려됩니다.
3.3 네임스페이스에 들어갈 값
네임스페이스에는 저장소가 실제로 쓰는 식별자를 그대로 넣어야 합니다. 사람이 읽는 회사 이름이나 URL은 식별자가 아닙니다. 생성 도구가 매니페스트의 벤더 문자열을 groupId 자리에 그대로 옮기면 pkg:maven/The%2BApache%2BSoftware%2BFoundation/poi@5.4.1이나 pkg:maven/http%3A/www.jboss.org/jbossxts@1.1 같은 형태가 되는데, 둘 다 저장소에 없는 좌표라 매칭되지 않습니다. Maven이라면 pkg:maven/org.apache.poi/poi@5.4.1처럼 실제 groupId를 기재해야 합니다.
3.4 언어별 PURL 예시
| 생태계 | PURL 형식 예시 |
|---|
| Java (Maven) | pkg:maven/org.springframework/spring-core@5.3.20 |
| JavaScript (NPM) | pkg:npm/express@4.18.2 |
| Python (PyPI) | pkg:pypi/django@4.1.0 |
| Go | pkg:golang/github.com/gin-gonic/gin@v1.8.1 |
| .NET (NuGet) | pkg:nuget/Newtonsoft.Json@13.0.1 |
| Ruby (RubyGems) | pkg:gem/rails@7.0.4 |
| GitHub (Actions·소스 호스팅) | pkg:github/actions/checkout@v3 |
| OS 패키지 (RPM) | pkg:rpm/centos/glibc@2.17-317.el7?arch=x86_64 |
3.5 올바른 / 잘못된 PURL 예시
| 잘못된 예 | 올바른 예 |
|---|
commons-lang3:3.12.0 | pkg:maven/org.apache.commons/commons-lang3@3.12.0 |
actions/checkout:v3 | pkg:github/actions/checkout@v3 |
lodash@4.17.21 | pkg:npm/lodash@4.17.21 |
pkg:generic/foo@1.0 | (생태계에 맞는 타입으로 변경) |
pkg:applications/java@11.0.25 | (규격에 정의된 타입으로 변경) |
pkg:maven/org.slf4j.jcl-over-slf4j@2.0.15 | pkg:maven/org.slf4j/jcl-over-slf4j@2.0.15 |
pkg:maven/The%2BApache%2BSoftware%2BFoundation/poi@5.4.1 | pkg:maven/org.apache.poi/poi@5.4.1 |
pkg:rpm/bind@9.11.36-16.el8_10.6 | pkg:rpm/rhel/bind@9.11.36-16.el8_10.6 |
pkg:rpm/bind@9.11.36-16.el8_10.6?distro=rhel-8.10 | pkg:rpm/rhel/bind@9.11.36-16.el8_10.6 |
PURL에 대한 자세한 사양은 Package URL 공식 스펙을 참고하시기 바랍니다.
4. 샘플 문서
CycloneDX 샘플
{
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"version": 1,
"metadata": {
"timestamp": "2026-04-06T10:30:00Z",
"tools": [{
"vendor": "Example Corp",
"name": "cyclonedx-maven-plugin",
"version": "2.7.9"
}],
"component": {
"type": "application",
"name": "PaymentModule",
"version": "2.1.0",
"purl": "pkg:maven/com.example/payment-module@2.1.0"
}
},
"components": [{
"type": "library",
"name": "spring-core",
"version": "5.3.20",
"purl": "pkg:maven/org.springframework/spring-core@5.3.20",
"licenses": [{
"license": {
"id": "Apache-2.0"
}
}]
}]
}
5. 자체개발 구성요소
소스코드 스캔은 패키지 매니저와 lock 파일로 들어온 오픈소스를 찾습니다. 공급사가 직접 빌드한 실행 파일이나 라이브러리, 칩 제조사가 준 바이너리, 패키지 매니저 없이 소스 트리에 복사해 넣은 코드는 찾지 못하므로 SBOM에서 빠집니다. SK텔레콤은 이런 구성요소도 SBOM에 적기를 권장합니다. 권장 항목이므로 없어도 반려되지 않습니다.
왜 권장하나요?
- 독일 연방정보보안청(BSI)의 기술 지침 BSI TR-03183-2 v2.1.0은 SBOM의 범위를 공급자나 제3자가 만들어 제품과 함께 전달하는 모든 소프트웨어 부분으로 정합니다(8.1.11). 실행 파일과 압축 파일은 구성요소로 적어야 합니다(3.2.1).
- EU 사이버 복원력법(CRA, Cyber Resilience Act) 부속서 I 제2부 1항은 제조사에게 최소한 최상위 의존성을 담은 SBOM을 작성하도록 요구합니다.
- 유럽 고객사 중에는 오픈소스뿐 아니라 공급사 자체 소프트웨어까지 담은 SBOM을 요구하는 곳이 있습니다. 같은 SBOM을 SK텔레콤 제출과 다른 고객사 제출에 함께 쓸 수 있습니다.
무엇을 적나요?
스캔이 찾지 못하는 구성요소만 적습니다. 패키지 매니저로 들어와 스캔이 이미 찾은 오픈소스는 다시 적지 않습니다.
- 직접 만들어 배포하는 산출물: 실행 파일, 라이브러리, 펌웨어 이미지, 압축 파일. 배포하는 파일마다 구성요소 하나로 적습니다.
- 벤더가 준 바이너리: 칩 제조사의 드라이버나 미리 빌드된 라이브러리
- 소스로 복사해 넣은 제3자 코드: HAL, RTOS처럼 패키지 매니저 없이 소스 트리에 넣은 코드
구성요소마다 이름, 버전, 공급자(이름과 함께 URL이나 이메일), 배포 라이선스를 적고, 파일로 배포되는 구성요소에는 SHA-512 해시를 함께 적습니다. 자체 라이선스처럼 SPDX License List에 없는 라이선스는 LicenseRef-로 시작하는 이름(예: LicenseRef-ExampleCorp-Proprietary)으로 적습니다.
자체개발 구성요소는 패키지 저장소에 올라가지 않으므로 PURL이 없습니다. 공급자와 SHA-512 해시가 있는 자체개발 구성요소는 3절의 PURL 요구에서 제외됩니다. 벤더 바이너리나 복사해 넣은 소스처럼 다른 곳에서 받은 구성요소에는 PURL이 계속 필요합니다.
선언 파일 예시
BomLens를 쓰면 스캔이 찾지 못하는 구성요소를 저장소의 sbom-declared.cdx.json 파일에 적어 둡니다. 내용은 components만 담은 CycloneDX 문서이며, 필드 이름은 CycloneDX 표준 그대로입니다. bomlens:origin 속성으로 직접 만든 구성요소(first-party)와 다른 곳에서 받은 구성요소(third-party)를 구분하고, bomlens:artifact 속성에 빌드 산출물 경로를 적습니다.
{
"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:artifact", "value": "out/bin/media-daemon" }
]
},
{
"type": "library",
"name": "vendor-hal",
"version": "4.2.0",
"supplier": { "name": "Example Chip Vendor", "url": ["https://chip.example.com"] },
"licenses": [ { "license": { "id": "BSD-3-Clause" } } ],
"properties": [
{ "name": "bomlens:origin", "value": "third-party" }
]
}
]
}
버전을 적지 않은 first-party 구성요소는 제품 버전(--version)을 씁니다. third-party 구성요소는 받은 버전을 반드시 적습니다. 펌웨어에 컴파일되어 들어간 HAL처럼 별도 파일이 없는 구성요소는 bomlens:artifact 없이 적습니다.
BomLens로 SBOM에 넣기
빌드를 먼저 실행해 선언 파일이 가리키는 산출물을 만든 뒤 스캔합니다. BomLens는 선언한 구성요소를 SBOM에 넣고, 빌드 산출물에서 SHA-512와 SHA-256 해시, 파일 이름, 실행 파일인지와 압축 파일인지를 읽어 채웁니다. 스캔 대상 루트에 sbom-declared.cdx.json이 있으면 옵션 없이 읽고, 다른 위치의 파일은 --components로 지정합니다(여러 파일이면 옵션을 반복).
make # 선언 파일이 가리키는 빌드 산출물(예: out/bin/media-daemon)을 만든다
/path/to/scripts/scan-sbom.sh --project "MediaBox" --version "2.1.0" \
--components sbom-declared.cdx.json \
--generate-only
BSI TR-03183-2 기준 검사가 필요하면 다음 옵션을 더합니다. --supplier는 제품의 공급자를, --sbom-author는 SBOM 작성자를, --license는 제품의 배포 라이선스를 기록합니다. 기준을 충족하지 못하면 --fail-on-conformance가 CI 작업을 실패로 끝냅니다.
/path/to/scripts/scan-sbom.sh --project "MediaBox" --version "2.1.0" \
--components sbom-declared.cdx.json \
--generate-only \
--conformance-profile bsi-tr-03183-2 --fail-on-conformance \
--supplier "Example Corp <https://example.com>" \
--sbom-author "Example Corp <sbom@example.com>" \
--license Apache-2.0
선언 파일 규칙에 맞지 않는 파일(예: bomlens:origin이 없거나, 가리킨 빌드 산출물이 없는 경우)은 스캔이 거부하고 CI 작업이 실패합니다. --components 옵션과 bsi-tr-03183-2 검사 기준은 BomLens v1.14.0부터 쓸 수 있습니다. 파일 형식과 거부 규칙, 플랫폼별 예시(Android, Zephyr, 베어메탈 펌웨어, Yocto), GitHub Actions 예시는 BomLens의 자체 구성요소 선언 가이드를 참고하세요.
참고 자료
관련 문서
2 - BomLens
BomLens로 SK텔레콤 정책에 맞는 SBOM을 생성하는 방법을 안내합니다.
BomLens
BomLens는 공급사가 Docker 환경에서 SK텔레콤 정책에 맞는 산출물을 생성할 수 있는 오픈소스 도구입니다. 로컬에 언어별 도구를 따로 설치하지 않아도 여러 언어를 분석해 CycloneDX(JSON) 산출물을 만듭니다.
이 페이지는 제출과 관련된 산출물과 제출 전 점검만 다룹니다. 설치, 실행 방법, 전체 옵션, 웹 UI 등 사용법은 아래 BomLens 문서가 정본입니다.
github.com/sktelecom/bomlens
버그 제보, 기능 제안, Pull Request 기여를 환영합니다.
생성되는 산출물
한 번의 실행으로 다음 네 가지가 함께 {프로젝트}_{버전}/ 하위 폴더에 생성됩니다(--all 옵션). 오픈소스위험분석보고서는 --no-report로 끌 수 있으며, 적합성 리포트는 항상 생성됩니다(현재 끄는 옵션 없음).
| 산출물 | 파일 | 용도 |
|---|
| SBOM | {프로젝트}_{버전}_bom.json | CycloneDX 1.6 구성요소 명세 (납품 기준 산출물) |
| 오픈소스 고지문 | {프로젝트}_{버전}_NOTICE.{txt,html} | 라이선스 의무 이행을 위한 고지문 |
| 오픈소스위험분석보고서 | {프로젝트}_{버전}_risk-report.{md,html} | 라이선스와 취약점 위험 집계 |
| 적합성 리포트 | {프로젝트}_{버전}_conformance.{json,md,html} | 제출 품질 기준 충족 여부와 누락 항목 |
적합성 리포트 파일은 매 실행마다 생성되지만, 웹 UI의 통과/실패 판정 화면은 이미 만들어진 SBOM을 --analyze로 다시 넣었을 때만 나타납니다(방금 생성한 SBOM이 자기 자신을 채점하는 건 대부분의 항목에서 의미 있는 신호가 아니기 때문입니다). 제출 전 점검은 아래처럼 한 단계 더 거치세요.
./scripts/scan-sbom.sh --analyze myserver_1.0.0_bom.json --project myserver --version 1.0.0 --generate-only
시작하기
BomLens는 Docker 위에서 동작하므로 Docker 엔진 20.10 이상이 필요합니다. 설치와 첫 SBOM 생성은 시작하기를, 명령줄이 익숙하지 않다면 설치형 앱과 웹 UI를 안내하는 명령줄 없이 시작하기를 따릅니다. 제출 전까지는 --generate-only 옵션으로 로컬에 파일만 생성하기를 권장합니다.
더 알아보기
도구 사용법의 정본은 저장소 문서입니다.
다음 단계
SBOM을 생성한 뒤 검증 체크리스트로 파일을 확인하고 제출 절차에 따라 제출합니다. 필수 데이터 필드는 제출 요구사항, SKT 도구 대신 cdxgen, Syft 등을 직접 쓰는 방법은 오픈소스 도구 활용을 참고하세요.
3 - 오픈소스 도구를 활용한 SBOM 생성
범용 오픈소스 도구를 활용하여 환경별로 SBOM을 생성하는 방법을 안내합니다.
이미 운영 중인 자체 도구 체계가 있다면 그 도구로 SBOM을 생성하고, 아래 도구 선택 가이드를 참고해 빠진 부분을 보완합니다. 아직 도구 체계가 없다면 Docker만 설치되어 있으면 BomLens 하나로 소스코드, 컨테이너 이미지, 서버 rootfs, 실행 파일, 펌웨어를 모두 스캔할 수 있습니다.
도구 선택 가이드
graph TD
A{{"공급 소프트웨어 분류"}}
subgraph G1["소프트웨어 공급"]
direction LR
T1["소스코드·앱<br>(예: OSS/BSS, 관리 포털, 미들웨어)"]
T2["실행 파일·라이브러리<br>(예: .jar, .dll, .so)"]
T3["OS 없는 펌웨어<br>(예: 베어메탈·RTOS 단말)"]
end
subgraph G2["OS(예: Linux) 포함 공급"]
direction LR
T4["컨테이너 이미지<br>(예: CNF, 컨테이너형 네트워크 기능)"]
T5["서버·VM 이미지<br>(예: VNF, 서버 어플라이언스)"]
T6["OS 내장 펌웨어<br>(예: 기지국, 라우터, OLT/ONT, 셋톱박스)"]
end
%% 좌측: 소스코드 스캔 서브 박스 구조
subgraph M1["소스코드 스캔"]
M1_Sub["BomLens 또는 cdxgen"]
end
%% 우측: 소스코드 + OS 이미지 스캔 서브 박스 구조 (세로 배치)
subgraph M2["소스코드 + OS 이미지 스캔"]
direction TB
M2_Top["OS (예: Linux) 스캔<br>(BomLens 또는 Syft·Trivy,<br>OS 내장 펌웨어는 BomLens)"]
M2_Bottom["소스코드 스캔<br>(BomLens 또는 cdxgen)"]
end
A --> G1
A --> G2
%% 그룹 박스 경계로만 연결 (박스당 화살표 1개)
G1 --> M1
G2 --> M2
%% 그룹 박스에서 다음 단계로 연결
M1 --> P(["SBOM 제출"])
M2 --> P
classDef start fill:#F2F2F2,stroke:#171717,color:#171717,stroke-width:1.5px
classDef typebox fill:#ffffff,stroke:#c8c8c8,color:#171717,stroke-width:1px
classDef submit fill:#F2F2F2,stroke:#171717,color:#171717,stroke-width:1.5px
%% 내부 단일 박스용 흰색 스타일 정의 (좌/우 테두리 색상 구분)
classDef subwhite_left fill:#ffffff,stroke:#00A651,color:#171717,stroke-width:1px
classDef subwhite_right fill:#ffffff,stroke:#68127A,color:#171717,stroke-width:1px
class A start
class T1,T2,T3,T4,T5,T6 typebox
class M1_Sub subwhite_left
class M2_Top,M2_Bottom subwhite_right
class P submit
style G1 fill:#F1FAF5,stroke:#00A651,stroke-width:1px,color:#0A5A32
style G2 fill:#FAF4FB,stroke:#68127A,stroke-width:1px,color:#4A0D57
%% 외곽 박스 스타일 (배경색 및 테두리 유지)
style M1 fill:#D9F0E4,stroke:#00A651,stroke-width:1px,color:#0A5A32
style M2 fill:#EEDCF3,stroke:#68127A,stroke-width:1px,color:#4A0D57소스코드·앱, 실행 파일이나 라이브러리, OS 없는 펌웨어는 모두 자기가 개발한 소스코드를 BomLens 또는 cdxgen으로 스캔합니다. 완성된 바이너리를 그대로 스캔하면 패키지 매니저 메타데이터가 없어 purl이 누락되고 반려됩니다.
OS나 베이스 이미지를 포함해 공급하는 경우(컨테이너 이미지, 서버, OS 내장 펌웨어)는 두 층으로 나눠 각각 스캔해 함께 제출합니다. OS 층은 납품되는 상태의 이미지나 rootfs를 BomLens 또는 Syft·Trivy로, 소스코드(앱 층)는 BomLens 또는 cdxgen으로 스캔합니다. OS 내장 펌웨어의 OS 층은 펌웨어 파일이나 OS 영역 폴더를 BomLens로 스캔합니다. 층별 명령과 파일 이름 규칙은 아래 서버 납품에 있습니다.
타사가 제조한 상용 소프트웨어나 완제품을 공급해 소스코드에 접근할 수 없는 경우는 스캔 대신 제조사로부터 SBOM을 받아 제출합니다. 상용 소프트웨어 공급을 참고하세요.
주요 도구 안내
BomLens (SK텔레콤 제공)
SK텔레콤이 만든 SBOM 생성 도구입니다. 소스코드, 컨테이너 이미지, 서버 rootfs, 실행 파일, 펌웨어를 아래 오픈소스 도구들을 개별적으로 설치하지 않고 하나의 Docker 컨테이너로 스캔합니다. 최상위 컴포넌트 이름 자동 기입, 제출 전 자체 검증(적합성 리포트) 등 SK텔레콤 제출 기준에 맞춘 기능이 포함되어 있습니다.
제출 전에는 --conformance-profile skt-submission 옵션으로 SK텔레콤 심사 기준(PURL 포함률 100% 등)을 미리 확인하시기 바랍니다. 자세한 내용은 검증 체크리스트를 참고하세요. 스캔 중 오류가 나거나 결과가 이상하면 자주 발생하는 반려 사유에서 비슷한 사례를 먼저 확인하시기 바랍니다.
BomLens로 처리되지 않는 경우이거나 오픈소스 도구를 직접 조합해서 쓰려면 아래를 참고하시기 바랍니다.
cdxgen (소스코드 분석)
Java, Python, Node.js, Go 등 다양한 언어 프로젝트를 자동 분석하여 CycloneDX 형식의 SBOM을 생성합니다.
cdxgen은 lockfile이나 매니페스트를 정적으로 해석합니다. 정확한 결과를 얻으려면 의존성이 설치되거나 해결된 상태(lockfile이 있거나 빌드한 뒤)에서 실행하시기 바랍니다. 의존성이 해결되지 않은 순수 소스만 스캔하면 일부 컴포넌트나 purl이 누락될 수 있습니다.
Syft (컨테이너 이미지 및 바이너리 분석)
빌드된 컨테이너 이미지나 패키지 매니저 메타데이터가 포함된 빌드 산출물을 분석하여 OS 패키지와 애플리케이션 라이브러리를 모두 식별합니다. CycloneDX 및 SPDX 형식을 지원합니다.
경고 — 설치 디렉터리나 원시 파일 모음은 스캔하지 마십시오 (purl 누락으로 전량 반려)
syft dir: 모드로 패키지 매니저 메타데이터(package.json, go.mod, *.jar, RPM/DEB 패키지 DB 등)가
없는 설치 디렉터리나 바이너리 모음을 스캔하면, Syft가 생태계(ecosystem)를 식별하지 못해 purl이 비어 있는
SBOM이 생성됩니다. SK텔레콤 시스템은 purl로 취약점을 매핑하므로, 이런 SBOM은 매칭이 전량 실패하여 반려됩니다.
이렇게 반려된 실제 사례는 자주 발생하는 반려 사유를 참고하십시오.
Syft는 다음 대상으로 실행하시기 바랍니다.
# 권장: 빌드된 이미지 스캔 (purl과 생태계를 자동 식별)
syft <이미지명>:<태그> -o cyclonedx-json=sbom.json
# 비권장: 설치 디렉터리나 원시 파일 스캔 (purl 누락으로 반려)
syft dir:/root/nag_pkg # 패키지 매니저 메타데이터가 없으면 purl이 0개가 됩니다
생성 직후 반드시 purl 개수를 확인하시기 바랍니다. 검증 방법은 검증 체크리스트를 참고하십시오.
Trivy (컨테이너 이미지 분석)
컨테이너 이미지 분석과 취약점 스캔을 함께 수행할 수 있는 올인원 도구입니다.
보안 경고 — Trivy 공급망 공격 사례 (2026년)
2026년 3월, 공격자가 aquasecurity/trivy의 기존 릴리즈 태그를 재지정하여 악성코드를 삽입하는
공급망 공격이 발생하였습니다. GitHub 릴리즈 v0.69.4(3/19) 및 DockerHub 이미지
v0.69.5·v0.69.6(3/22)이 오염된 것으로 확인되었으므로 사용을 중단하시기 바랍니다.
Trivy를 안전하게 사용하려면 다음 원칙을 따르시기 바랍니다.
GitHub Actions: 가변 태그(@master, @latest, @v1 등) 대신 고정된 Commit SHA 또는 검증된 버전 태그를 사용합니다.
# 권장: 검증된 버전 고정
- uses: aquasecurity/trivy-action@0.35.0
# 더 안전: Commit SHA 고정
- uses: aquasecurity/trivy-action@<commit-sha>
Docker 이미지: 특정 버전 태그를 명시하거나 이미지 다이제스트(@sha256:...)로 고정합니다.
docker run aquasecurity/trivy:<검증된-버전> image <대상-이미지>
공식 채널: GitHub Security Advisory를 통해 최신 보안 권고사항을 확인합니다.
이 사례는 오픈소스 도구를 도입할 때 버전을 고정하지 않으면 언제든 공급망 공격에 노출될 수 있음을 보여줍니다. 모든 외부 도구는 버전을 명시하고 무결성을 검증한 뒤 사용하시기 바랍니다.
언어별 전용 플러그인
빌드 도구 플러그인을 사용하면 더 정확한 의존성 정보를 추출할 수 있습니다.
| 언어/빌드 도구 | 플러그인/도구 | 공식 문서 |
|---|
| Java (Maven) | cyclonedx-maven-plugin | 링크 |
| Java (Gradle) | cyclonedx-gradle-plugin | 링크 |
| Python | cyclonedx-bom | 링크 |
| Node.js | @cyclonedx/cyclonedx-npm | 링크 |
| Go | cyclonedx-gomod | 링크 |
서버 납품
OS나 베이스 이미지를 포함해 공급하는 경우(서버, 컨테이너 이미지, OS 내장 펌웨어)에 해당합니다. 두 층을 각각 만들어 함께 제출합니다.
| 층 | 대상 | 누락 시 증상 |
|---|
| OS | 운영체제와 설치된 패키지 전체 (예: RHEL과 rpm 데이터베이스의 모든 패키지) | OS 취약점 누락 |
| 애플리케이션 | 납품 애플리케이션과 패키지 매니저 의존성(직접·전이) | 앱 의존성 누락 |
두 층으로 나눠 스캔
OS 층은 서버의 rootfs(추출한 루트 파일시스템)나 그 컨테이너 이미지를 대상으로 합니다. 패키지 데이터베이스(rpm/dpkg/apk)를 읽어 설치된 패키지를 모두 실제 purl(pkg:rpm/...)로 식별합니다. 대상은 받아온 원본 베이스가 아니라 빌드가 끝나 납품되는 상태여야 합니다. 빌드 과정에서 설치한 OS 패키지까지 포함해야 하기 때문입니다. 설치 파일만 풀어 놓고 패키지 데이터베이스가 없는 폴더를 스캔하면 purl이 비어 반려됩니다.
대상은 rootfs의 루트여야 합니다. 하위 디렉터리만 지정하면 패키지 데이터베이스는 읽혀도 배포판이 판정되지 않습니다. Syft는 대상 안의 /etc/os-release로 배포판을 정하고 그 값을 purl에 넣습니다. 정상이라면 pkg:rpm/rhel/bind@9.11.36-16.el8_10.6처럼 타입과 패키지 이름 사이에 배포판이 들어갑니다. 이 자리가 비면 형식 검증은 통과하지만 SK텔레콤 시스템이 패키지를 식별하지 못해 OS 패키지가 전량 미매칭으로 반려됩니다. 스캔 전에 대상 안에 이 파일이 있는지 확인하시기 바랍니다.
주의: rootfs를 감싼 릴리스 폴더를 그대로 지정하지 마십시오
--target은 rootfs 폴더 자체를 가리켜야 합니다. 납품 산출물이 릴리스-20260919/rootfs/처럼 릴리스 폴더 한 겹 아래 rootfs가 들어있는 경우 그 릴리스 폴더를 그대로 주면, BomLens 1.13.2 이하 버전은 rootfs로 인식하지 못하고 조용히 일반 소스 스캔으로 처리해 컴포넌트가 거의 없는 SBOM을 만듭니다. 1.13.3부터는 이런 폴더를 만나면 스캔을 멈추고 지정할 --target을 안내하므로, 안내된 대상으로 다시 실행하시기 바랍니다. 릴리스 폴더 전체를 .tar.gz나 .zip으로 압축해서 지정해도 됩니다(압축 파일은 안에 rootfs가 한두 단계 아래 있어도 자동으로 찾습니다).
# 대상 안에 배포판 정보가 있는지 먼저 확인
cat /path/to/server-rootfs/etc/os-release
# BomLens로 (rootfs 디렉터리를 그대로 대상으로 지정, 최상위 컴포넌트 이름도 자동 기입)
./scan-sbom.sh --project myserver-os --version 1.0.0 --target /path/to/server-rootfs --generate-only
# 오픈소스 도구를 직접 쓰려면: rootfs 디렉터리를 대상으로
syft dir:/path/to/server-rootfs -o cyclonedx-json=myserver-os_1.0.0_bom.json
# 서버가 컨테이너 이미지로 패키징돼 있다면(BomLens는 이미지 이름을 그대로 대상으로 지정)
./scan-sbom.sh --project myserver-os --version 1.0.0 --target myserver:7 --generate-only
syft myserver:7 -o cyclonedx-json=myserver-os_1.0.0_bom.json
애플리케이션 층은 빌드를 마친 뒤 애플리케이션 소스를 스캔합니다. 패키지 매니저(Maven, npm, pip, Go modules, Conan 등)를 쓰면 전이 의존성까지 자동으로 해석됩니다.
cd /path/to/app-source
cdxgen -o myserver-app_1.0.0_bom.json
# 또는 BomLens로
./scan-sbom.sh --project myserver-app --version 1.0.0 --target /path/to/app-source --generate-only
OS 층 스캔에 파이썬이나 Node.js처럼 파일로 설치된 의존성이 함께 잡히기도 합니다. 그래도 애플리케이션 층은 따로 만드시기 바랍니다. C/C++처럼 소스에 라이브러리를 포함하는 방식은 OS 층 스캔으로 전혀 식별되지 않습니다.
애플리케이션 소스만 스캔하면 OS 패키지가 통째로 빠집니다
서버 납품인데 애플리케이션 소스 트리만 스캔해 제출하는 사례가 반복됩니다. 이 경우 설치된 rpm 패키지가 하나도 담기지 않아, OS를 업그레이드해도 그 결과가 SBOM에 나타나지 않습니다. 두 층을 모두 만들었는지 확인하시기 바랍니다.
OS 내장 펌웨어(기지국, 라우터 등)
기지국, 라우터, OLT/ONT, 셋톱박스처럼 OS를 내장한 펌웨어도 위와 같은 두 층 구조입니다. 다만 OS 층은 위의 서버 방식(rootfs를 Syft나 Trivy로 스캔)으로 만들면 안 됩니다. 임베디드 장비에는 대개 패키지 정보가 없어서 오픈소스가 거의 식별되지 않는 SBOM이 만들어집니다. OS 층은 BomLens 1.13.9 이상으로 아래와 같이 만듭니다.
장비에 설치하는 펌웨어 파일이나, 빌드 과정에서 만들어진 OS 영역 폴더(rootfs)를 지정해 스캔합니다. 둘 중 가지고 있는 것을 쓰면 되고, 결과는 같습니다. 생성된 mydevice-os_1.0.0_bom.json 하나를 제출하면 됩니다. 같은 폴더에 생기는 고지문, 보안 보고서 등은 공급사가 자체 점검에 쓰는 자료입니다.
# 펌웨어 파일을 스캔할 때
./scan-sbom.sh --project mydevice-os --version 1.0.0 --target /path/to/firmware.bin --firmware --generate-only
# OS 영역 폴더를 스캔할 때
./scan-sbom.sh --project mydevice-os --version 1.0.0 --target /path/to/rootfs --firmware --generate-only
Yocto로 빌드한다면 펌웨어 파일 대신 빌드가 끝난 빌드 디렉터리를 지정합니다. 빌드 기록에서 설치된 패키지와 정확한 버전을 읽으므로 더 정확합니다.
./scan-sbom.sh --project mydevice-os --version 1.0.0 --target /path/to/yocto-build --generate-only
펌웨어가 암호화되어 있거나 BomLens가 풀지 못하는 형식이면 SK텔레콤 담당자에게 문의하시기 바랍니다.
임베디드 리눅스 위에서 자체 애플리케이션이 별도로 동작한다면, 그 애플리케이션 소스는 위의 “애플리케이션 층” 스캔을 동일하게 적용합니다. 펌웨어 이미지 안에 애플리케이션까지 모두 포함되어 있다면 OS 층 스캔 하나로 끝날 수도 있습니다.
버전을 읽지 못한 컴포넌트가 있을 때
펌웨어 파일 스캔은 오픈소스 이름은 찾았지만 버전을 읽지 못하는 경우가 있습니다. 버전이 없으면 그 컴포넌트는 취약점을 확인할 수 없으므로, SK텔레콤이 버전 보충을 요청할 수 있습니다. 이때는 스캔과 함께 생성된 mydevice-os_1.0.0_component-versions.template.csv에 제품에 실제로 들어간 버전을 적어, 처음과 같은 대상으로 다시 스캔합니다. 버전을 적을 수 없으면 버전을 비우고 사유(own-code 자체 개발 코드, not-open-source 오픈소스 아님, version-unknown 확인 불가)를 적습니다.
name,version,reason
net-snmp,5.7.1,
libradius,,own-code
./scan-sbom.sh --project mydevice-os --version 1.0.0 --target /path/to/firmware.bin --firmware \
--component-versions mydevice-os_1.0.0_component-versions.template.csv --generate-only
층별로 제출
층별 SBOM은 합치지 않고 그대로 제출합니다. SK텔레콤 시스템은 SBOM 문서 하나를 스캔 단위로 등록하고, 같은 제품 버전에 등록된 문서들을 합쳐 하나의 목록으로 봅니다. 층별로 포맷이 달라도 됩니다.
파일마다 이름이 달라야 하고, 재제출할 때는 같은 이름을 그대로 써야 합니다. SBOM 문서 이름이 스캔의 정체성이라, 이름이 바뀌면 이전 제출분이 지워지지 않고 남아 이미 조치한 취약점이 계속 집계됩니다. 층을 나타내는 접미어는 재제출해도 바뀌지 않으므로 안전하지만, 제출 회차를 나타내는 순번은 붙이지 마시기 바랍니다.
| 층 | 파일 이름 예 |
|---|
| OS | myserver-os_1.0.0_bom.json |
| 애플리케이션 | myserver-app_1.0.0_bom.json |
층 구분은 --project 값에 붙이는 접미어(-os, -app)로 합니다. BomLens는 {프로젝트 이름}_{버전}_bom.json을 자동으로 만들므로, 두 층을 모두 만들 때는 --project를 층마다 다르게 주십시오(예: myserver-os, myserver-app). 같은 이름으로 두 번 실행하면 파일 이름이 같아져 나중에 실행한 쪽이 앞선 산출물을 덮어씁니다. cdxgen이나 Syft로 직접 만들 때도 출력 파일 이름을 같은 규칙(-o myserver-app_1.0.0_bom.json 등)으로 맞추시기 바랍니다.
최상위 컴포넌트 이름(CycloneDX는 metadata.component.name, SPDX는 DocumentName)도 파일 이름 앞부분({이름}_{버전})과 같은 값으로 기재합니다. BomLens는 --project/--version 값을 이 필드에 자동으로 넣으므로 따로 손댈 필요가 없습니다. 이 값이 제출 건 전체에서 고유해야 하는 식별자입니다. 자세한 내용은 제출 요구사항의 메타데이터 절을 참고하세요.
클러스터처럼 노드가 여럿인 제품을 어떤 단위로 묶어 내는지는 제출 절차의 제출 단위 절을 참고하세요.
공통 주의사항
도구를 사용하기 전 아래 사항을 확인하시기 바랍니다.
- 전이적 의존성 포함 여부: 빌드(패키지 설치)가 완료된 상태에서 생성해야 전이적 의존성까지 포함됩니다. 의존성 누락은 반려 사유가 되며, 언어별 빌드 선행 명령은 제출 요구사항의 의존성 범위 절을 참고하세요.
- PURL 포함 여부: 생성된 SBOM에 모든 컴포넌트의
purl 필드가 포함되어 있는지 확인합니다. SK텔레콤 시스템은 PURL을 기반으로 취약점을 매핑합니다. 확인 명령과 재생성 절차는 검증 체크리스트를 참고하세요. - 출력 포맷: CycloneDX JSON 형식을 권장합니다. (
-o cyclonedx-json 또는 동등한 옵션 사용) - 프로젝트 정보: 메타데이터에 납품 프로젝트의 이름과 버전이 정확히 기입되었는지 확인합니다.
관련 문서
4 - 상용 소프트웨어·완제품 공급 시 SBOM 제출
타사가 제조한 상용 소프트웨어나 완제품을 공급하는 경우, 제조사로부터 SBOM을 받아 제출하는 방법을 안내합니다.
이 문서는 자사가 개발하지 않은 상용 소프트웨어나 완제품을 SK텔레콤에 공급하는 공급사를 위한 가이드입니다. 이 경우 공급사는 소스코드에 접근할 수 없으므로, SBOM 생성 방법의 소스코드 스캔 방식을 적용할 수 없습니다. 제품을 제조한 원제조사로부터 SBOM을 받아 제출합니다.
납품된 장비나 설치 이미지를 도구로 통째로 스캔하는 방식은 대안이 되지 않습니다. 상용 소프트웨어 부분은 패키지 매니저 메타데이터가 없어 purl이 누락된 컴포넌트로 생성되고, 취약점 매칭이 실패하여 반려됩니다.
적용 대상
다음과 같은 형태로 타사 제품을 공급하는 경우가 해당합니다.
- 상용 소프트웨어 재판매: 타사가 개발한 패키지 소프트웨어의 라이선스를 공급 (리셀러, 총판)
- 어플라이언스·완제품 장비: 제조사가 OS와 소프트웨어를 설치해 출하하는 장비 (예: 스토리지, 백업 어플라이언스, 네트워크 장비)
- 타사 제품이 포함된 시스템: 자체 개발 부분과 타사 상용 제품을 함께 구성해 납품
자체 개발 부분이 함께 있다면, 자체 개발 부분은 SBOM 생성 방법에 따라 직접 생성하고, 상용 부분은 본 문서에 따라 제조사 SBOM을 받아 함께 제출합니다. 자체 개발 부분 가운데 소스 스캔이 찾지 못하는 실행 파일, 라이브러리, 펌웨어 같은 배포 산출물은 제출 요구사항의 자체개발 구성요소 권장 사항에 따라 SBOM에 함께 적습니다.
제조사 SBOM 수령
원제조사(제조사 또는 개발사)에 CycloneDX 또는 SPDX 형식의 SBOM을 요청합니다. 미국 행정명령 EO 14028, EU Cyber Resilience Act 등 규제 시행에 따라 글로벌 제조사 다수가 제품별 SBOM 제공 체계를 갖추고 있습니다. 요청할 때 다음 사항을 함께 전달하면 회신을 빠르게 받을 수 있습니다.
- 형식: CycloneDX JSON (권장) 또는 SPDX
- 대상: 납품하는 제품의 정확한 모델명과 버전
- 범위: OS를 포함해 출하되는 제품이라면 OS 패키지까지 포함
제조사마다 SBOM 제공 여부와 소요 기간이 다르므로, 납품 일정에 맞추려면 계약 검토 단계에서 미리 요청하시기 바랍니다.
받은 SBOM 점검
제조사에게 받은 SBOM도 자체 생성한 SBOM과 같은 기준으로 검토됩니다. 제출 전에 다음을 확인합니다.
- 제출 요구사항 충족 여부: 표준 포맷과 버전, 메타데이터, 컴포넌트 이름과 버전, purl 포함 여부
- 검증 체크리스트 점검: purl 보유 수 등 필수 항목
- 제품 버전 일치 여부: SBOM의 최상위 컴포넌트가 실제 납품하는 제품의 이름·버전과 일치하는지
점검을 마친 SBOM은 제출 절차에 따라 파일명을 정해 제출합니다.
클러스터로 구성된 제품이라면
여러 대의 노드가 하나의 클러스터를 이루는 제품(예: 분산 스토리지)도 제출 단위는 제품당 SBOM 하나입니다. SBOM 단위를 정하는 기준은 제출 절차의 제출 단위 절을 참고하세요.
제조사가 SBOM을 제공하지 못하는 경우
제조사가 SBOM을 제공하기 어렵다고 회신한 경우, 임의 방식으로 생성해 제출하기 전에 opensource@sktelecom.com으로 먼저 협의해 주시기 바랍니다.
관련 문서
5 - SBOM 제출 전 검증 체크리스트
SBOM 제출 전 필수 확인 사항을 점검하여 반려를 방지합니다.
필수 점검 항목
아래 체크리스트를 통과하지 못한 SBOM은 시스템에서 자동으로 반려될 수 있습니다. 2~4번 항목은 아래 검증 도구의 BomLens 자동 검증으로 한 번에 확인할 수 있습니다.
1. 파일 무결성
아래 명령으로 확인하시기 바랍니다. 오류 없이 종료되면 통과입니다.
jq empty sbom.json && echo "OK: valid JSON"
2. 필수 데이터 필드
3. 의존성 완전성 확인
전이적 의존성 누락은 가장 흔한 반려 사유입니다. 아래 항목을 반드시 확인하시기 바랍니다.
4. 식별자 (PURL) 확인
SK텔레콤 시스템은 PURL로 취약점을 매핑합니다. 가장 중요한 항목입니다.
아래 명령으로 purl 개수를 직접 확인하시기 바랍니다. 전체 컴포넌트 수와 purl 보유 수가 같아야 합니다.
# CycloneDX — 두 값이 같아야 한다
jq '.components | length' sbom.json # 전체 컴포넌트 수
jq '[.components[] | select(.purl)] | length' sbom.json # purl 보유 수
# SPDX — purl(externalRef) 보유 패키지 수
jq '[.packages[] | select(.externalRefs[]?.referenceType == "purl")] | length' sbom.json
# CycloneDX: 네임스페이스가 필수인 타입인데 그 자리가 빈 개수 (0이어야 한다)
# rpm/deb/apk의 배포판 누락과 maven의 groupId 누락이 함께 잡힌다
jq '[.components[] | (.purl // "")
| select(test("^pkg:(alpm|apk|bitbucket|composer|deb|git|github|golang|huggingface|maven|qpkg|rpm|swift|vscode-extension)/[^/@?#]+([@?#]|$)"))
] | length' sbom.json
# CycloneDX: 규격에 없는 타입을 쓴 경우 그 타입 이름을 출력한다 (아무것도 나오지 않아야 한다)
curl -sO https://raw.githubusercontent.com/package-url/purl-spec/main/purl-types-index.json
jq -r --slurpfile ok purl-types-index.json '
[.components[] | (.purl // "") | select(startswith("pkg:")) | capture("^pkg:(?<t>[^/@?#]+)").t]
| unique - $ok[0] | .[]' sbom.json
purl 보유 수가 0이거나 전체 컴포넌트 수보다 현저히 적으면 제출하지 마십시오. 원인과 재생성 방법은 자주 발생하는 반려 사유를 참고하십시오.
검증 도구
BomLens 자동 검증 (권장)
BomLens의 SBOM 분석 기능은 위 체크리스트의 2~4번을 포함해 제출 요구사항을 자동으로 점검합니다. v1.8.0 이상이 필요합니다.
./scripts/scan-sbom.sh --project my-app --version 1.0.0 \
--analyze "./sbom.json" \
--lang ko \
--generate-only
실행하면 my-app_1.0.0/ 폴더에 적합성 리포트(my-app_1.0.0_conformance.html)가 생성됩니다. 리포트가 자동으로 확인하는 항목은 다음과 같습니다.
BomLens로 SBOM을 직접 생성한 경우에도 이 명령으로 한 번 더 점검하시기 바랍니다. 방금 만든 SBOM을 그대로 --analyze에 넣으면 됩니다 — 생성과 검증을 한 번에 하지 않는 이유는, 갓 만든 SBOM이 자기 자신을 채점하는 것보다 별도 단계로 재확인하는 편이 실수를 더 잘 잡아내기 때문입니다.
| 검사 항목 | 체크리스트 대응 |
|---|
스펙 버전 범위 (CycloneDX 1.31.7, SPDX 2.22.3) | 2. 필수 데이터 필드 |
| 생성 일시, 생성 도구, 최상위 컴포넌트 이름·버전 | 2. 필수 데이터 필드 |
| 모든 컴포넌트의 이름·버전 | 2. 필수 데이터 필드 |
| 직접·전이적 의존성 포함 여부 | 3. 의존성 완전성 확인 |
PURL 보유율, 표준 형식(pkg:type/name@version), pkg:generic 금지, 규격에 정의된 타입, 네임스페이스 필수 타입의 네임스페이스 | 4. 식별자 (PURL) 확인 |
| 라이선스·해시 보유율 (권장 항목) | — |
위 표는 BomLens v1.12.1 이상 기준입니다. 이전 버전으로 검증한다면 CycloneDX 1.7로 생성했거나 maven 등 네임스페이스가 필요한 타입을 쓰는 경우에 위 jq 명령으로 함께 확인하시기 바랍니다.
결과가 fail이면 어떤 컴포넌트가 어느 항목에 미달하는지 목록으로 표시되므로, 해당 부분을 보완해 SBOM을 다시 생성한 뒤 재검증하면 됩니다. 웹 UI(--ui 실행 후 SBOM 업로드)에서도 같은 검증을 할 수 있습니다.
제출 전에는 위 명령에 --conformance-profile skt-submission을 추가해서, SK텔레콤 심사와 같은 기준(PURL 포함률 100%, pkg:generic 식별자 없음)으로 확인하시기 바랍니다. 웹 UI의 제출 검토 화면은 이 기준을 이미 기본값으로 적용하므로, 이 옵션은 CLI를 직접 실행할 때만 필요합니다.
CycloneDX Validator (스키마 검사)
CycloneDX 파일이 표준 스키마에 맞는지 확인하는 온라인 도구입니다. JSON 문법과 형식 오류(체크리스트 1번)를 설치 없이 빠르게 확인할 때 유용합니다. 다만 스키마 검사만 수행하므로, 통과하더라도 2~4번(필수 필드, 의존성 완전성, PURL)을 충족한다는 뜻은 아닙니다. SPDX 파일은 이 도구로 검사할 수 없습니다.
관련 문서
6 - SBOM 제출 절차
작성된 SBOM 파일의 제출 채널과 이메일 양식, 제출 후 프로세스를 안내합니다.
1. 제출 단위
제출 단위는 납품 제품 하나입니다. 여러 대의 노드가 하나의 클러스터를 이루는 제품도 마찬가지이며, 노드 대수만큼 만들 필요는 없습니다.
- 모든 노드가 동일 구성이라면, 대표 노드 1대를 기준으로 생성해 제출합니다.
- 노드 역할에 따라 설치된 소프트웨어가 다르다면(예: 관리 노드와 스토리지 노드), 역할별로 만들어 함께 제출합니다.
제품 하나에 SBOM 파일이 여럿일 수 있습니다. 서버처럼 층을 나눠 생성한 경우 파일을 합치지 않고 그대로 함께 제출하며, SK텔레콤 시스템이 같은 제품 버전에 등록된 문서들을 합쳐 하나의 목록으로 봅니다. 이때 파일마다 이름이 달라야 하고 재제출 시에는 같은 이름을 유지해야 합니다. 이름 규칙은 SBOM 생성 방법의 층별로 제출 절을 참고하세요.
2. 제출 시기
- 소프트웨어 계약 체결 후 초기 납품 시
- 소프트웨어의 주요 버전(Major/Minor) 업데이트 시
- 계약서에 명시된 정기 제출 일정 도래 시
3. 제출 방법
SBOM 파일은 SK텔레콤 사업부서 및 보안부서 담당자에게 이메일(또는 담당자가 지정한 채널)로 제출합니다.
- 이메일 제목:
[SBOM 제출] 공급사명_프로젝트명_버전 - 첨부파일: 생성된 SBOM 파일 (비밀번호 걸린 압축 파일 금지)
본문 필수 기재 사항:
- 납품 계약 번호
- 담당자 정보 (성명, 부서, 연락처)
- 프로젝트 정보 (시스템명, 상세 버전)
- 사용 도구 및 버전 (예: BomLens, cdxgen)
4. 제출 후 검증 및 조치
제출된 SBOM은 사내 오픈소스 & SBOM 관리 시스템(TOSCA)에 등록된 후 아래 절차에 따라 검증됩니다. TOSCA는 사내 시스템이므로 공급사가 접근할 필요는 없습니다.
| 단계 | 내용 | 처리 기한 |
|---|
| 형식 검증 | 필수 필드 누락 여부 확인. 미충족 시 반려 통보 | 접수 후 3일 이내 |
| 보안 취약점 분석 | Critical/High 등급 취약점 탐지 여부 자동 분석 | - |
| 조치 요청 | 심각한 취약점 발견 시 패치 계획 또는 소명서 요청 | Critical: 7일 / High: 30일 |
검증 결과와 조치 요청 사항은 사업부서 담당자를 통해 공급사 및 보안부서 담당자에게 통보됩니다.
관련 문서
7 - 자주 발생하는 반려 사유
제출된 SBOM이 반려되는 대표 사유와 원인, 해결 방법을 안내합니다.
제출된 SBOM은 형식 검증과 취약점 분석을 거치며, 기준에 미달하면 반려됩니다. 아래는 실제 접수 과정에서 반복적으로 발생하는 반려 사유입니다. 제출 전에 검증 체크리스트와 함께 확인하시기 바랍니다.
반려는 SBOM의 형식이나 완전성 문제일 뿐이며, 아래 해결 방법대로 보완해 다시 제출하면 됩니다.
반려 사유 한눈에 보기
| 반려 사유 | 주요 원인 | 해결 방법 |
|---|
| PURL 전량 누락 | 패키지 매니저 메타데이터가 없는 설치 디렉터리나 원시 파일을 스캔 (syft dir: 등) | 빌드된 이미지나 소스코드를 스캔 대상으로 변경. SBOM 생성 방법 |
| 전이 의존성 누락 | 빌드(패키지 설치) 전에 소스만 스캔 | 빌드 완료 후 재생성. 제출 요구사항의 의존성 범위 절 |
pkg:generic/ PURL | 도구가 생태계를 식별하지 못함 | 생태계를 명시하는 타입으로 재생성. 제출 요구사항의 PURL 절 |
| 규격에 없는 PURL 타입 | 도구가 규격에 정의되지 않은 타입을 임의로 기재(예: pkg:applications/) | 규격에 정의된 타입으로 재생성. 제출 요구사항의 PURL 절 |
| maven 등 네임스페이스 필수 타입에 네임스페이스 누락 | 도구가 groupId와 artifactId를 점으로 이어 붙여 한 자리에 기재 | groupId를 네임스페이스 자리로 분리해 재생성. 제출 요구사항의 PURL 절 |
| 네임스페이스에 공급사 이름이나 URL 기재 | 생성 도구가 매니페스트의 벤더 문자열을 groupId 자리에 그대로 옮김 | 저장소가 쓰는 실제 식별자로 수정. 제출 요구사항의 PURL 절 |
| 컴포넌트 버전 누락 | 매니페스트 불완전 또는 도구 설정 문제 | version 필드 필수 기재. 제출 요구사항 |
| 서버인데 OS 패키지 미포함 | 애플리케이션 소스만 스캔 | 납품 상태의 rootfs나 이미지를 스캔. SBOM 생성 방법 |
| OS 패키지 PURL에 배포판 누락 | 스캔 대상에 /etc/os-release가 없어 도구가 배포판을 판정하지 못함 | rootfs의 루트나 이미지를 대상으로 재생성. SBOM 생성 방법 |
| OS 패키지 PURL의 배포판이 네임스페이스가 아닌 쿼리 파라미터에 표기 | 도구가 배포판을 ?distro=...처럼 부가 정보로만 기재 | 배포판을 경로(네임스페이스)로 옮겨 재생성. 제출 요구사항의 PURL 절 |
| 실제와 다른 배포판·버전의 PURL | 도구가 파일 이름으로 무관한 배포판 패키지를 추정 | 실제 설치된 패키지를 기준으로 재생성. SBOM 생성 방법 |
| 허용되지 않는 포맷·버전 | 지원 범위 밖의 포맷으로 생성 | CycloneDX JSON 권장. 제출 요구사항 |
| 최상위 컴포넌트 정보 누락 | 메타데이터에 납품 제품명과 버전 미기재 | metadata의 component에 제품명과 버전 기재. 제출 요구사항 |
| 최상위 컴포넌트 이름이 다른 제출 건과 충돌 | 생성 도구가 제품명 대신 고정값을 채움(예: 빈 값, ., /scan) | metadata의 component 이름을 장비·제품을 특정할 수 있는 고유한 값으로 수정 후 재제출. 제출 요구사항 |
대표 사례
사례 1: 설치 디렉터리 스캔으로 PURL이 전량 누락
한 공급사가 syft dir:<설치 디렉터리>로 패키지 매니저 메타데이터가 없는 위치를 스캔해 제출한 SBOM은 대부분의 컴포넌트에 purl이 하나도 없어, 취약점 매칭이 전량 실패하고 반려되었습니다. 패키지 매니저 메타데이터(package.json, go.mod, RPM/DEB 패키지 DB 등)가 없는 위치를 스캔하면 도구가 생태계를 식별하지 못합니다.
스캔 대상을 빌드된 이미지나 소스코드로 바꾸고, 생성 직후 purl 개수를 확인하십시오. 확인 명령은 검증 체크리스트에 있습니다.
사례 2: 빌드 전 스캔으로 전이 의존성 누락
직접 의존성이 수 개인 프로젝트인데 총 컴포넌트가 10개 미만이라면 전이 의존성 누락을 의심해야 합니다. 일반적인 웹 애플리케이션은 전이 의존성까지 포함하면 수십에서 수백 개의 컴포넌트가 나옵니다. npm install, mvn package 같은 빌드를 완료한 뒤 생성하면 해결됩니다.
사례 3: 생성 도구가 최상위 컴포넌트 이름을 고정값으로 채워 다른 제출 건과 충돌
한 공급사가 제조사 제공 SBOM 생성 도구로 만든 CycloneDX SBOM을 제출했는데, 이미 등록된 다른 장비의 SBOM과 이름이 겹쳐 반려되었습니다. 확인 결과 이 도구는 스캔한 장비와 무관하게 metadata.component.name을 항상 같은 고정값으로 채우고 있었습니다. 같은 도구로 다른 장비의 SBOM을 만들어도 이름이 매번 똑같이 나오기 때문에, 먼저 등록된 건과 계속 충돌합니다.
이런 도구를 사용하는 경우 SBOM을 텍스트 편집기로 열어 metadata.component.name(CycloneDX) 또는 최상단 name(SPDX) 값을 장비를 식별할 수 있는 값으로 직접 수정한 뒤 제출해야 합니다.
사례 4: OS 패키지가 빠지고 실제와 다른 배포판 PURL로 선언
RHEL 서버 제품의 SBOM이 애플리케이션 소스 트리만 대상으로 생성되어, 설치된 rpm 패키지가 하나도 포함되지 않은 채 제출되었습니다. 여기에 더해 소스에 포함된 라이브러리가 pkg:deb/debian/libpcap@1.1.1-2+squeeze1처럼 데비안 소스 패키지로 선언되어 있었습니다. 생성 도구가 소스 파일 이름을 단서로 그 파일을 담고 있는 데비안 패키지를 추정해 붙인 결과입니다.
이 유형은 형식 검증을 통과합니다. purl이 실재하는 패키지를 가리키므로 매칭도 정상 성공하고 화면에도 오류가 보이지 않습니다. 그러나 실제 서버에 설치된 것과 무관한 컴포넌트의 취약점이 보고되고, OS를 업그레이드해도 결과가 달라지지 않습니다.
납품 상태의 rootfs나 이미지를 스캔해 OS 패키지를 포함시키고, 소스에 포함된 라이브러리는 실제 버전으로 선언해야 합니다. 절차는 SBOM 생성 방법의 서버 납품 절을 참고하십시오.
사례 5: 배포판 정보가 네임스페이스가 아니라 쿼리 파라미터에 표기됨
자체 빌드 리눅스 배포판을 쓰는 한 서버 제품의 SBOM에서, rpm 패키지 PURL에 배포판 값이 물음표 뒤 쿼리 파라미터로 붙어 있었습니다(예: pkg:rpm/bind@9.11.36?distro=customdistro-1.0). 도구가 배포판 자체는 식별했지만, 이를 요구되는 네임스페이스 자리가 아니라 부가 정보 자리에 기재한 경우입니다.
이 값은 취약점 매칭에 쓰이지 않아 해당 서버의 rpm 패키지 전량이 매칭 실패로 반려되었습니다. 배포판 값을 경로(타입과 패키지 이름 사이)로 옮겨 pkg:rpm/<배포판>/bind@9.11.36처럼 재생성해야 합니다.
사례 6: 형식 검사를 모두 통과했는데 purl 642건이 매칭 실패
한 공급사가 컴포넌트 8,129개짜리 CycloneDX SBOM을 제출했습니다. 모든 컴포넌트에 purl이 있어 보유율은 100%였고, pkg:generic도 없었으며, OS 패키지 배포판 누락도 0건이었습니다. 당시 체크리스트와 자동 검증 기준을 모두 통과한 파일입니다. 그런데 고유 purl 2,785건 가운데 642건이 실제 저장소 조회에서 매칭되지 않았습니다.
원인은 세 가지가 섞여 있었습니다.
- 네임스페이스 누락 663건:
pkg:maven/org.slf4j.jcl-over-slf4j@2.0.15처럼 groupId와 artifactId가 점으로 이어 붙어 한 자리에 들어갔습니다. 형식은 유효하고 스키마 검사도 통과하지만 저장소에 없는 좌표입니다. - 규격에 없는 타입:
pkg:applications/java@11.0.25처럼 applications라는 임의 타입이 쓰였습니다. generic이 아니므로 기존 금지 규칙에 걸리지 않았습니다. - 네임스페이스에 벤더 문자열:
pkg:maven/The%2BApache%2BSoftware%2BFoundation/poi@5.4.1, pkg:maven/http%3A/www.jboss.org/jbossxts@1.1처럼 회사 이름이나 URL이 groupId 자리에 들어갔습니다.
세 유형 모두 스키마 검사로는 걸러지지 않으므로, 검증 체크리스트의 PURL 확인 명령으로 직접 점검한 뒤 제출해야 합니다.
같은 파일에서 pkg:maven/org.drools/org.drools.drools-core-dynamic@7.67.2.Final-redhat-00054처럼 artifactId 앞에 groupId가 한 번 더 붙은 경우도 나왔습니다. 실제 좌표는 org.drools:drools-core-dynamic입니다. 이 유형은 위 세 가지와 달리 형식으로 판정할 수 없습니다. org.drools:org.drools.updatesite나 org.apache.felix:org.apache.felix.http.jetty처럼 artifactId가 groupId로 시작하는 것이 정상인 좌표도 많기 때문입니다. Eclipse 플러그인과 OSGi 번들은 artifactId에 번들 심볼릭 이름을 그대로 쓰는 관례가 있습니다. 그래서 체크리스트에는 점검 항목을 두지 않았고, 확인하려면 해당 좌표가 저장소에 실제로 있는지 조회해야 합니다.
반려되지 않는 SBOM의 모습
합격 기준을 충족하는 예시 파일을 내려받아 구조를 비교해 보십시오. 모든 컴포넌트에 purl과 버전이 있고, dependencies 배열이 직접·전이 의존 관계를 담고 있습니다.
관련 문서