我正试图从Google/Firebase Cloud函数为给定的服务帐户serviceA
生成JWT。服务帐户serviceB
正在运行该功能。
我通过使用JSON中的帐户密钥使其工作。
考虑到CF在Google Cloud中运行,我想利用计算元数据,而不必将私钥与函数一起存储。
当serviceB
执行CF时,我一直在尝试访问serviceA
的元数据服务器。我故意不希望serviceA
运行CF。
代码
const request = require('request-promise');
const serviceAccountEmail = 'serviceA@<projectA>.iam.gserviceaccount.com';
const metadataServerTokenURL = `http://metadata/computeMetadata/v1/instance/service-accounts/${serviceAccountEmail}/identity?audience=<audience>`;
const tokenRequestOptions = {
uri: metadataServerTokenURL,
headers: {
'Metadata-Flavor': 'Google'
}
};
const token = await request(tokenRequestOptions);
错误
我目前收到一个404未找到错误的电子邮件提供
我想这是
a(我想做的不可能,或者
b(我缺少serviceA
的一些IAM权限
您可以使用元数据服务器来执行此操作,因为它们只能为与您的实例一起加载的服务帐户(在本例中为serviceB(生成ID令牌。
您可以为此使用另一个API:服务帐户凭据API,尤其是generateIdToken方法
在你的情况下,你可以做这样的事情(在python中(
import google.auth
from google.auth.transport.requests import AuthorizedSession
import json
# IAP audience is the ClientID of IAP-App-Engine-app in
# the API->credentials page
# Cloud Function and Cloud Run need the base URL of the service
audience = 'YOUR AUDIENCE'
# #1 Get the default credential to generate the access token
credentials, project_id = google.auth.default(
scopes='https://www.googleapis.com/auth/cloud-platform')
# #2 To use the current service account email
service_account_email = credentials.service_account_email
# Don't work with user account, so define manually the email
# service_account_email = 'MY SERVICE ACCOUNT EMAIL'
# #3 prepare the call the the service account credentials API
sa_credentials_url = f'https://iamcredentials.googleapis.com/'
f'v1/projects/-/serviceAccounts/'
f'{service_account_email}:generateIdToken'
headers = {'Content-Type': 'application/json'}
# Create an AuthorizedSession that includes
# automatically the access_token based on your credentials
authed_session = AuthorizedSession(credentials)
# Define the audience in the request body
# add the parameter "'includeEmail':true" for IAP access
body = json.dumps({'audience': audience})
# Make the call
token_response = authed_session.request('POST',sa_credentials_url,
data=body, headers=headers)
jwt = token_response.json()
id_token = jwt['token']
我写了一篇关于这个的文章,这个星期
我采用@guillaume blaquiere的Typescript解决方案:
import { GaxiosOptions, Headers } from 'gaxios';
import { GoogleAuth } from 'google-auth-library';
interface TokenRequestResponse {
token: string
}
const service_account_email = 'MY SERVICE ACCOUNT EMAIL'
const audience: string = 'MY AUDIENCE';
const sa_credentials_url = `https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${service_account_email}:generateIdToken`
const headers: Headers = { 'Content-Type': 'application/json' }
const body = {
'audience': audience
};
const options: GaxiosOptions = {
method: 'POST',
url: sa_credentials_url,
body: JSON.stringify(body),
headers: headers,
};
const auth = new GoogleAuth({
scopes: 'https://www.googleapis.com/auth/cloud-platform'
});
const client = await auth.getClient();
const tokenResponse = await client.request(options);
const tokenRequestResponse = tokenResponse.data as TokenRequestResponse;
const token = tokenRequestResponse.token;