0

我正在尝试使用 ruby​​ googleauth gem 来验证服务帐户以对 Cloud Function 进行 HTTP 调用,但没有成功。

测试代码:

require 'googleauth'

class TestService
  include HTTParty
  format :json
  debug_output $stdout

  def test
    authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
      json_key_io: File.open(ENV['GOOGLE_APPLICATION_CREDENTIALS']),
      scope: 'https://www.googleapis.com/auth/cloud-platform')
    options =
      {
        headers:
          {
            accept: 'application/json',
            authorization: "Bearer #{authorizer.fetch_access_token!['access_token']}"
          },
        query:
          {
            foo: 'bar'
          }
      }

    self.class.get('https://us-east1-xx-beta.cloudfunctions.net/my-cloud-function', options)
  end
end

TestService.new.test

(我想知道是否应该指定audience而不是scope,但我一直无法做到这一点。)

我将 GOOGLE_APPLICATION_CREDENTIALS env var 设置为有效 GCP 服务帐户密钥文件的路径,并确保相关服务帐户列在具有Cloud Functions Invoker 角色的此 Cloud Function 的权限中。

访问失败,输出如下。

opening connection to us-east1-xx-beta.cloudfunctions.net:443...
opened
starting SSL for us-east1-xx-beta.cloudfunctions.net:443...
SSL established, protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384
<- "GET /my-cloud-function?foo=bar HTTP/1.1\r\nAccept: application/json\r\nAuthorization: Bearer ya29.c.Kp8B-QfKOgrA5jwGxc3tK8MkX2RJqe0LcQqKtjo1hMDJawXJZWTOq3nZyOHkfHZMJpm5hbFr11T7LFTzbP4bnxX1SIUXJt-papBSKYU0lOKXXiqdwa9s5yN-oHD45qSp6bSOIMwzhG9GJC8ZqeOrbyJAhd5oqmZUgqDg_2cgGusA5wVViaJZtiBFC_TaMmBK06MUmGT2a1q4UGLIyH4nyug1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nUser-Agent: Ruby\r\nConnection: close\r\nHost: us-east1-xx-beta.cloudfunctions.net\r\n\r\n"
-> "HTTP/1.1 401 Unauthorized\r\n"
-> "WWW-Authenticate: Bearer error=\"invalid_token\" error_description=\"The access token could not be verified\"\r\n"
-> "Date: Mon, 29 Mar 2021 19:42:21 GMT\r\n"
-> "Content-Type: text/html; charset=UTF-8\r\n"
-> "Server: Google Frontend\r\n"
-> "Content-Length: 315\r\n"
-> "Alt-Svc: h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"\r\n"
-> "Connection: close\r\n"
-> "\r\n"
reading 315 bytes...
-> "\n<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<title>401 Unauthorized</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Unauthorized</h1>\n<h2>Your client does not have permission to the requested URL <code>/my-cloud-function?foo=bar</code>.</h2>\n<h2></h2>\n</body></html>\n"
read 315 bytes
Conn close
4

1 回答 1

2

正如 John Hanley 所提到的,您正在使用访问令牌作为函数的授权,但您需要一个身份令牌才能成功调用该函数。你可以在你的程序中通过改变来做到这scope一点target_audience

authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open(ENV['GOOGLE_APPLICATION_CREDENTIALS']),
  target_audience: "GCF-TRIGGER-URL")

然后使用以下命令获取 ID 令牌:

authorizer.fetch_access_token!["id_token"]

(查看源代码)中有一条线索make_creds(),指定范围和 target_audience 会引发 ArgumentError。测试库将显示指定scope返回访问令牌,而指定target_audience将返回 ID 令牌。

于 2021-03-30T03:36:05.687 回答