【问题标题】:Unable to access secret from Secrets Manager无法从 Secrets Manager 访问密钥
【发布时间】:2022-01-17 18:29:59
【问题描述】:

我已向 Secret Manager 添加了一些秘密,但尝试在运行时访问它们时出现以下错误:

rpc error: code = Unauthenticated desc = transport: compute: Received 500 `Could not fetch URI /computeMetadata/v1/instance/service-accounts/default/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform

这是我重新设置的旧应用程序,所以我一定错过了权限中的某些内容。我正在通过带有项目 ID 和密钥名称的完整路径访问密钥。

我运行了gcloud app describe 并验证了那里列出的serviceAccount 具有Owner 角色。我还将Owner 添加到App 引擎默认服务帐户中。我也尝试了特定的 Secret Manager Accessor 角色。

更新: 该服务与 docs 中的 golang 示例匹配以访问密钥。它使用标准的谷歌库来创建客户端和请求。我没有明确配置身份验证,因此应用程序应该使用here 所述的服务帐户。

秘密的路径看起来有效:

projects/<my-project-id>/secrets/MY_SECRET/versions/latest

错误消息表明它缺少云平台范围,但我没有看到任何具体配置,因为它是 Google App Engine。

更新 2: 我推了一个repo 来重新创建这个。它使用来自 google 的示例代码来访问一个秘密,并因与云平台范围相同的错误而失败。

【问题讨论】:

  • 根据official documentation访问密钥版本需要您的应用程序的 App Engine 服务帐户的 Secret Manager Secret Accessor 角色 (roles/secretmanager.secretAccessor)。另外,您能否展示一个您用于访问 Secret Manager 以拥有 minimal code that reproduces the problem 的代码示例?
  • Owner 角色包括所有权限,包括 secretAccessor。该代码与 google 示例匹配,并且自从它在旧项目下工作以来没有改变。我需要启动一个新的测试项目,它只读取一个秘密。它必须是环保的。
  • 你有没有机会测试一个全新的项目?从我对你的回购所做的测试来看,对我来说效果很好。因此,我同意你的观点,它可能是环境问题。
  • @RogelioMonter 感谢您试用我的仓库。我启动了一个新项目并在此处共享之前使用该存储库进行了测试。它失败的方式与我在同一帐户下的现有项目失败的方式相同。我没有尝试在新帐户下创建新项目。这是目前这些测试中唯一不同的地方。

标签: go google-app-engine google-secret-manager


【解决方案1】:

为了解决您的应用问题,我建议您执行以下操作:

为确保您部署到 App Engine 的代码使用所需的帐户运行,我建议 Passing credentials using code在代码中明确指向您的服务帐户文件

./project-folder
├── test.go
├── service-account-credentials.json
├── ...

使用新的项目文件夹,create a service account key 并保存在该文件夹中。

使用以下代码测试您的服务帐户是否具有适当的权限,以放弃问题是 App Engine 未使用正确的帐户。您可以检查您的 App Engine 日志以防出现问题。

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "os"

    secretmanager "cloud.google.com/go/secretmanager/apiv1"
    "google.golang.org/api/option"
    secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
    "google.golang.org/grpc/status"
)

// Your Project ID
const projectId = "project-id"
// Name of your secret
const secret = "secret"

func main() {
    // Path to your secret
    // The version can be a version number as a string (e.g. "5") or an
    // alias (e.g. "latest").
    name := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", projectId, secret)
    
    ctx := context.Background()
    
    // Explicitly reads credentials from the specified path.
    // Create the client.
        client, err := secretmanager.NewClient(ctx,
        option.WithCredentialsFile("service-account-key.json"))
    if err != nil {
        log.Fatal("Failed to create secretmanager client\n")
        if s, ok := status.FromError(err); ok {
            log.Println(s.Message())
            for _, d := range s.Proto().Details {
                log.Println(d)
            }
        }
    }
    defer client.Close()

    // Build the request.
    req := &secretmanagerpb.AccessSecretVersionRequest{
        Name: name,
    }
    
    // accessSecretVersion accesses the payload for the given secret version if one exists.
    // Call the API.
    result, err := client.AccessSecretVersion(ctx, req)
    if err != nil {
        log.Fatal("Failed to access secret version\n")
        if s, ok := status.FromError(err); ok {
            log.Println(s.Message())
            for _, d := range s.Proto().Details {
                log.Println(d)
            }
        }
    }



    // WARNING: Do not print the secret in a production environment - this snippet
    // is showing how to access the secret material.
    log.Printf("Plaintext: %s\n", string(result.Payload.Data))

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, `<h1>For testing purposes only.</h1>
        <h2>Do not use in production enviroments</h2>
        <p>Your secret is shown on Logs.<p>`)
    })

    port := os.Getenv("PORT")

    fmt.Printf("Starting server at port %s\n", port)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal(err)
    }
}   

如上所述,您的服务帐户必须使用授予 Secret Manager 权限的 Owner 角色才能访问 Secret Manager 中的密钥。

另见

【讨论】:

  • 查看我的更新,我注意到我没有在应用程序中配置服务凭据。该应用程序使用上面链接的服务帐户身份。您上面的示例依赖于在文件中配置的服务凭据。
猜你喜欢
  • 2020-10-26
  • 2020-11-27
  • 2019-02-15
  • 2021-06-12
  • 2021-10-29
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 2020-09-29
相关资源
最近更新 更多