使用 google auth gem 从 ruby 客户端通过 HTTP 访问 Cloud Function
Access Cloud Function via HTTP from ruby client, using google auth gem
我正在尝试使用 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 Functions 的权限。
访问失败,输出如下。
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
正如 John Hanley 提到的,您正在使用访问令牌作为函数的授权,但您需要 Identity Token 才能成功调用该函数。您可以在程序中通过将 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
returns 访问令牌,同时指定 target_audience
将 return ID 令牌。
我正在尝试使用 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 Functions 的权限。
访问失败,输出如下。
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
正如 John Hanley 提到的,您正在使用访问令牌作为函数的授权,但您需要 Identity Token 才能成功调用该函数。您可以在程序中通过将 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
returns 访问令牌,同时指定 target_audience
将 return ID 令牌。