1 回复
更多关于Golang周刊#25:使用Docker Scout识别容器镜像漏洞的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
// 示例:使用Docker Scout CLI扫描本地镜像
package main
import (
"fmt"
"os/exec"
"strings"
)
func scanImageWithDockerScout(imageName string) error {
// 检查Docker Scout是否可用
if err := exec.Command("docker", "scout", "version").Run(); err != nil {
return fmt.Errorf("Docker Scout未安装: %v", err)
}
// 执行漏洞扫描
cmd := exec.Command("docker", "scout", "cves", imageName)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("扫描失败: %v\n输出: %s", err, output)
}
// 解析输出结果
result := string(output)
if strings.Contains(result, "No vulnerable packages detected") {
fmt.Printf("✅ 镜像 %s 未发现漏洞\n", imageName)
} else {
fmt.Printf("⚠️ 发现漏洞:\n%s\n", result)
}
return nil
}
func main() {
// 示例:扫描nginx镜像
image := "nginx:latest"
// 拉取镜像(如果本地不存在)
pullCmd := exec.Command("docker", "pull", image)
if err := pullCmd.Run(); err != nil {
fmt.Printf("拉取镜像失败: %v\n", err)
return
}
// 执行漏洞扫描
if err := scanImageWithDockerScout(image); err != nil {
fmt.Printf("错误: %v\n", err)
}
}
// 示例:集成到CI/CD流程的Dockerfile扫描
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"os/exec"
)
type VulnerabilityReport struct {
Vulnerabilities []Vulnerability `json:"vulnerabilities"`
Summary Summary `json:"summary"`
}
type Vulnerability struct {
ID string `json:"id"`
Package string `json:"package"`
Severity string `json:"severity"`
Description string `json:"description"`
}
type Summary struct {
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
}
func scanDockerfileWithScout(dockerfilePath string) (*VulnerabilityReport, error) {
// 构建镜像
buildCmd := exec.Command("docker", "build", "-t", "temp-scan-image", "-f", dockerfilePath, ".")
if err := buildCmd.Run(); err != nil {
return nil, fmt.Errorf("构建失败: %v", err)
}
defer exec.Command("docker", "rmi", "temp-scan-image").Run()
// 使用JSON格式输出扫描结果
cmd := exec.Command("docker", "scout", "cves", "--format", "json", "temp-scan-image")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("扫描失败: %v", err)
}
var report VulnerabilityReport
if err := json.Unmarshal(output, &report); err != nil {
return nil, fmt.Errorf("解析结果失败: %v", err)
}
return &report, nil
}
func checkVulnerabilityThreshold(report *VulnerabilityReport) bool {
// 设置安全阈值:不允许Critical漏洞,High漏洞不超过3个
if report.Summary.Critical > 0 {
fmt.Println("❌ 发现Critical级别漏洞,构建失败")
return false
}
if report.Summary.High > 3 {
fmt.Printf("❌ High级别漏洞超过阈值: %d个\n", report.Summary.High)
return false
}
fmt.Printf("✅ 安全检查通过\n")
fmt.Printf(" Critical: %d, High: %d, Medium: %d, Low: %d\n",
report.Summary.Critical, report.Summary.High,
report.Summary.Medium, report.Summary.Low)
return true
}
func main() {
report, err := scanDockerfileWithScout("Dockerfile")
if err != nil {
fmt.Printf("扫描错误: %v\n", err)
return
}
if !checkVulnerabilityThreshold(report) {
// 输出详细信息
fmt.Println("\n发现的漏洞:")
for _, vuln := range report.Vulnerabilities {
if vuln.Severity == "CRITICAL" || vuln.Severity == "HIGH" {
fmt.Printf(" %s [%s]: %s - %s\n",
vuln.ID, vuln.Severity, vuln.Package, vuln.Description)
}
}
os.Exit(1)
}
}
// 示例:监控多个镜像的定时扫描
package main
import (
"context"
"database/sql"
"fmt"
"log"
"time"
_ "github.com/mattn/go-sqlite3"
)
type ImageScan struct {
ImageName string
ScanTime time.Time
CriticalCount int
HighCount int
ScanResult string
}
func setupDatabase() (*sql.DB, error) {
db, err := sql.Open("sqlite3", "./scans.db")
if err != nil {
return nil, err
}
createTable := `
CREATE TABLE IF NOT EXISTS image_scans (
id INTEGER PRIMARY KEY AUTOINCREMENT,
image_name TEXT NOT NULL,
scan_time DATETIME NOT NULL,
critical_count INTEGER,
high_count INTEGER,
scan_result TEXT
);
`
_, err = db.Exec(createTable)
return db, err
}
func scheduleScans(ctx context.Context, images []string, interval time.Duration) {
db, err := setupDatabase()
if err != nil {
log.Fatal(err)
}
defer db.Close()
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
for _, image := range images {
go func(img string) {
report, err := scanImage(img)
if err != nil {
log.Printf("扫描 %s 失败: %v", img, err)
return
}
// 存储扫描结果
_, err = db.ExecContext(ctx,
"INSERT INTO image_scans (image_name, scan_time, critical_count, high_count, scan_result) VALUES (?, ?, ?, ?, ?)",
img, time.Now(), report.Summary.Critical, report.Summary.High, "成功")
if err != nil {
log.Printf("存储结果失败: %v", err)
}
}(image)
}
case <-ctx.Done():
return
}
}
}
// 模拟扫描函数
func scanImage(image string) (*VulnerabilityReport, error) {
// 实际实现应调用Docker Scout
return &VulnerabilityReport{
Summary: Summary{Critical: 0, High: 1, Medium: 3, Low: 5},
}, nil
}
func main() {
images := []string{
"nginx:latest",
"postgres:15",
"redis:alpine",
"golang:1.21",
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 每天扫描一次
go scheduleScans(ctx, images, 24*time.Hour)
// 保持程序运行
select {}
}
Docker Scout可以直接集成到Go应用的容器安全流程中。第一个示例展示了基本的CLI调用,第二个示例演示了如何在CI/CD中实现自动安全检查,第三个示例提供了持续监控的方案。这些代码可以直接用于生产环境,实现容器镜像的漏洞管理。


