如何通过API列举GCP项目内所有镜像URL以配合Go实现容器漏洞扫描
实现方案
核心原理
你执行的gcloud container images list命令底层对应两套API,根据你使用的镜像托管服务选择即可:
- 旧版Container Registry(gcr.io、us.gcr.io等域名):兼容Docker Registry V2 API,也可以直接调用GCP官方提供的Container Registry专用接口
- 新版Artifact Registry(<区域>-docker.pkg.dev域名):使用Artifact Registry官方Go SDK调用列表接口
注意事项
- 运行代码的身份(服务账号/个人账号)需要对应镜像仓库的读取权限,和调用Container Analysis API所需权限兼容,无需额外配置特殊权限
- 如果你的项目只使用其中一种镜像托管服务,只需要调用对应列表函数即可
Go代码实现示例
前置依赖
先安装所需依赖:
go get google.golang.org/api/containerregistry/v1 go get google.golang.org/api/artifactregistry/v1 go get golang.org/x/oauth2/google
1. 拉取Container Registry下所有镜像URL
package main import ( "context" "fmt" "golang.org/x/oauth2/google" "google.golang.org/api/containerregistry/v1" ) func listGCRImages(projectID string) ([]string, error) { ctx := context.Background() // 复用GCP默认认证,和Container Analysis SDK认证逻辑一致 client, err := google.DefaultClient(ctx, containerregistry.CloudPlatformScope) if err != nil { return nil, err } regService, err := containerregistry.New(client) if err != nil { return nil, err } var imageUrls []string // GCR支持的多区域域名,按需增删 domains := []string{"gcr.io", "us.gcr.io", "eu.gcr.io", "asia.gcr.io"} for _, domain := range domains { parent := fmt.Sprintf("projects/%s", projectID) res, err := regService.Projects.Tags.List(domain, parent).Do() if err != nil { // 对应区域没有镜像时跳过 continue } for _, img := range res.Child { // 拼接成符合要求的resourceURL格式 imageUrls = append(imageUrls, fmt.Sprintf("https://%s/%s/%s", domain, projectID, img)) } } return imageUrls, nil }
2. 拉取Artifact Registry下所有镜像URL
import "strings" import "google.golang.org/api/artifactregistry/v1" func listARImages(projectID string) ([]string, error) { ctx := context.Background() client, err := google.DefaultClient(ctx, artifactregistry.CloudPlatformScope) if err != nil { return nil, err } arService, err := artifactregistry.New(client) if err != nil { return nil, err } var imageUrls []string // 先拉取项目下所有Docker格式的仓库 parent := fmt.Sprintf("projects/%s/locations/-", projectID) // 用-代表查询所有区域 res, err := arService.Projects.Locations.Repositories.List(parent).Filter("format:DOCKER").Do() if err != nil { return nil, err } for _, repo := range res.Repositories { // 拉取单个仓库下所有镜像 pkgRes, err := arService.Projects.Locations.Repositories.Packages.List(repo.Name).Do() if err != nil { continue } for _, pkg := range pkgRes.Packages { // 解析出镜像URL parts := strings.Split(repo.Name, "/") location := parts[3] repoName := parts[5] imageName := strings.Split(pkg.Name, "/")[7] imageUrl := fmt.Sprintf("https://%s-docker.pkg.dev/%s/%s/%s", location, projectID, repoName, imageName) imageUrls = append(imageUrls, imageUrl) } } return imageUrls, nil }
后续使用
把两个函数返回的镜像URL列表合并后,循环调用findVulnerabilityOccurrencesForImage()即可获取全量镜像漏洞信息。
内容的提问来源于stack exchange,提问作者Emre Chomko
相关产品推荐
相关产品推荐

