【问题标题】:Prevent Cloud Run from passing on Authorization header阻止 Cloud Run 传递 Authorization 标头
【发布时间】:2021-12-24 02:20:06
【问题描述】:

我在 Cloud Run 上托管了 Grafana。 Grafana 已启用匿名访问,而 Cloud Run 需要有效凭据。

现在我试着模仿https://grafana.com/docs/grafana/latest/http_api/dashboard/ 的第一个例子。因此,我将服务帐户密钥下载到/tmp/creds.json。这个文件我设置为GOOGLE_APPLICATION_CREDENTIALS。 然后使用这些凭据向/api/dashboards/db 发送一个POST。 我看到的是我通过了 Google 身份验证,它启动了 Cloud Run 实例,我从 Grafana 收到一条错误消息:

{"message":"invalid API key"}

这反过来又让我相信 Google 身份验证没有使用 Authorization 标头,而是将其委托给它。

所以我的问题是如何防止 Google 身份验证委托此标头? 或者作为一种解决方法,我怎样才能让 Grafana 忽略标题?

这里是我用来提出请求的来源:

func TestCall(t *testing.T) {
    r := strings.NewReader(`
    {
      "dashboard": {
        "id": null,
        "uid": null,
        "title": "Production Overview",
        "tags": [ "templated" ],
        "timezone": "browser",
        "schemaVersion": 16,
        "version": 0,
        "refresh": "25s"
      },
      "folderId": 0,
      "folderUid": "l3KqBxCMz",
      "message": "Made changes to xyz",
      "overwrite": false
    }
    `)
    os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", "/tmp/creds.json")
    ctx := context.TODO()
    ts, err := idtoken.NewTokenSource(ctx, "https://grafana-123.run.app")
    if err != nil {
        if !strings.HasPrefix(err.Error(), "idtoken: credential must be service_account") {
            panic(err)
        }
        creds, err := google.FindDefaultCredentials(ctx)
        if err != nil {
            panic(err)
        }
        ts = creds.TokenSource
    }
    tok, err := ts.Token()
    if err != nil {
        panic(err)
    }
    if tok.AccessToken == "" {
        panic("Empty token!")
    }
    fmt.Printf("AT %s\n", tok.AccessToken)
    client := &http.Client{}
    req, err := http.NewRequest("POST", "https://grafana-123.run.app/api/dashboards/db", r)
    if err != nil {
        panic(err)
    }
    req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
    // This does not work at all: req.Header.Set("Proxy-Authorization", "Bearer "+tok.AccessToken)
    req.Header.Set("Content-Type", "application/json")
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        fmt.Printf("SC %d\n", resp.StatusCode)
        bs, err := io.ReadAll(resp.Body)
        if err != nil {
            panic(err)
        }
        panic(string(bs))
    }
}

【问题讨论】:

  • 我想知道你是否可以在grafana中设置基于oidc的访问,以google作为身份提供者,然后将用户的身份暴露给grafana。 grafana.com/docs/grafana/latest/auth/google
  • 我在 OIDC 和多层身份验证/反向代理/负载均衡器方面的经验是,您需要非常了解每一个部分才能使其正常工作。我不是;)

标签: go google-cloud-run


【解决方案1】:

标头 Proxy-Authorization 应该可以工作,但我也没有成功。

为了澄清您的问题,您正在使用 IAP(OIDC 身份令牌)来授权访问 Cloud Run。您的软件 (Grafana) 正在处理 HTTP Authorization 标头并假设您正在向其传递 API 密钥(失败)。我不熟悉 Grafana 内部结构,但一种可能的解决方案是编写检测 OIDC 令牌并删除该标头的中间件。我不知道有一种 Cloud Run 方法可以从您的应用收到的 HTTP 请求中删除 Authorization 标头。

恕我直言,这是一个应该在 Grafana 的代码中解决的问题。如果 Grafana 启用了匿名访问,那么它不应该验证 HTTP 授权标头。考虑打开 Grafana 问题或修复代码并提交补丁。

【讨论】:

  • 我尽量不要故意使用 IAP(AFAIK 你不能将 ADC 与 IAP 一起使用)。无论谷歌云实例前面有什么网络实例——AFAIK 他们只验证Authorization 标头。
  • @abergmeier - 如果您的意思是应用程序默认凭据中的 ADC,是的,您可以将该方法与 IAP 一起使用。 ADC 不是凭证,ADC 是一种查找凭证的方法。
  • 我的意思是 ADC 是可用的凭据,例如云。而且由于 IAP 似乎迫使您使用自定义 OAuth 客户端 ID,我认为“gcloud adc”不能与 IAP 一起使用,因为范围不同。
  • 是的,您可以使用 CLI (gcloud)。但是,这取决于 CLI 获得授权的身份类型。
猜你喜欢
  • 2019-12-31
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 2016-08-11
  • 2021-02-21
  • 2012-01-17
  • 2021-01-17
相关资源
最近更新 更多