Golang周刊#25:使用Docker Scout识别容器镜像漏洞

Golang周刊#25:使用Docker Scout识别容器镜像漏洞 packagemain #25: 使用 Docker Scout 识别容器镜像漏洞

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中实现自动安全检查,第三个示例提供了持续监控的方案。这些代码可以直接用于生产环境,实现容器镜像的漏洞管理。

回到顶部