Golang 1.22.5-alpine3.20镜像在ECR中发现重大安全漏洞

Golang 1.22.5-alpine3.20镜像在ECR中发现重大安全漏洞 我不太确定如何解决 AWS ECR 安全扫描针对这个“官方” Docker 镜像(golang:1.22.5-alpine3.20)所发现的 CVE 漏洞。报告的 CVE 如下所示,它们似乎都来自 /usr/local/go/src 目录下的 go.mod 文件。

image

深入查看细节,我发现它们都指向相同的 3 个包:golang/x/net、golang/x/crypt 和 golang/x/text。

一个详细的示例如下:

CVE-2022-27191 - golang.org/x/crypto, golang.org/x/crypto
Finding ID: arn:aws:inspector2:eu-west-2:######657:finding/58b03c24c39cde6d8f20e74fd89da72e
The golang.org/x/crypto/ssh package before 0.0.0-20220314234659-1baeb1ce4c0b for Go allows an attacker to crash a server in certain circumstances involving AddHostKey.

Finding details...

Inspector score and vulnerability intelligence
Finding overview
Severity: High
Type: Package Vulnerability
Fix available: Yes
Last known public exploit at
Exploit available
No
Created at: August 3, 2024 10:33 AM (UTC-04:00)
Affected packages
Name: golang.org/x/crypto
Installed version / Fixed version: 0:0.0.0-20191011191535-87dc89f01550 / 0.0.0-20220314234659-1baeb1ce4c0b
Package manager: GOMOD
File paths:usr/local/go/src/crypto/internal/edwards25519/field/_asm/go.sum, usr/local/go/src/crypto/internal/bigmod/_asm/go.sum

有人能指点我一下,如何在不影响 Go 安装“官方”版本的前提下修复这些问题吗?我不太愿意修改这个镜像。我们使用这个镜像作为 Docker 构建器来构建我们的 Go 应用程序。那些构建出来的应用程序在扫描中没有显示任何 CVE。但是,我们的安全团队一直在提醒我,这个 Go 构建镜像存在 11 个主要 CVE。我也不确定我的应用程序是否会从构建器镜像的 /usr/local/go/src 中获取 golang.org/x/{crypt,net,text} 的代码。为什么一个官方版本一开始就会包含这样的 CVE 呢?我是第一次处理这类补丁问题,如果我问的问题很基础,还请见谅。提前感谢任何帮助和指点。


更多关于Golang 1.22.5-alpine3.20镜像在ECR中发现重大安全漏洞的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang 1.22.5-alpine3.20镜像在ECR中发现重大安全漏洞的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Golang构建镜像中处理CVE漏洞的标准做法是通过多阶段构建来隔离构建环境和运行时环境。以下是解决方案:

1. 标准的多阶段构建模式

# 构建阶段 - 使用官方镜像(包含CVE)
FROM golang:1.22.5-alpine3.20 AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main ./cmd/main.go

# 运行阶段 - 使用干净的运行时镜像
FROM alpine:3.20

RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .

# 添加必要的库(如果需要)
# RUN apk --no-cache add libc6-compat

EXPOSE 8080
CMD ["./main"]

2. 验证应用程序的依赖关系

创建验证脚本来检查应用程序实际使用的依赖版本:

// check-deps.go
package main

import (
    "encoding/json"
    "fmt"
    "os/exec"
    "strings"
)

func main() {
    // 获取go.mod中的依赖
    cmd := exec.Command("go", "list", "-m", "all")
    output, err := cmd.Output()
    if err != nil {
        panic(err)
    }
    
    modules := strings.Split(string(output), "\n")
    for _, mod := range modules {
        if strings.Contains(mod, "golang.org/x/") {
            fmt.Println(mod)
        }
    }
    
    // 检查vendor目录(如果使用vendor)
    cmd = exec.Command("go", "mod", "vendor")
    if err := cmd.Run(); err == nil {
        fmt.Println("Vendor目录已创建,包含所有依赖")
    }
}

3. 使用go mod tidy更新依赖

在Dockerfile中显式更新易受攻击的模块:

FROM golang:1.22.5-alpine3.20 AS builder

WORKDIR /app
COPY go.mod go.sum ./

# 显式更新有CVE的模块
RUN go get golang.org/x/crypto@latest && \
    go get golang.org/x/net@latest && \
    go get golang.org/x/text@latest && \
    go mod tidy

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/main ./cmd/main.go

4. 使用最小化基础镜像

对于更严格的安全要求,使用distroless或scratch镜像:

# 构建阶段
FROM golang:1.22.5-alpine3.20 AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/main ./cmd/main.go

# 使用distroless镜像
FROM gcr.io/distroless/static-debian12

COPY --from=builder /app/main /
CMD ["/main"]

5. 验证构建镜像的安全性

创建测试来验证应用程序不包含易受攻击的代码:

// security_test.go
package main

import (
    "testing"
    "os/exec"
    "strings"
)

func TestNoVulnerableDependencies(t *testing.T) {
    cmd := exec.Command("go", "list", "-m", "all")
    output, err := cmd.Output()
    if err != nil {
        t.Fatal(err)
    }
    
    vulnerableVersions := map[string]string{
        "golang.org/x/crypto": "0.0.0-20191011191535-87dc89f01550",
        "golang.org/x/net": "0.0.0-20191011234639-9e8e44b5b54c",
        "golang.org/x/text": "0.3.0",
    }
    
    for _, line := range strings.Split(string(output), "\n") {
        for pkg, badVersion := range vulnerableVersions {
            if strings.Contains(line, pkg) && strings.Contains(line, badVersion) {
                t.Errorf("发现易受攻击的依赖: %s", line)
            }
        }
    }
}

关键点说明:

  1. 构建镜像中的CVE不影响最终应用:构建镜像中的/usr/local/go/src包含的是Go工具链的源代码,不是应用程序的运行时依赖

  2. 应用程序依赖由go.mod控制:应用程序实际使用的golang.org/x/*模块版本由项目的go.mod文件决定

  3. 多阶段构建是标准解决方案:构建阶段使用完整工具链,运行时阶段使用最小化镜像

  4. 安全扫描的误报:ECR扫描构建镜像时检测到的是工具链源代码中的CVE,这些不会打包到最终应用镜像中

通过多阶段构建,可以确保最终部署的镜像只包含编译后的二进制文件和必要的运行时文件,从而消除构建镜像中CVE的影响。

回到顶部