本文目录导读:

在Shell脚本中扫描容器镜像漏洞,通常需要借助第三方的漏洞扫描工具,以下是几种常见的方法和对应的脚本示例:
使用 Trivy(推荐)
Trivy 是最流行的开源容器漏洞扫描工具之一。
安装 Trivy
# macOS brew install trivy # Linux curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh # Docker 方式运行 docker run aquasec/trivy --help
扫描脚本示例
#!/bin/bash
# 扫描单个镜像
scan_image() {
local image_name="$1"
echo "扫描镜像: $image_name"
# Trivy 扫描,输出 JSON 格式
trivy image --format json --output "${image_name//\//_}_scan.json" "$image_name"
# 检查是否有严重漏洞
trivy image --severity CRITICAL,HIGH --exit-code 1 "$image_name"
if [ $? -eq 1 ]; then
echo "警告: 发现严重或高危漏洞!"
return 1
fi
return 0
}
# 批量扫描多个镜像
scan_images() {
local images=("$@")
local failed=0
for image in "${images[@]}"; do
if ! scan_image "$image"; then
failed=$((failed + 1))
fi
done
echo "扫描完成: $failed 个镜像存在漏洞"
return $failed
}
# 使用示例
images=(
"nginx:latest"
"node:14-alpine"
"python:3.9-slim"
)
scan_images "${images[@]}"
使用 Grype
Grype 是 Anchore 的开源漏洞扫描工具。
安装 Grype
# macOS brew install grype # Linux curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
扫描脚本
#!/bin/bash
scan_with_grype() {
local image="$1"
local output_file="${image//\//_}_grype_scan.json"
echo "使用 Grype 扫描: $image"
# JSON 格式输出
grype "$image" -o json > "$output_file"
# 仅显示严重漏洞
echo "严重漏洞:"
cat "$output_file" | jq '.matches[] | select(.vulnerability.severity == "Critical") | {package: .artifact.name, vulnerability: .vulnerability.id}'
# 检查并返回退出码
grype "$image" --fail-on Critical --quiet
return $?
}
# 使用示例
if scan_with_grype "nginx:latest"; then
echo "未发现严重漏洞"
else
echo "发现严重漏洞,请检查报告"
fi
使用 Docker Scout(Docker Desktop 内置)
#!/bin/bash
# 需要 Docker Desktop 4.17+
scan_with_docker_scout() {
local image="$1"
echo "使用 Docker Scout 扫描: $image"
# 登录 Docker Hub(如果需要)
# docker login
# 启用 Docker Scout
docker scout enable
# 扫描镜像
docker scout quickview "$image"
# 获取详细报告
docker scout recommendations "$image"
# 比较镜像
docker scout compare "$image" --to "nginx:1.25-alpine"
}
# 使用示例
scan_with_docker_scout "nginx:latest"
综合扫描脚本(带CI/CD集成)
#!/bin/bash
set -euo pipefail
# 配置
SCANNER="trivy" # trivy, grype, or docker-scout
SEVERITY_THRESHOLD="CRITICAL,HIGH"
EXIT_ON_FINDINGS=true
REPORT_DIR="./security_reports"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 检查工具安装
check_tool() {
if ! command -v "$1" &> /dev/null; then
log_error "$1 未安装"
exit 1
fi
}
# 创建报告目录
setup_reports() {
mkdir -p "$REPORT_DIR"
local timestamp=$(date +%Y%m%d_%H%M%S)
REPORT_FILE="$REPORT_DIR/scan_report_$timestamp.json"
}
# 使用 Trivy 扫描
trivy_scan() {
local image="$1"
local image_safe="${image//\//_}"
log_info "开始 Trivy 扫描: $image"
# 完整扫描并输出 JSON
trivy image --format json \
--severity "$SEVERITY_THRESHOLD" \
--output "$REPORT_DIR/${image_safe}_trivy.json" \
"$image" 2>/dev/null
# 快速检查漏洞
local vuln_count=$(trivy image --severity "$SEVERITY_THRESHOLD" \
--exit-code 0 \
--quiet \
"$image" 2>/dev/null | grep -c "Total:")
echo "$vuln_count"
}
# 生成HTML报告
generate_html_report() {
local image="$1"
local image_safe="${image//\//_}"
local html_file="$REPORT_DIR/${image_safe}_report.html"
cat > "$html_file" << EOF
<!DOCTYPE html>
<html>
<head>容器漏洞扫描报告 - $image</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
h1 { color: #333; }
.critical { color: red; }
.high { color: orange; }
.medium { color: yellow; }
.low { color: green; }
</style>
</head>
<body>
<h1>扫描报告: $image</h1>
<p>扫描时间: $(date)</p>
<h2>漏洞摘要</h2>
<pre>$(cat "$REPORT_DIR/${image_safe}_trivy.json" | python3 -m json.tool 2>/dev/null || cat "$REPORT_DIR/${image_safe}_trivy.json")</pre>
</body>
</html>
EOF
log_info "HTML报告已生成: $html_file"
}
# 清理函数
cleanup() {
log_info "清理临时文件..."
# 可以在这里添加清理逻辑
}
# 主函数
main() {
local images=("$@")
if [ ${#images[@]} -eq 0 ]; then
log_error "请提供要扫描的镜像名称"
echo "用法: $0 <镜像1> [镜像2] ..."
exit 1
fi
# 设置清理陷阱
trap cleanup EXIT
# 检查工具
check_tool "$SCANNER"
setup_reports
local total_vulns=0
local failed_images=0
for image in "${images[@]}"; do
echo -e "\n${YELLOW}═══════════════════════════════════════${NC}"
log_info "扫描镜像: $image"
echo -e "${YELLOW}═══════════════════════════════════════${NC}\n"
# 执行扫描
if [ "$SCANNER" = "trivy" ]; then
vuln_count=$(trivy_scan "$image")
if [ "$vuln_count" -gt 0 ] && [ "$EXIT_ON_FINDINGS" = true ]; then
log_warn "发现 $vuln_count 个漏洞"
generate_html_report "$image"
failed_images=$((failed_images + 1))
else
log_info "未发现漏洞"
fi
fi
total_vulns=$((total_vulns + vuln_count))
done
# 输出总结
echo -e "\n${YELLOW}═══════════════════════════════════════${NC}"
log_info "扫描完成"
echo "扫描镜像数: ${#images[@]}"
echo "存在漏洞的镜像数: $failed_images"
echo "总漏洞数: $total_vulns"
echo "报告位置: $REPORT_DIR"
echo -e "${YELLOW}═══════════════════════════════════════${NC}"
# 返回非零退出码表示有漏洞
if [ "$failed_images" -gt 0 ] && [ "$EXIT_ON_FINDINGS" = true ]; then
exit 1
fi
}
# 执行主函数
main "$@"
使用方式
基本用法
# 扫描单个镜像 ./scan.sh nginx:latest # 扫描多个镜像 ./scan.sh nginx:latest node:14-alpine python:3.9 # 忽略漏洞继续执行 ./scan.sh --no-fail nginx:latest
CI/CD 集成示例 (GitLab CI)
container-scan:
stage: test
image: aquasec/trivy:latest
script:
- trivy image --severity CRITICAL,HIGH --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
重要提示
-
更新漏洞数据库:定期更新扫描工具的漏洞数据库
trivy image --update # 或 trivy image --cache-backend redis://localhost:6379
-
性能考虑:大规模扫描时考虑使用缓存和并行处理
-
权限管理:确保脚本有适当的执行权限
chmod +x scan.sh
-
结果处理:根据业务需求决定如何处理发现的漏洞(阻塞发布、记录报警等)
这些脚本提供了完整的容器漏洞扫描解决方案,可以根据具体需求进行调整和扩展。