VEX로 예외 만들기
VEX로 예외 만들기
VEX(Vulnerability Exploitability eXchange)는 소프트웨어 패키지나 제품 맥락에서 취약점을 문서화하기 위한 표준 형식이에요. Docker Scout는 VEX 문서를 지원해 이미지의 취약점에 대한 예외(exceptions)를 만들어요.
[!NOTE] Docker Scout Dashboard나 Docker Desktop으로도 예외를 만들 수 있어요. GUI는 예외 생성을 위한 사용자 친화적인 인터페이스를 제공하고, 여러 이미지의 예외를 쉽게 관리할 수 있어요. 여러 이미지 또는 조직 전체에 대한 예외를 한 번에 만들 수도 있어요. 자세한 내용은 GUI로 예외 만들기를 참고하세요.
사전 요구사항 (Prerequisites)
OpenVEX 문서로 예외를 만들려면 다음이 필요해요.
- 최신 버전의 Docker Desktop 또는 Docker Scout CLI 플러그인
vexctl명령줄 도구
추가 요구사항은 VEX 문서를 첨부하는 방법에 따라 달라요.
- 인증(attestation)으로 문서를 첨부하려면 containerd 이미지 저장소를 활성화해야 해요.
- 인증으로 문서를 첨부하려면 이미지가 저장된 레지스트리 저장소에 대한 쓰기 권한이 필요해요.
VEX 소개
VEX 표준은 미국 CISA(Cybersecurity and Infrastructure Security Agency)의 워킹 그룹이 정의했어요. VEX의 핵심은 악용 가능성 평가(exploitability assessments)예요. 이 평가는 제품에 대한 주어진 CVE의 상태를 설명해요. VEX의 가능한 취약점 상태는 다음과 같아요.
- Not affected(영향 없음): 이 취약점에 대해 시정이 필요 없음.
- Affected(영향 있음): 이 취약점을 시정하거나 다루기 위한 조치가 권장됨.
- Fixed(수정됨): 이 제품 버전은 취약점에 대한 수정을 포함함.
- Under investigation(조사 중): 이 제품 버전이 취약점의 영향을 받는지 아직 알 수 없음. 이후 릴리스에서 업데이트가 제공될 것임.
VEX에는 여러 구현과 형식이 있어요. Docker Scout는 OpenVex 구현을 지원해요. 특정 구현과 관계없이 핵심 아이디어는 동일해요: 취약점의 영향을 설명하는 프레임워크를 제공하는 것. 구현과 관계없는 VEX의 핵심 구성 요소는 다음을 포함해요.
VEX 문서 (VEX document) : VEX 문(statement)을 저장하는 일종의 보안 권고. 문서의 형식은 특정 구현에 따라 달라져요.
VEX 문 (VEX statement) : 제품에서 취약점의 상태, 악용 가능 여부, 이슈를 시정할 방법이 있는지 설명해요.
근거와 영향 (Justification and impact) : 취약점 상태에 따라 문에는 제품이 영향받는지 or 아닌지 이유를 설명하는 근거나 영향 문이 포함돼요.
조치 문 (Action statements) : 취약점을 시정하거나 완화하는 방법을 설명해요.
vexctl 예시
다음 예시 명령은 다음을 명시하는 VEX 문서를 만들어요.
- 이 VEX 문서가 설명하는 소프트웨어 제품은 Docker 이미지
example/app:v1 - 이미지는 npm 패키지
[email protected]을 포함 - npm 패키지는 알려진 취약점
CVE-2022-24999의 영향을 받음 - 취약한 코드가 이 이미지를 실행하는 컨테이너에서 실행되지 않으므로 이미지는 CVE의 영향을 받지 않음
$ vexctl create \
--author="[email protected]" \
--product="pkg:docker/example/app@v1" \
--subcomponents="pkg:npm/[email protected]" \
--vuln="CVE-2022-24999" \
--status="not_affected" \
--justification="vulnerable_code_not_in_execute_path" \
--file="CVE-2022-24999.vex.json"
이 예시의 옵션에 대한 설명은 다음과 같아요.
--author
: VEX 문서 작성자의 이메일.
--product
: Docker 이미지의 패키지 URL(PURL). PURL은 PURL 스펙에 정의된 표준화된 형식의 이미지 식별자예요.
Docker 이미지 PURL 문자열은 pkg:docker 유형 접두사로 시작하고, 그 뒤에 이미지 저장소와 버전(이미지 태그 또는 SHA256 다이제스트)이 따라와요. 버전을 example/app:v1처럼 지정하는 이미지 태그와 달리 PURL에서는 이미지 저장소와 버전이 @로 구분돼요.
--subcomponents
: 이미지에 있는 취약한 패키지의 PURL. 이 예시에서 취약점은 npm 패키지에 존재하므로 --subcomponents PURL은 npm 패키지 이름과 버전의 식별자(pkg:npm/[email protected])예요.
같은 취약점이 여러 패키지에 존재하면 vexctl은 단일 create 명령에 --subcomponents 플래그를 여러 번 지정할 수 있게 해 줘요.
--subcomponents를 생략할 수도 있는데, 그 경우 VEX 문은 이미지 전체에 적용돼요.
--vuln
: VEX 문이 다루는 CVE의 ID.
--status
: 취약점의 상태 라벨. 소프트웨어(--product)와 CVE(--vuln) 사이의 관계를 설명해요. OpenVEX의 상태 라벨 가능한 값은 다음과 같아요.
not_affectedaffectedfixedunder_investigation
이 예시에서 VEX 문은 Docker 이미지가 취약점에 not_affected임을 주장해요. not_affected 상태는 CVE가 분석 결과에서 걸러지는 CVE 억제로 이어지는 유일한 상태예요. 다른 상태는 문서화 목적에는 유용하지만 예외를 만드는 데는 동작하지 않아요. 가능한 모든 상태 라벨에 대한 자세한 내용은 OpenVEX 스펙의 Status Labels를 참고하세요.
--justification
: not_affected 상태 라벨을 근거로, 제품이 취약점에 영향받지 않는 이유를 설명해요. 이 경우 주어진 근거는 vulnerable_code_not_in_execute_path로, 제품이 사용하는 대로 취약점이 실행될 수 없다는 신호를 줘요.
OpenVEX에서 상태 근거는 다음 다섯 가지 값 중 하나일 수 있어요.
component_not_presentvulnerable_code_not_presentvulnerable_code_not_in_execute_pathvulnerable_code_cannot_be_controlled_by_adversaryinline_mitigations_already_exist
이 값들과 정의에 대한 자세한 내용은 OpenVEX 스펙의 Status Justifications를 참고하세요.
--file
: VEX 문서 출력의 파일명.
예시 JSON 문서
이 명령으로 생성된 OpenVEX JSON은 다음과 같아요.
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://openvex.dev/docs/public/vex-749f79b50f5f2f0f07747c2de9f1239b37c2bda663579f87a35e5f0fdfc13de5",
"author": "[email protected]",
"timestamp": "2024-05-27T13:20:22.395824+02:00",
"version": 1,
"statements": [
{
"vulnerability": {
"name": "CVE-2022-24999"
},
"timestamp": "2024-05-27T13:20:22.395829+02:00",
"products": [
{
"@id": "pkg:docker/example/app@v1",
"subcomponents": [
{
"@id": "pkg:npm/[email protected]"
}
]
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path"
}
]
}
VEX 문서가 어떻게 구조화되어야 하는지 이해하는 건 조금 어려울 수 있어요. OpenVEX 스펙은 문서와 문의 형식과 가능한 모든 속성을 설명해요. 전체 세부 사항은 스펙을 참조해 사용 가능한 필드와 잘 구성된 OpenVEX 문서를 만드는 방법을 알아보세요.
vexctl CLI 도구의 사용 가능한 플래그·구문과 설치 방법에 대해 더 알아보려면 vexctl GitHub 저장소를 참고하세요.
VEX 문서 검증하기
만든 VEX 문서가 잘 구성되었고 예상 결과를 내는지 테스트하려면 --vex-location 플래그와 함께 docker scout cves 명령을 사용해 CLI로 로컬 이미지 분석에 VEX 문서를 적용해 보세요.
다음 명령은 --vex-location 플래그를 사용해 지정된 위치의 모든 VEX 문서를 통합한 로컬 이미지 분석을 호출해요. 이 예시에서 CLI는 현재 작업 디렉토리에서 VEX 문서를 찾도록 지시받아요.
$ docker scout cves <IMAGE> --vex-location .
docker scout cves 명령의 출력은 --vex-location 위치에서 찾은 VEX 문이 결과에 반영된 결과를 표시해요. 예를 들어 not_affected 상태가 할당된 CVE는 결과에서 걸러져요. 출력이 VEX 문을 반영하지 않는 것처럼 보이면 VEX 문서가 어떤 식으로든 유효하지 않다는 신호일 수 있어요.
주의할 점은 다음을 포함해요.
- Docker 이미지의 PURL은
pkg:docker/로 시작하고 이미지 이름이 따라와야 해요. - Docker 이미지 PURL에서 이미지 이름과 버전은
@로 구분돼요.example/myapp:1.0이라는 이미지는pkg:docker/example/[email protected]이라는 PURL을 가져요. author를 지정하는 걸 기억하세요 (OpenVEX에서 필수 필드예요).- OpenVEX 스펙은 VEX 문서에서
justification,impact_statement및 기타 필드를 언제·어떻게 사용할지 설명해요. 이를 잘못 지정하면 유효하지 않은 문서가 돼요. VEX 문서가 OpenVEX 스펙을 준수하는지 확인하세요.
VEX 문서를 이미지에 첨부하기
VEX 문서를 만들면 다음 방법으로 이미지에 첨부할 수 있어요.
- 문서를 인증(attestation)으로 첨부
- 문서를 이미지 파일시스템에 임베드
한번 추가한 VEX 문서는 이미지에서 제거할 수 없어요. 인증으로 첨부된 문서는 새 VEX 문서를 만들어 이미지에 다시 첨부할 수 있어요. 그러면 이전 VEX 문서를 덮어써요 (하지만 인증은 제거하지 않아요). VEX 문서가 이미지 파일시스템에 임베드된 이미지는 VEX 문서를 바꾸려면 이미지를 다시 빌드해야 해요.
인증 (Attestation)
VEX 문서를 인증으로 첨부하려면 docker scout attestation add CLI 명령을 사용할 수 있어요. VEX를 사용할 때 예외를 이미지에 첨부하는 권장 옵션은 인증을 사용하는 거예요. 이 방법은 containerd 이미지 저장소와 이미지가 저장된 레지스트리 저장소에 대한 쓰기 접근이 필요해요.
이미 레지스트리에 push된 이미지에 인증을 첨부할 수 있어요. 이미지를 다시 빌드하거나 push할 필요가 없어요. 또한 예외를 인증으로 이미지에 첨부하면 소비자가 레지스트리에서 직접 이미지의 예외를 검사할 수 있어요.
이미지에 인증을 첨부하려면:
-
이미지를 빌드하고 레지스트리에 push하세요.
$ docker build --provenance=true --sbom=true --tag <IMAGE> --push . -
예외를 인증으로 이미지에 첨부하세요.
$ docker scout attestation add \ --file <cve-id>.vex.json \ --predicate-type https://openvex.dev/ns/v0.2.0 \ <IMAGE>이 명령의 옵션은 다음과 같아요.
--file: VEX 문서의 위치와 파일명--predicate-type: OpenVEX용 in-totopredicateType
이미지 파일시스템 (Image filesystem)
VEX 문서를 이미지 파일시스템에 직접 임베드하는 건 이미지를 빌드하기 전에 예외를 미리 알고 있다면 좋은 옵션이에요. 그리고 비교적 쉬워요. Dockerfile에서 VEX 문서를 이미지로 COPY하면 돼요. 인증과 달리 이 방법은 containerd 이미지 저장소나 이미지 push 전 레지스트리에 대한 쓰기 접근이 필요하지 않아요.
이 방법의 단점은 이후에 예외를 바꾸거나 갱신할 수 없다는 거예요. 이미지 레이어는 변경 불가능하므로 이미지 파일시스템에 넣은 것은 영원히 남아요. 문서를 인증으로 첨부하면 더 나은 유연성을 제공해요.
[!NOTE] 이미지 파일시스템에 임베드된 VEX 문서는 인증이 있는 이미지에 대해 고려되지 않아요. 이미지에 어떤 인증이라도 있으면 Docker Scout는 예외를 인증에서만 찾고 이미지 파일시스템에서는 찾지 않아요.
이미지 파일시스템에 임베드된 VEX 문서를 사용하려면 이미지에서 인증을 제거해야 해요. 출처(provenance) 인증은 이미지에 자동으로 추가될 수 있다는 점에 유의하세요. 이미지에 인증이 추가되지 않도록 하려면 이미지를 빌드할 때
--provenance=false와--sbom=false플래그로 SBOM과 provenance 인증을 모두 명시적으로 비활성화할 수 있어요.
VEX 문서를 이미지 파일시스템에 임베드하려면 이미지 빌드의 일부로 파일을 이미지로 COPY하세요. 다음 예시는 빌드 컨텍스트의 .vex/ 아래 모든 VEX 문서를 이미지의 /var/lib/db로 복사하는 방법을 보여 줘요.
# syntax=docker/dockerfile:1
FROM alpine
COPY .vex/* /var/lib/db/
VEX 문서의 파일명은 *.vex.json glob 패턴과 일치해야 해요. 이미지 파일시스템의 어디에 파일을 저장하는지는 중요하지 않아요.
복사된 파일은 최종 이미지의 파일시스템 일부여야 한다는 점에 유의하세요. 다단계 빌드에서는 문서가 최종 스테이지에 남아 있어야 해요.