防止 Cloud Run 传递授权头部。

huangapple go评论119阅读模式
英文:

Prevent Cloud Run from passing on Authorization header

问题

我在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))
	}
}
英文:

I have Grafana hosted on Cloud Run. Grafana has anonymous access enabled while Cloud Run needs valid credentials.

Now I try mimic the first example of https://grafana.com/docs/grafana/latest/http_api/dashboard/. Thus I downloaded a service account key to /tmp/creds.json. This file I set as GOOGLE_APPLICATION_CREDENTIALS.
Using these credentials I then send a POST to /api/dashboards/db.
What I see is that I get through Google auth, it starts up Cloud Run instances and I get an error message from Grafana:

{&quot;message&quot;:&quot;invalid API key&quot;}

This in turn then lets me believe that Google auth is not consuming the Authorization header but delegating it along.

So my question is how can I prevent Google auth from delegate this header?
Or as a workaround how can I make Grafana ignore the header?

Here the source I use to make the requests:

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

答案1

得分: 1

头部的Proxy-Authorization应该是有效的,但我也没有成功。

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

在我看来,这是一个应该在Grafana代码中解决的问题。如果Grafana启用了匿名访问,那么它就不应该验证HTTP授权头部。考虑向Grafana提交一个问题报告,或修复代码并提交一个补丁。

英文:

The header Proxy-Authorization should work, but I have also been unsuccessful.

To clarify your problem, you are using IAP (OIDC Identity Token) to authorize access to Cloud Run. Your software (Grafana) is processing the HTTP Authorization header and assuming that you are passing it an API Key (which fails). I am not familiar with Grafana internals, but one possible solution is to write middleware that detects an OIDC token and removes that header. I am not aware of a Cloud Run method to remove the Authorization header from HTTP requests that your application receives.

IMHO this is a problem that should be resolved in Grafana's code. If Grafana has anonymous access enabled, then it should not be validating the HTTP Authorization header. Consider opening an issue with Grafana or fixing the code and submitting a patch.

huangapple
  • 本文由 发表于 2021年11月11日 23:35:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/69930980.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定