如何在GKE(Go)中为Google云存储对象生成签名URL 目标:

如何在GKE(Go)中为Google云存储对象生成签名URL 目标:,go,google-cloud-platform,google-cloud-storage,google-kubernetes-engine,Go,Google Cloud Platform,Google Cloud Storage,Google Kubernetes Engine,在GKE POD中生成签名URL,而无需手动注入服务帐户JSON密钥。生成它们的语法需要服务帐户电子邮件和私钥 //导入“cloud.google.com/go/storage” url,err:=storage.SignedURL(bucketName、objectName和storage.SignedURLOptions{ ContentType:ContentType, GoogleAccessID:saEmail, 私钥:saPrivateKey, }) 换句话说,我想从GKE节点中自

在GKE POD中生成签名URL,而无需手动注入服务帐户JSON密钥。生成它们的语法需要服务帐户电子邮件和私钥

//导入“cloud.google.com/go/storage”
url,err:=storage.SignedURL(bucketName、objectName和storage.SignedURLOptions{
ContentType:ContentType,
GoogleAccessID:saEmail,
私钥:saPrivateKey,
})
换句话说,我想从GKE节点中自动可用的默认凭据加载
saEmail
saPrivateKey

尝试:
ctx:=context.Background()
//为简洁起见,错误被忽略
//导入“golang.org/x/oauth2/google”
creds,u:=google.FindDefaultCredentials(ctx、storage.ScopeReadWrite)
cfg,\:=google.JWTConfigFromJSON(creds.JSON)
url,:=storage.SignedURL(bucketName、objectName和storage.SignedURLOptions{
ContentType:ContentType,
GoogleAccessID:cfg.Email,
PrivateKey:cfg.PrivateKey,
})
当我在GKE pod中运行
google.FindDefaultCredentials()
时,结果JSON为空

环境:
  • Go
    1.13
  • GKE
    1.14.10-GKE.36
  • cloud.google.com/go
    v0.58.0
  • cloud.google.com/go/storage
    v1.8.0
补充说明: 我已经测试了两种可能的替代方案,包括将服务帐户密钥(JSON)手动注入pod,但我希望尽可能避免它们:

  • 将服务帐户密钥写入文件,并将
    GOOGLE\u应用程序\u凭据设置为其路径。完成此操作后,
    google.FindDefaultCredentials()
    将加载电子邮件和私钥

  • 将服务帐户密钥作为字符串传递到pod中,并使用
    google.JWTConfigFromJSON()
    对其进行解析


要生成签名URL,您需要有私钥

当您使用GCP服务(这里是计算实例,K8S集群的节点,但云运行、云函数等其他GCP服务也是如此)并且您使用默认凭证(并且没有定义GOOGLE_应用程序_凭证env var)时,库使用

元数据服务器允许您生成访问令牌

curl -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
或标识令牌(访问群体在参数中)

因此,在没有任何秘密或私钥的情况下,库能够生成用于访问外部API的令牌(访问或标识)

但是,元数据服务器不提供秘密(私钥),您不能将其用于生成已签名的URL

此处需要服务帐户密钥文件

您有几种方法可以安全地将其提供给pod

  • 标准K8S方式:
  • GCP托管解决方案:。由于有了元数据服务器,您可以实例化secret manager客户端并获取您的机密(您的服务帐户密钥文件),然后像以前一样使用它。另一种选择是,我,因此,您只需使用env var,而不必与秘密管理服务进行交互
我不建议您将您的服务帐户密钥文件直接放在容器中,这不是真正安全的

另一种解决方案

最终,您可以动态生成一个密钥,并将其定义为服务帐户密钥(其名称)

  • 您可以在集群上部署服务时生成它。就像这样,你不必存储秘密,它每次都是动态生成的
  • 您可以在容器启动时生成密钥,将其设置在服务帐户中,并将其保存在内存中
然后,当您在代码中需要它时使用它,它应该可以工作,因为它是指向您的服务帐户的链接


但是,您还需要考虑如何清除旧的和无用的密钥。

要生成签名URL,您需要有一个私钥

当您使用GCP服务(这里是计算实例,K8S集群的节点,但云运行、云函数等其他GCP服务也是如此)并且您使用默认凭证(并且没有定义GOOGLE_应用程序_凭证env var)时,库使用

元数据服务器允许您生成访问令牌

curl -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
或标识令牌(访问群体在参数中)

因此,在没有任何秘密或私钥的情况下,库能够生成用于访问外部API的令牌(访问或标识)

但是,元数据服务器不提供秘密(私钥),您不能将其用于生成已签名的URL

此处需要服务帐户密钥文件

您有几种方法可以安全地将其提供给pod

  • 标准K8S方式:
  • GCP托管解决方案:。由于有了元数据服务器,您可以实例化secret manager客户端并获取您的机密(您的服务帐户密钥文件),然后像以前一样使用它。另一种选择是,我,因此,您只需使用env var,而不必与秘密管理服务进行交互
我不建议您将您的服务帐户密钥文件直接放在容器中,这不是真正安全的

另一种解决方案

最终,您可以动态生成一个密钥,并将其定义为服务帐户密钥(其名称)

  • 您可以在集群上部署服务时生成它。就像这样,你不必存储秘密,它每次都是动态生成的
  • 您可以在容器启动时生成密钥,将其设置在服务帐户中,并将其保存在内存中
然后,当您在代码中需要它时使用它,它应该可以工作,因为它是指向您的服务帐户的链接


但是,您还需要考虑如何清理旧的和无用的钥匙。

我遇到了同样的问题,并在这里找到了解决方案:

TL;博士 我
//import (
//    "cloud.google.com/go/storage"
//    credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"
//    credentials "cloud.google.com/go/iam/credentials/apiv1"
//)

ctx := context.Background()
saEmail := "your-service-account-email@something-something.iam.gserviceaccount.com"

c, err := credentials.NewIamCredentialsClient(ctx)
if err != nil {
    panic(err)
}

url, err := storage.SignedURL(bucketName, objectName, &storage.SignedURLOptions{
    ContentType:    contentType,
    GoogleAccessID: saEmail,
    SignBytes: func(b []byte) ([]byte, error) {
        req := &credentialspb.SignBlobRequest{
            Payload: b,
            Name:    saEmail,
        }
        resp, err := c.SignBlob(ctx, req)
        if err != nil {
            panic(err)
        }
        return resp.SignedBlob, err
    }
})