Docker Hardened Images 스캔하기
Docker Hardened Images 스캔하기
Docker Scout, Grype, Trivy 같은 OpenVEX 호환 스캐너로 Docker Hardened Images를 스캔하고, VEX attestation을 적용·내보내는 방법을 알아봐요.
출처: 문서
본문
Docker Hardened Images(DHI)는 기본적으로 안전하도록 설계되지만, 다른 컨테이너 이미지와 마찬가지로 취약점 관리 프로세스의 일부로 정기적으로 스캔하는 것이 중요해요.
OpenVEX 호환 스캐너로 스캔하기
정확한 취약점 평가를 얻으려면 VEX attestation을 지원하는 스캐너를 사용해요. 다음 스캐너는 Docker Hardened Images에 포함된 VEX 문을 읽고 적용할 수 있어요.
- Docker Scout: 구성 없이 VEX 문을 자동으로 적용
- Trivy: VEX Hub 또는 로컬 VEX 파일을 통해 VEX 지원
- Grype:
--vex플래그로 VEX 지원
지원 스캐너의 전체 목록은 Scanner integrations를 봐요.
Docker Scout
Docker Scout는 Docker Desktop과 Docker CLI에 통합되어 있어요. 취약점 인사이트, CVE 요약, 해결(remediation) 지침에 대한 직접 링크를 제공해요.
Docker Scout로 DHI 스캔하기
Docker Scout로 Docker Hardened Image를 스캔하려면 다음 명령을 실행해요.
$ docker login dhi.io
$ docker scout cves dhi.io/<image>:<tag> --platform <platform>
예시 출력:
v SBOM obtained from attestation, 101 packages found
v Provenance obtained from attestation
v VEX statements obtained from attestation
v No vulnerable package detected
...
더 상세한 필터링과 JSON 출력은 Docker Scout CLI reference를 봐요.
provenance attestation으로 자식 이미지 빌드하기
Docker Hardened Image를 베이스로 사용하는 커스텀 이미지를 빌드할 때는 --provenance=mode=max와 --sbom=true로 빌드해야 해요. 그래야 Docker Scout가 베이스 이미지 계보(lineage)를 추적하고 VEX 문을 올바르게 적용할 수 있어요.
이 플래그가 없으면 Docker Scout가 provenance 체인에서 DHI 베이스 이미지를 식별할 수 없어요. 결과적으로 베이스 이미지에서 VEX 문으로 이미 억제된 CVE를 보고해서, 스캔 결과에 거짓 CVE 양성(false positive)이 생겨요.
[!NOTE] provenance attestation이 필요한 이유
Docker Scout는 max 모드 provenance attestation을 사용해 DHI 베이스 이미지를 식별하고 그 계보를 추적해요. 암호화 서명된 provenance attestation은 베이스 이미지 계보가 검증되고 변조 방지됨을 보장해서, 베이스 이미지의 VEX 문을 올바르게 적용하는 데 필요한 신뢰 앵커를 Docker Scout에 제공해요.
최대 provenance와 SBOM attestation으로 빌드하려면:
$ docker build \
--provenance=mode=max \
--sbom=true \
--push \
-t docker.io/<namespace>/<image>:<tag> .
이 플래그로 빌드한 후 Docker Scout는 전체 provenance 체인을 읽고, DHI 베이스 이미지를 매칭하며, 그 VEX 문을 적용해요. 자식 이미지 스캔은 이제 올바른 억제된 CVE를 반영해서 정확한 취약점 평가를 제공해요.
자식 이미지의 VEX attestation
자식 이미지에 새 레이어를 도입하고 그 레이어의 CVE를 억제하고 싶다면, DHI 베이스 이미지의 VEX 문을 중복하거나 집계할 필요 없이 자식 이미지에 자체 VEX attestation을 독립적으로 첨부할 수 있어요.
docker scout cves가 자식 이미지에 대해 실행되면 Scout는 전체 provenance 체인의 VEX attestation을 읽고 누적해서 적용해요.
- 베이스 이미지 VEX — DHI에 첨부되며 베이스 이미지 레이어의 CVE에 적용
- 자식 이미지 VEX — 내 이미지에 첨부되며 내가 도입한 레이어의 CVE에 적용
예를 들어 DHI Python 베이스 이미지에 requests 레이어를 추가하고 CVE-2024-47081을 억제하는 VEX 문을 첨부하면, Scout는 두 VEX attestation을 독립적으로 적용하고 각각의 작성자에게 귀속시켜요.
✓ VEX statements obtained from attestation
CVE-2024-47081 VEX: not affected [vulnerable code not present] : <your-namespace>
Scout는 DHI 베이스 VEX의 CVE와 자식 VEX의 CVE를 같은 스캔에서 억제해요 — 집계 VEX 문서는 필요하지 않아요.
자식 이미지에 VEX attestation을 만들고 첨부하려면:
cat > child-vex.json << 'EOF'
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://<your-namespace>/vex/<image-name>/1",
"author": "<your-namespace>",
"timestamp": "<timestamp>",
"version": 1,
"statements": [
{
"vulnerability": {
"name": "<CVE-ID>"
},
"products": [
{
"@id": "pkg:pypi/<package>@<version>"
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_present"
}
]
}
EOF
docker scout attestation add \
--file child-vex.json \
--predicate-type https://openvex.dev/ns/v0.2.0 \
docker.io/<your-namespace>/<image>:<tag>
[!NOTE] 이는
--provenance=mode=max로 빌드했기 때문에만 가능해요. 전체 provenance 체인이 없으면 Scout가 베이스 이미지로 거슬러 올라가 VEX attestation을 가져올 수 없어요.
Docker Scout로 CI/CD에서 DHI 스캔 자동화하기
CI/CD 파이프라인에 Docker Scout를 통합하면 Docker Hardened Images에서 빌드한 이미지가 빌드 과정 중 알려진 취약점이 없는지 자동으로 검증할 수 있어요. 이 선제적 접근 방식은 개발 수명주기 전반에 걸쳐 이미지의 지속적인 보안 무결성을 보장해요.
GitHub Actions 워크플로 예시
다음은 이미지를 빌드하고, 스캔하며, 스캔이 통과할 때만 레지스트리에 푸시하는 GitHub Actions 워크플로 예시예요.
name: DHI Vulnerability Scan
on:
push:
branches:
- main
pull_request:
env:
REGISTRY: docker.io
IMAGE_NAME: ${{ github.repository }}
SHA: ${{ github.event.pull_request.head.sha || github.event.after }}
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker with containerd image store
uses: docker/setup-docker-action@v5
with:
daemon-config: |
{
"features": {
"containerd-snapshotter": true
}
}
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build
uses: docker/build-push-action@v7
with:
context: .
sbom: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
- name: Run Docker Scout CVE scan
uses: docker/scout-action@v1
with:
command: cves
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
only-severities: critical,high
exit-code: true
- name: Push image
if: success()
run: |
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
exit-code: true 파라미터는 critical 또는 high 심각도 취약점이 감지되면 워크플로가 실패하도록 보장해서, 안전하지 않은 이미지의 배포를 방지해요.
[!NOTE]
--provenance=mode=max와--sbom=true플래그는 Docker Scout가 DHI 베이스 이미지 계보를 추적하고 VEX 문을 올바르게 적용할 수 있도록 필수예요.docker/setup-docker-action으로 containerd 이미지 스토어를 활성화하면 BuildKit이 먼저 레지스트리에 푸시하지 않고도 attestation을 로컬에 저장할 수 있어요. containerd 이미지 스토어가 없으면 Docker Engine은Attestation is not supported for the docker driver. Switch to a different driver, or turn on the containerd image store, and try again.오류로 빌드를 거부해요.Push image단계는if: success()를 사용해 스캔이 통과할 때만 실행되며, 이미지가 critical 또는 high 심각도 취약점이 없는 경우에만 레지스트리에 푸시되도록 보장해요.
CI에서 Docker Scout 사용에 대한 자세한 내용은 Integrating Docker Scout with other systems를 봐요.
Grype
Grype는 NVD와 배포판 advisory 같은 취약점 데이터베이스에 대해 컨테이너 이미지를 검사하는 오픈소스 스캐너예요.
Grype로 DHI 스캔하기
VEX 필터링을 사용해 Grype로 Docker Hardened Image를 스캔하려면 먼저 VEX attestation을 내보내고 --vex 플래그로 스캔해요.
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
$ grype dhi.io/<image>:<tag> --vex vex.json
--vex 플래그는 스캔 중 VEX 문을 적용해 알려진 익스플로잇 불가능한 CVE를 걸러내 정확한 결과를 얻어요.
VEX attestation 내보내기에 대한 자세한 내용은 Export VEX attestations를 봐요.
Trivy
Trivy는 컨테이너와 기타 아티팩트를 위한 오픈소스 취약점 스캐너예요. OS 패키지와 애플리케이션 의존성의 취약점을 감지해요.
Trivy로 DHI 스캔하기
Trivy를 설치한 후 이미지를 풀하고 스캔 명령을 실행해 Docker Hardened Image를 스캔할 수 있어요.
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ trivy image --scanners vuln dhi.io/<image>:<tag>
VEX 문을 사용해 취약점을 필터링하려면 Trivy는 여러 접근 방식을 지원해요. Docker는 구성된 저장소에서 VEX 문을 자동으로 다운로드·적용하는 원활한 워크플로를 제공하는 VEX Hub 사용을 권장해요.
VEX Hub 사용(권장)
Trivy를 구성해 VEX Hub에서 Docker Hardened Images advisories 저장소를 다운로드하게 해요. 다음 명령을 실행해 VEX 저장소를 설정해요.
$ trivy vex repo init
$ cat << REPO > ~/.trivy/vex/repository.yaml
repositories:
- name: default
url: https://github.com/aquasecurity/vexhub
enabled: true
username: ""
password: ""
token: ""
- name: dhi-vex
url: https://github.com/docker-hardened-images/advisories
enabled: true
REPO
$ trivy vex repo list
$ trivy vex repo download
VEX Hub를 설정한 후 VEX 필터링으로 Docker Hardened Image를 스캔할 수 있어요.
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ trivy image --scanners vuln --vex repo dhi.io/<image>:<tag>
예를 들어 dhi.io/python:3.13 이미지를 스캔하면:
$ trivy image --scanners vuln --vex repo dhi.io/python:3.13
예시 출력:
Report Summary
┌─────────────────────────────────────────────────────────────────────────────┬────────────┬─────────────────┐
│ Target │ Type │ Vulnerabilities │
├─────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┤
│ dhi.io/python:3.13 (debian 13.2) │ debian │ 0 │
├─────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┤
│ opt/python-3.13.11/lib/python3.13/site-packages/pip-25.3.dist-info/METADATA │ python-pkg │ 0 │
└─────────────────────────────────────────────────────────────────────────────┴────────────┴─────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
--vex repo 플래그는 스캔 중 구성된 저장소의 VEX 문을 적용해 알려진 익스플로잇 불가능한 CVE를 걸러내요.
로컬 VEX 파일 사용
VEX Hub 외에도 Trivy는 취약점 필터링을 위한 로컬 VEX 파일 사용을 지원해요. Docker Hardened Images가 제공하는 VEX attestation을 다운로드해 Trivy에서 직접 사용할 수 있어요.
먼저 이미지의 VEX attestation을 다운로드해요.
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
그런 다음 로컬 VEX 파일로 이미지를 스캔해요.
$ trivy image --scanners vuln --vex vex.json dhi.io/<image>:<tag>
VEX attestation 내보내기
로컬 VEX 파일이 필요한 스캐너(예: Grype나 로컬 파일을 사용하는 Trivy)를 위해 Docker Hardened Images에서 VEX attestation을 내보낼 수 있어요.
[!NOTE]
기본적으로 VEX attestation은
registry.scout.docker.com에서 가져와요. 네트워크에 아웃바운드 제한이 있다면 이 레지스트리에 접근할 수 있는지 확인해요. attestation을 대체 레지스트리로 미러링할 수도 있어요. 자세한 내용은 Mirror to a third-party registry를 봐요.
VEX attestation을 JSON 파일로 내보내요.
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
[!NOTE]
docker scout vex get명령은 Docker Scout CLI 버전 1.18.3 이상이 필요해요.이미지가 로컬 디바이스에 존재한다면 이미지 이름 앞에
registry://접두사를 붙여야 해요. 예를 들어docs/dhi-python:3.13대신registry://docs/dhi-python:3.13을 사용해요.
VEX 파일 살펴보기
VEX attestation을 내보낸 후 내용을 검사해 각 문이 무엇을 의미하는지 이해하고 상태로 필터링할 수 있어요. VEX 문서 구조, 상태 값, jq 필터링 명령에 대한 안내 워크스루는 Explore VEX statements in Docker Hardened Images를 봐요.