前言
在現代雲原生應用程式開發中,容器安全已成為不可忽視的重要議題。隨著容器化技術的普及,攻擊者也開始針對容器映像檔中的漏洞進行攻擊。Docker Scout 是 Docker 官方推出的容器安全掃描工具,能夠幫助開發者在軟體開發生命週期的各個階段識別和修復安全漏洞。
本文將深入介紹 Docker Scout 的功能特性、安裝設定、使用方法,以及如何將其整合到 CI/CD 流程中。
Docker Scout 功能介紹
什麼是 Docker Scout?
Docker Scout 是一個容器映像檔分析工具,主要提供以下功能:
- 漏洞掃描:分析容器映像檔中的已知安全漏洞(CVE)
- SBOM 生成:自動產生軟體物料清單(Software Bill of Materials)
- 政策評估:根據預定義或自訂政策評估映像檔的合規性
- 修復建議:提供具體的漏洞修復方案和升級路徑
- 持續監控:追蹤已部署映像檔的新發現漏洞
核心特色
| 功能 | 說明 |
|---|
| 即時分析 | 在本地或 Docker Hub 上即時掃描映像檔 |
| 深度解析 | 分析所有層級的套件依賴關係 |
| 多來源比對 | 整合多個漏洞資料庫進行交叉比對 |
| 原生整合 | 與 Docker Desktop 和 Docker Hub 無縫整合 |
| API 支援 | 提供 REST API 供程式化存取 |
安裝與設定
前置需求
- Docker Desktop 4.17.0 或更新版本(已內建 Docker Scout)
- 或 Docker Engine 搭配 Docker Scout CLI 外掛
安裝 Docker Scout CLI
如果您使用的是 Docker Engine 而非 Docker Desktop,可以手動安裝 Docker Scout CLI 外掛:
1
2
3
4
5
6
7
8
| # 建立 CLI 外掛目錄
mkdir -p ~/.docker/cli-plugins
# 下載最新版本的 Docker Scout CLI
curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
# 驗證安裝
docker scout version
|
透過套件管理器安裝
1
2
3
4
5
6
| # macOS 使用 Homebrew
brew install docker/tap/docker-scout
# 或直接下載二進位檔
curl -fsSL https://github.com/docker/scout-cli/releases/latest/download/docker-scout_linux_amd64.tar.gz | tar -xz
sudo mv docker-scout /usr/local/bin/
|
登入 Docker Hub
使用 Docker Scout 前需要先登入 Docker Hub:
1
2
3
4
5
| # 登入 Docker Hub
docker login
# 確認登入狀態
docker info | grep Username
|
啟用 Docker Scout
1
2
3
4
5
| # 為特定 Repository 啟用 Docker Scout
docker scout repo enable <organization>/<repository>
# 查看已啟用的 Repository
docker scout repo list
|
映像檔掃描基礎
快速掃描
最基本的掃描方式是使用 docker scout quickview 命令:
1
2
3
4
5
6
7
8
| # 掃描本地映像檔
docker scout quickview nginx:latest
# 掃描特定映像檔
docker scout quickview myapp:v1.0.0
# 掃描 Docker Hub 上的映像檔
docker scout quickview docker/scout-cli:latest
|
輸出範例:
1
2
3
4
5
6
7
8
9
10
| ✓ Image stored for indexing
✓ Indexed 187 packages
Target │ nginx:latest │ 0C 2H 12M 25L
digest │ a8758716bb6a │
Base image │ debian:bookworm-slim
What's Next?
View vulnerabilities → docker scout cves nginx:latest
View base image update recommendations → docker scout recommendations nginx:latest
|
詳細漏洞掃描
使用 docker scout cves 命令進行詳細的漏洞分析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 完整 CVE 掃描
docker scout cves nginx:latest
# 僅顯示高危及嚴重漏洞
docker scout cves --only-severity critical,high nginx:latest
# 輸出為 JSON 格式
docker scout cves --format json nginx:latest > vulnerabilities.json
# 輸出為 SARIF 格式(適用於 GitHub Security)
docker scout cves --format sarif nginx:latest > scout-results.sarif
# 只掃描特定類型的套件
docker scout cves --only-package-type npm nginx:latest
|
掃描結果過濾
1
2
3
4
5
6
7
8
| # 過濾特定 CVE
docker scout cves --only-cve CVE-2024-1234 nginx:latest
# 排除特定套件
docker scout cves --ignore-package openssl nginx:latest
# 僅顯示可修復的漏洞
docker scout cves --only-fixed nginx:latest
|
比較兩個映像檔
1
2
3
4
5
| # 比較兩個版本的漏洞差異
docker scout compare nginx:1.24 --to nginx:1.25
# 比較本地與遠端映像檔
docker scout compare myapp:local --to myapp:production
|
輸出範例:
1
2
3
4
5
6
7
8
9
10
| ✓ Analyzed image nginx:1.24
✓ Analyzed image nginx:1.25
│ nginx:1.24 │ nginx:1.25 │
─────────────────────────┼────────────┼────────────┤
Packages │ 187 │ 185 │
Critical vulnerabilities│ 0 │ 0 │
High vulnerabilities │ 2 │ 0 │
Medium vulnerabilities │ 12 │ 8 │
Low vulnerabilities │ 25 │ 20 │
|
SBOM 軟體物料清單
什麼是 SBOM?
軟體物料清單(Software Bill of Materials, SBOM)是一份詳細列出軟體組成元件的清單,包含:
生成 SBOM
1
2
3
4
5
6
7
8
9
10
11
| # 生成 SPDX 格式的 SBOM
docker scout sbom nginx:latest --format spdx > sbom-spdx.json
# 生成 CycloneDX 格式的 SBOM
docker scout sbom nginx:latest --format cyclonedx > sbom-cyclonedx.json
# 生成簡易格式的 SBOM
docker scout sbom nginx:latest --format list
# 僅列出特定類型的套件
docker scout sbom --only-package-type apk,deb nginx:latest
|
SBOM 輸出範例
1
| docker scout sbom --format list nginx:latest | head -20
|
輸出:
1
2
3
4
5
6
7
8
9
10
11
| Name Version Type
─────────────────────────────────────────────────
adduser 3.134 deb
apt 2.6.1 deb
base-files 12.4+deb12u5 deb
base-passwd 3.6.1 deb
bash 5.2.15-2+b2 deb
bsdutils 1:2.38.1-5+b1 deb
coreutils 9.1-1 deb
curl 7.88.1-10+deb12u5 deb
...
|
分析 SBOM 內容
1
2
3
4
5
| # 查看套件授權資訊
docker scout sbom nginx:latest --format spdx | jq '.packages[] | {name: .name, license: .licenseConcluded}'
# 統計套件類型
docker scout sbom nginx:latest --format list | awk '{print $3}' | sort | uniq -c
|
CVE 漏洞分析與修復建議
漏洞嚴重程度分類
Docker Scout 使用 CVSS(Common Vulnerability Scoring System)評分系統:
| 等級 | CVSS 分數 | 說明 |
|---|
| Critical | 9.0 - 10.0 | 嚴重漏洞,需立即修復 |
| High | 7.0 - 8.9 | 高危漏洞,應優先處理 |
| Medium | 4.0 - 6.9 | 中等風險,計劃性修復 |
| Low | 0.1 - 3.9 | 低風險,可視情況處理 |
詳細漏洞資訊
1
2
3
4
5
| # 查看完整漏洞詳情
docker scout cves --format markdown nginx:latest
# 查看特定 CVE 的詳細資訊
docker scout cves nginx:latest 2>&1 | grep -A 10 "CVE-2024"
|
獲取修復建議
1
2
3
4
5
| # 查看基礎映像檔升級建議
docker scout recommendations nginx:latest
# 查看詳細的修復建議
docker scout recommendations --format json nginx:latest
|
輸出範例:
1
2
3
4
5
6
7
8
9
10
11
12
| Current base image: debian:bookworm-slim
- Vulnerabilities: 2C 5H 15M 30L
Recommended updates:
1. Update to debian:bookworm-slim (newer version)
- Vulnerabilities: 0C 2H 10M 25L
- Reduces: 2C 3H 5M 5L
2. Switch to alpine:3.19
- Vulnerabilities: 0C 0H 2M 5L
- Reduces: 2C 5H 13M 25L
|
建立 VEX 聲明
VEX(Vulnerability Exploitability eXchange)允許您聲明某些漏洞在您的環境中不受影響:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # 建立 VEX 聲明檔案
cat > vex.json << 'EOF'
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://example.com/vex/myapp",
"author": "security@example.com",
"timestamp": "2025-05-19T00:00:00Z",
"statements": [
{
"vulnerability": {
"@id": "CVE-2024-1234"
},
"products": [
{
"@id": "pkg:docker/myapp@1.0.0"
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_present"
}
]
}
EOF
# 使用 VEX 聲明進行掃描
docker scout cves --vex-location ./vex.json myapp:1.0.0
|
政策與合規性檢查
內建政策
Docker Scout 提供多種內建安全政策:
1
2
3
4
5
| # 列出所有可用政策
docker scout policy list
# 查看政策詳情
docker scout policy inspect <policy-name>
|
常見的內建政策:
| 政策名稱 | 說明 |
|---|
| no-critical-vulnerabilities | 不允許存在嚴重漏洞 |
| no-high-vulnerabilities | 不允許存在高危漏洞 |
| no-fixable-vulnerabilities | 不允許存在可修復的漏洞 |
| approved-base-images | 僅允許使用核准的基礎映像檔 |
| no-unapproved-licenses | 不允許使用未核准的授權 |
評估映像檔政策
1
2
3
4
5
6
7
8
| # 評估單一映像檔
docker scout policy evaluate nginx:latest
# 評估特定政策
docker scout policy evaluate --policy no-critical-vulnerabilities nginx:latest
# 輸出 JSON 格式的評估結果
docker scout policy evaluate --format json nginx:latest
|
自訂政策
建立自訂政策檔案 custom-policy.yaml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| # custom-policy.yaml
version: "1.0"
policies:
- name: production-ready
description: "生產環境映像檔安全標準"
rules:
- type: vulnerability
severity:
- critical
action: deny
message: "不允許存在嚴重漏洞"
- type: vulnerability
severity:
- high
max_count: 5
action: warn
message: "高危漏洞數量超過閾值"
- type: base-image
allowed:
- "alpine:3.*"
- "debian:bookworm-slim"
- "ubuntu:22.04"
action: deny
message: "必須使用核准的基礎映像檔"
- type: license
denied:
- "GPL-3.0"
- "AGPL-3.0"
action: warn
message: "包含受限授權的套件"
|
1
2
| # 使用自訂政策評估
docker scout policy evaluate --policy-file custom-policy.yaml myapp:latest
|
組織級政策管理
1
2
3
4
5
| # 為組織設定預設政策
docker scout config organization <org-name> --policy no-critical-vulnerabilities
# 查看組織政策狀態
docker scout policy status --org <org-name>
|
CI/CD 整合
GitHub Actions 整合
建立 .github/workflows/docker-scout.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| name: Docker Scout Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build image
uses: docker/build-push-action@v5
with:
context: .
push: false
load: true
tags: ${{ github.repository }}:${{ github.sha }}
- name: Docker Scout Quickview
uses: docker/scout-action@v1
with:
command: quickview
image: ${{ github.repository }}:${{ github.sha }}
- name: Docker Scout CVE Scan
uses: docker/scout-action@v1
with:
command: cves
image: ${{ github.repository }}:${{ github.sha }}
only-severities: critical,high
exit-code: true
- name: Docker Scout SBOM
uses: docker/scout-action@v1
with:
command: sbom
image: ${{ github.repository }}:${{ github.sha }}
output: sbom.spdx.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.spdx.json
- name: Compare with previous version
uses: docker/scout-action@v1
if: github.event_name == 'pull_request'
with:
command: compare
image: ${{ github.repository }}:${{ github.sha }}
to: ${{ github.repository }}:latest
exit-code: true
only-severities: critical,high
|
GitLab CI 整合
建立 .gitlab-ci.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| stages:
- build
- scan
- deploy
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
scout-scan:
stage: scan
image: docker:24
services:
- docker:24-dind
before_script:
- apk add --no-cache curl
- curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
- docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_TOKEN
script:
- docker pull $DOCKER_IMAGE
- docker scout cves $DOCKER_IMAGE --exit-code --only-severity critical,high
- docker scout sbom $DOCKER_IMAGE --format spdx > sbom.json
artifacts:
paths:
- sbom.json
expire_in: 1 week
allow_failure: false
scout-policy:
stage: scan
image: docker:24
services:
- docker:24-dind
before_script:
- apk add --no-cache curl
- curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
- docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_TOKEN
script:
- docker pull $DOCKER_IMAGE
- docker scout policy evaluate $DOCKER_IMAGE
allow_failure: true
|
Jenkins Pipeline 整合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
| // Jenkinsfile
pipeline {
agent any
environment {
DOCKER_IMAGE = "${env.DOCKER_REGISTRY}/${env.JOB_NAME}:${env.BUILD_NUMBER}"
DOCKERHUB_CREDENTIALS = credentials('dockerhub-credentials')
}
stages {
stage('Build') {
steps {
script {
docker.build(DOCKER_IMAGE)
}
}
}
stage('Security Scan') {
steps {
script {
// 登入 Docker Hub
sh '''
echo $DOCKERHUB_CREDENTIALS_PSW | docker login -u $DOCKERHUB_CREDENTIALS_USR --password-stdin
'''
// 執行 Docker Scout 掃描
sh '''
docker scout cves ${DOCKER_IMAGE} --format sarif --output scout-results.sarif
docker scout cves ${DOCKER_IMAGE} --only-severity critical,high --exit-code
'''
}
}
post {
always {
// 上傳 SARIF 結果
archiveArtifacts artifacts: 'scout-results.sarif', fingerprint: true
}
}
}
stage('SBOM Generation') {
steps {
sh '''
docker scout sbom ${DOCKER_IMAGE} --format spdx --output sbom.spdx.json
'''
}
post {
always {
archiveArtifacts artifacts: 'sbom.spdx.json', fingerprint: true
}
}
}
stage('Policy Check') {
steps {
sh '''
docker scout policy evaluate ${DOCKER_IMAGE} || true
'''
}
}
stage('Push') {
when {
branch 'main'
}
steps {
script {
docker.withRegistry("https://${env.DOCKER_REGISTRY}", 'docker-registry-credentials') {
docker.image(DOCKER_IMAGE).push()
docker.image(DOCKER_IMAGE).push('latest')
}
}
}
}
}
post {
always {
sh 'docker logout'
}
}
}
|
使用 Pre-commit Hook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| #!/bin/bash
# .git/hooks/pre-push
echo "Running Docker Scout security scan..."
# 取得要推送的映像檔標籤
IMAGE_TAG=$(docker images --format "{{.Repository}}:{{.Tag}}" | head -1)
if [ -z "$IMAGE_TAG" ]; then
echo "No Docker image found. Skipping scan."
exit 0
fi
# 執行掃描
docker scout cves "$IMAGE_TAG" --only-severity critical,high --exit-code
if [ $? -ne 0 ]; then
echo "❌ Security scan failed! Critical or high vulnerabilities detected."
echo "Please fix the vulnerabilities before pushing."
exit 1
fi
echo "✅ Security scan passed."
exit 0
|
與其他工具比較
Docker Scout vs Trivy vs Snyk
| 功能特性 | Docker Scout | Trivy | Snyk |
|---|
| 授權模式 | 免費 + 付費方案 | 開源免費 | 免費 + 付費方案 |
| 掃描速度 | 快速 | 非常快速 | 中等 |
| 漏洞資料庫 | 多來源整合 | 多來源整合 | Snyk 專屬資料庫 |
| SBOM 支援 | SPDX, CycloneDX | SPDX, CycloneDX | SPDX |
| 政策引擎 | 內建 | 需搭配 OPA | 內建 |
| IDE 整合 | Docker Desktop | VS Code 外掛 | 多種 IDE |
| CI/CD 整合 | 原生支援 | 原生支援 | 原生支援 |
| 修復建議 | 詳細 | 基本 | 詳細 |
| 容器 Runtime 掃描 | 有限 | 支援 | 支援 |
| IaC 掃描 | 不支援 | 支援 | 支援 |
Trivy 使用範例
1
2
3
4
5
6
7
8
9
10
11
| # 安裝 Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# 掃描映像檔
trivy image nginx:latest
# 僅顯示嚴重漏洞
trivy image --severity CRITICAL,HIGH nginx:latest
# 生成 SBOM
trivy image --format spdx-json -o sbom.json nginx:latest
|
Snyk 使用範例
1
2
3
4
5
6
7
8
9
10
11
| # 安裝 Snyk CLI
npm install -g snyk
# 登入
snyk auth
# 掃描容器映像檔
snyk container test nginx:latest
# 監控映像檔
snyk container monitor nginx:latest
|
選擇建議
| 使用情境 | 建議工具 |
|---|
| 已使用 Docker 生態系統 | Docker Scout |
| 需要開源且快速的方案 | Trivy |
| 企業級功能與支援 | Snyk |
| 需要 IaC 掃描整合 | Trivy 或 Snyk |
| 注重修復建議品質 | Docker Scout 或 Snyk |
| 預算有限 | Trivy |
多工具整合策略
在實際生產環境中,建議結合多種工具以獲得更全面的安全覆蓋:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| # 多工具掃描 GitHub Actions 範例
name: Multi-tool Security Scan
on:
push:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
# Docker Scout 掃描
- name: Docker Scout Scan
uses: docker/scout-action@v1
with:
command: cves
image: myapp:${{ github.sha }}
sarif-file: scout-results.sarif
# Trivy 掃描
- name: Trivy Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
# Snyk 掃描
- name: Snyk Scan
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: myapp:${{ github.sha }}
args: --sarif-file-output=snyk-results.sarif
# 上傳所有結果到 GitHub Security
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: .
|
最佳實踐
1. 建立安全基線
1
2
3
4
5
| # 定期掃描基礎映像檔
docker scout cves alpine:3.19 --format json > baseline-alpine.json
# 比較應用程式映像檔與基線
docker scout compare myapp:latest --to alpine:3.19
|
2. 自動化漏洞通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #!/bin/bash
# daily-scan.sh
IMAGES=("myapp:production" "myapi:production" "myworker:production")
THRESHOLD="high"
for image in "${IMAGES[@]}"; do
result=$(docker scout cves "$image" --only-severity critical,high --format json)
count=$(echo "$result" | jq '.vulnerabilities | length')
if [ "$count" -gt 0 ]; then
echo "⚠️ $image has $count $THRESHOLD+ vulnerabilities" | \
mail -s "Security Alert: $image" security@example.com
fi
done
|
3. 映像檔標籤策略
1
2
3
4
5
6
7
8
9
10
11
| # Dockerfile 最佳實踐
# 使用固定版本標籤
FROM alpine:3.19.1@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b
# 使用非 root 使用者
RUN adduser -D appuser
USER appuser
# 最小化安裝
RUN apk add --no-cache python3 && \
rm -rf /var/cache/apk/*
|
4. 持續監控
1
2
3
4
5
| # 啟用持續監控
docker scout watch myorg/myapp
# 設定 Webhook 通知
docker scout config set webhook-url https://hooks.slack.com/services/xxx
|
結論
Docker Scout 作為 Docker 官方推出的容器安全掃描工具,提供了完整的漏洞掃描、SBOM 生成、政策評估等功能。其與 Docker 生態系統的原生整合使其成為使用 Docker 的團隊的理想選擇。
透過本文介紹的各項功能和 CI/CD 整合方法,您可以將容器安全檢查融入軟體開發生命週期的各個階段,實現「左移安全」(Shift Left Security)的目標。
無論您選擇使用 Docker Scout、Trivy 還是 Snyk,重要的是建立持續的安全掃描流程,及時發現並修復漏洞,確保容器化應用程式的安全性。
參考資源