You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Kubernetes中Golang服务如何结合GCP WIP与go-containerregistry拉取GAR镜像

解决方案

要实现通过GCP工作负载身份池(WIP)获取令牌,并用go-containerregistry拉取GAR镜像,需要分四步完成:获取AWS临时凭证、交换GCP身份令牌、获取GAR访问令牌、配置go-containerregistry认证。以下是完整代码示例:

依赖安装

先安装所需依赖包:

go get github.com/aws/aws-sdk-go-v2/aws
go get github.com/aws/aws-sdk-go-v2/config
go get google.golang.org/api/sts/v1
go get google.golang.org/api/oauth2/v2
go get github.com/google/go-containerregistry/pkg/authn
go get github.com/google/go-containerregistry/pkg/remote

完整代码示例

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/sts"
	"github.com/google/go-containerregistry/pkg/authn"
	"github.com/google/go-containerregistry/pkg/remote"
	"google.golang.org/api/oauth2/v2"
	"google.golang.org/api/sts/v1"
	"google.golang.org/api/option"
)

const (
	// 替换为你的GCP项目编号、工作负载身份池ID、提供商ID
	gcpProjectNumber = "1234567890"
	wipPoolID        = "aws-pool"
	wipProviderID    = "aws-provider"
	// GAR仓库地址示例
	garImageRef = "us-central1-docker.pkg.dev/my-project/my-repo/my-image:latest"
)

func main() {
	ctx := context.Background()

	// 1. 获取AWS临时凭证(K8s服务账号已绑定IAM角色,自动通过IRSA获取)
	cfg, err := config.LoadDefaultConfig(ctx)
	if err != nil {
		panic(fmt.Sprintf("加载AWS配置失败: %v", err))
	}
	creds, err := cfg.Credentials.Retrieve(ctx)
	if err != nil {
		panic(fmt.Sprintf("获取AWS凭证失败: %v", err))
	}

	// 调用AWS STS获取Caller Identity
	stsClient := sts.NewFromConfig(cfg)
	callerResp, err := stsClient.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
	if err != nil {
		panic(fmt.Sprintf("获取AWS Caller Identity失败: %v", err))
	}

	// 2. 用AWS凭证交换GCP工作负载身份池的身份令牌
	gcpStsService, err := sts.NewService(ctx)
	if err != nil {
		panic(fmt.Sprintf("初始化GCP STS服务失败: %v", err))
	}

	wipResource := fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s/providers/%s",
		gcpProjectNumber, wipPoolID, wipProviderID)

	tokenReq := &sts.GoogleIdentityStsV1ExchangeTokenRequest{
		GrantType:          "urn:ietf:params:oauth:grant-type:token-exchange",
		SubjectToken:       creds.SessionToken,
		SubjectTokenType:   "urn:ietf:params:aws:token-type:session-token",
		Audience:           wipResource,
		RequestedTokenType: "urn:ietf:params:oauth:token-type:jwt",
		Scope:              "https://www.googleapis.com/auth/cloud-platform",
		ActorToken:         *callerResp.Arn,
		ActorTokenType:     "urn:ietf:params:aws:token-type:arn",
	}

	tokenResp, err := gcpStsService.V1.ExchangeToken(tokenReq).Do()
	if err != nil {
		panic(fmt.Sprintf("交换GCP身份令牌失败: %v", err))
	}

	// 3. 用GCP身份令牌获取GAR访问令牌
	garTokenReqBody := strings.NewReader(fmt.Sprintf(
		`grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=%s&scope=https://www.googleapis.com/auth/cloud-platform`,
		tokenResp.Token,
	))
	garTokenResp, err := http.Post("https://oauth2.googleapis.com/token", "application/x-www-form-urlencoded", garTokenReqBody)
	if err != nil {
		panic(fmt.Sprintf("请求GAR访问令牌失败: %v", err))
	}
	defer garTokenResp.Body.Close()

	garTokenBody, err := io.ReadAll(garTokenResp.Body)
	if err != nil {
		panic(fmt.Sprintf("读取GAR令牌响应失败: %v", err))
	}

	var garTokenData map[string]interface{}
	if err := json.Unmarshal(garTokenBody, &garTokenData); err != nil {
		panic(fmt.Sprintf("解析GAR令牌响应失败: %v", err))
	}
	garAccessToken := garTokenData["access_token"].(string)

	// 4. 配置go-containerregistry认证并拉取镜像
	auth := authn.FromConfig(authn.AuthConfig{
		Username: "_token",
		Password: garAccessToken,
	})

	img, err := remote.Image(garImageRef, remote.WithAuth(auth))
	if err != nil {
		panic(fmt.Sprintf("拉取GAR镜像失败: %v", err))
	}

	// 验证镜像拉取结果
	manifest, err := img.Manifest()
	if err != nil {
		panic(fmt.Sprintf("获取镜像Manifest失败: %v", err))
	}
	fmt.Printf("成功拉取镜像,Manifest Digest: %s\n", manifest.Config.Digest.String())
}

关键说明

  • AWS凭证获取:在绑定了IAM角色的K8s服务账号环境中,会自动通过IRSA机制获取临时凭证,无需手动配置密钥。
  • GCP STS令牌交换:通过GCP STS服务将AWS会话令牌转换为WIP身份令牌,请求参数需严格匹配GCP的令牌交换规范。
  • GAR访问令牌:GAR的认证要求固定用_token作为用户名,访问令牌作为密码,通过OAuth2端点获取。
  • go-containerregistry集成:通过authn.FromConfig构造认证配置,传递给remote.Image即可实现带认证的镜像拉取。

内容的提问来源于stack exchange,提问作者Mitul Sheth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:31:23