使用 Go 的 Google 云客户端库出现错误:未知的凭证类型:“impersonated_service_account”?

Dav*_*ith 4 authentication go google-docs-api google-drive-api google-cloud-platform

我正在 Go 中使用 Google Cloud,并关注 John Hanley 的这篇文章:

https://www.jhanley.com/google-cloud-improving-security-with-impersonation/

并把它与这个SO答案混在一起:

如何从 Google Compute Engine 和本地验证 Google API(Google Drive API),而无需下载服务帐户凭据?

凭据已成功保存到“application_default_credentials.json”:

注意:“type”:“ impersonated_service_account

    {
  "delegates": [],
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[sa@example-2021.iam.gserviceaccount.com]:generateAccessToken",
  "source_credentials": {
    "client_id": "...apps.googleusercontent.com",
    "client_secret": "...",
    "refresh_token": "...",
    "type": "authorized_user"
  },
  "type": "impersonated_service_account"
}
Run Code Online (Sandbox Code Playgroud)

我的代码产生未知的凭据类型:“impersonated_service_account”错误:

package main

import (
...
    "cloud.google.com/go/storage"
    "golang.org/x/oauth2"
    "google.golang.org/api/docs/v1"
    "google.golang.org/api/drive/v3"
    "google.golang.org/api/impersonate"
    "google.golang.org/api/option"
...
)

var Config.GoogleServiceAccount string = "sa@example-2021.iam.gserviceaccount.com"




func main(){
  _ = getTokenAsImpersonator()
}

// From: https://pkg.go.dev/google.golang.org/api/impersonate#example-CredentialsTokenSource-ServiceAccount
func getTokenAsImpersonator() oauth2.TokenSource {
    ctx := context.Background()

    // Base credentials sourced from ADC or provided client options.
    ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
        TargetPrincipal: Config.GoogleServiceAccount,
        Scopes:          []string{"https://www.googleapis.com/auth/cloud-platform"},
        // Delegates: []string{"bar@project-id.iam.gserviceaccount.com"},
    })
    if err != nil {
        log.Fatal(err)
    }

    return ts
}
Run Code Online (Sandbox Code Playgroud)

'未知的凭据类型:“impersonated_service_account” '错误:

google: error getting credentials using GOOGLE_APPLICATION_CREDENTIALS environment variable: unknown credential type: "impersonated_service_account"

Run Code Online (Sandbox Code Playgroud)

我做错了什么还是这是一个错误?


更新

回答约翰在评论中提出的问题:

1.

a) 环境变量 GOOGLE_APPLICATION_CREDENTIALS 的值是多少?

GOOGLE_APPLICATION_CREDENTIALS=/Users/x/.config/gcloud/application_default_credentials.json
Run Code Online (Sandbox Code Playgroud)

b) 您使用什么命令生成 application_default_credentials.json?

gcloud auth application-default login --scopes=https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/accounts.reauth,openid --impersonate-service-account=[sa@example-2021.iam.gserviceaccount.com]


Response:

Credentials saved to file: [/Users/x/.config/gcloud/application_default_credentials.json]


Run Code Online (Sandbox Code Playgroud)

c) 哪个操作系统和版本?

MacOS 10.13.6
Run Code Online (Sandbox Code Playgroud)

d)gcloud --版本?

Google Cloud SDK 343.0.0
app-engine-go 
app-engine-python 1.9.91
bq 2.0.69
cloud-datastore-emulator 2.1.0
core 2021.05.27
gsutil 4.62
Run Code Online (Sandbox Code Playgroud)
  1. 如果你可以创建一个最小的例子......

我已经更新了上面的示例代码。

Ari*_*Ari 5

在某些时候,我曾使用 CLI 来模拟一个帐户:

gcloud config set auth/impersonate_service_account <service account>
Run Code Online (Sandbox Code Playgroud)

然后,稍后当尝试使用应用程序默认凭据命令时,它会使用服务帐户凭据包装您的凭据。

gcloud auth application-default login
Run Code Online (Sandbox Code Playgroud)

您最终得到的是一个如下所示的文件:

gcloud config set auth/impersonate_service_account <service account>
Run Code Online (Sandbox Code Playgroud)

这似乎会给 terraform 等第三方服务带来很多问题。

奇怪的是,Terraform 只是使用 Google SDK 向 Google 进行 API 调用,所以它确实与 Google 有关。

您需要删除模拟:

gcloud config unset auth/impersonate_service_account
Run Code Online (Sandbox Code Playgroud)

然后再次运行应用程序默认凭据命令:

gcloud auth application-default login
Run Code Online (Sandbox Code Playgroud)

现在,如果您检查文件,它应该如下所示:

gcloud auth application-default login
Run Code Online (Sandbox Code Playgroud)

当我尝试模拟帐户以便我可以将 Terraform 命令作为服务帐户而不是我的个人帐户运行时,我遇到了同样的问题,但它不喜欢那样。

编辑:重读你的问题,听起来你和我在同一条船上。我们希望在不实际下载密钥的情况下使用服务帐户。谷歌甚至将其称为最佳实践。但这样做会导致他们自己的 SDK 出现问题。