无法使用默认服务帐户和 google 云库从 Google Kubernetes Engine 访问 Google 云存储

Unable to access Google Cloud Storage from Google Kubernetes Engine using default service account and google cloud libraries

我编写了一个应用程序,它具有通过 Google Kubernetes Engine 使用 go lang 上传图像的功能。其他一切正常,但当我尝试将图像写入 Google 云存储时,我一直 运行 遇到问题。

这是我在 golang 中实际使用 google 存储的代码 api:

func putImage(imageURL string, image multipart.File) bool {
    fmt.Println("Putting into image location : " + imageURL)

    contextBackground := context.Background()
    storageClient, err := storage.NewClient(contextBackground)
    if err != nil {
        fmt.Println("No client.")
        return false
    }

    bucket := storageClient.Bucket("mytestbucketname")
    bucketWriter := bucket.Object(imageURL).NewWriter(contextBackground)
    bucketWriter.ContentType = "image/jpg"
    bucketWriter.CacheControl = "public, max-age=0"

    size, err := io.Copy(bucketWriter, image)
    if err != nil {
        fmt.Println("failed to put image")
        return false
    }

    fmt.Println(size)
    fmt.Println("Successfully put image")
    bucketWriter.Close()
    return true
}

上面的函数总是returns true 并且大小总是大于0。但是,当我检查桶时,里面实际上没有任何东西。所以我研究了一下,发现默认的服务账户只有对云存储的读取权限。这很奇怪,因为它应该返回 false 或 size 应该为 0 甚至输出权限被拒绝的错误。

官方cloud.google.com/go/storage API说Bucket()函数returns是一个BucketHandle,实际上不执行任何网络操作,这就说得通了我没有得到权限被拒绝的错误(?)。因此,我决定检查我是否真的从客户端或存储桶中获取任何内容,只是为了查看读取权限是否有效。我添加了以下代码:

attr, err := bucket.Attrs(contextBackground)
if err != nil {
    fmt.Println(err.Error())
}
fmt.Println("bucket name : " + attr.Name)

此时我开始遇到关闭我的应用程序的致命错误。我在尝试检索存储桶的属性时遇到的错误是:

Get https://www.googleapis.com/storage/v1/b/mytestbucketname?alt=json&prettyPrint=false&projection=full: oauth2: cannot fetch token: Post https://oauth2.googleapis.com/token: x509: certificate signed by unknown authority

所以我想我需要为我的图像添加 ca 证书。但这对我来说听起来不合逻辑,因为如果我是 运行 我在 Google Kubernetes Engine 中的图像并且它正在访问我的 Google 云存储,因为它已经有一个默认服务帐户具有读取权限,为什么我需要证书?我创建了一个版本为 1.12.8-gke.10 的新集群,并确保禁用问题客户端证书,并确保我具有对存储的读取权限,但仍然遇到相同的错误。我将这一行添加到我的 docker 文件中,但仍然出现相同的错误:

RUN apk --no-cache add ca-certificates && update-ca-certificates

我已经研究了两天了,现在我 运行 没主意了。我的问题是,当我使用默认权限尝试从 Kubernetes Engine 访问存储桶属性时,我做错了什么一直给我 "x.509 certificate signed by unknown authority" 错误?从技术上讲,获取存储桶属性只是一个读取功能,我应该能够在默认权限下执行此操作,对吗?如果有人有任何想法或曾经 运行 遇到同样的问题,请给我一些帮助!谢谢!

如果您使用的是默认集群服务帐户,则需要确保集群有 sufficient scopes to write to storage. By default,GKE 集群只有读取范围,它会阻止对 GCS 存储桶的写入尝试。

gke-default:
https://www.googleapis.com/auth/devstorage.read_only
https://www.googleapis.com/auth/logging.write
https://www.googleapis.com/auth/monitoring
https://www.googleapis.com/auth/service.management.readonly
https://www.googleapis.com/auth/servicecontrol
https://www.googleapis.com/auth/trace.append

如果不启用写入范围,无论凭据如何,您都无法写入存储桶。

Note: You can use the access token only for scopes that you specified when you created the instance. For example, if the instance has been granted only the https://www.googleapis.com/auth/storage-full scope for Google Cloud Storage, then it can't use the access token to make a request to BigQuery.

如果您想绕过作用域,请为应用程序创建一个自定义服务帐户,下载 JWT 令牌并将这些凭据直接安装到您的代码中。这是 recommended method to authenticate your application 针对 Google API

所以我终于弄明白了,如果有人也遇到过这个问题,就把它留在这里。是我太粗心了,但是看了这个问题后:

我能够将其缩小为证书问题。其实是因为我没有正确安装ca-certificate。因为我在 docker 文件中使用了多阶段构建,所以我放错了这行代码:

RUN apk --no-cache add ca-certificates && update-ca-certificates

正确放置后成功了!