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
相关产品推荐
相关产品推荐

