对受 IAP 保护的应用程序的服务帐户请求结果 'Invalid GCIP ID token: JWT signature is invalid'
Service account request to IAP-protected app results in 'Invalid GCIP ID token: JWT signature is invalid'
我正在尝试通过 Python 从 GCP 环境外部以编程方式访问受 IAP 保护的 App Engine 标准应用程序。
我尝试了各种方法,包括此处文档中显示的方法:https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python。这是我的代码:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
print(f'{open_id_connect_token=}')
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
print(f'{resp=}')
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
if __name__ == '__main__':
res = make_iap_request(
'https://MYAPP.ue.r.appspot.com/',
'Client ID from IAP>App Engine app>Edit OAuth Client>Client ID'
)
print(res)
当我在本地 运行 时,我将 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为本地 JSON 凭证文件,其中包含我要使用的服务帐户的密钥。我也在 Cloud Functions 中尝试了 运行ning 这个,所以它可能会使用元数据服务来获取 App Engine 默认服务帐户(我认为?)。
在这两种情况下,我都能生成一个看起来有效的令牌。使用 jwt.io,我看到它包含预期的数据并且签名有效。但是,当我使用令牌向应用程序发出请求时,我总是会收到此异常:
Bad response from application: 401 / {'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Tue, 09 Feb 2021 19:25:43 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '47', '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"'} / 'Invalid GCIP ID token: JWT signature is invalid'
我可能做错了什么?
此问题的解决方案是将 Google 身份令牌交换为身份平台身份令牌。
错误 Invalid GCIP ID token: JWT signature is invalid
的原因是使用 Google 身份令牌引起的,该令牌由 Google RSA 私钥而非 Google 身份签名平台 RSA 私钥。我忽略了错误消息中的 GCIP
,一旦我们验证令牌在使用中未损坏,它就会告诉我解决方案。
在问题中,这行代码获取 Google Identity Token:
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
以上代码行要求设置 Google 云应用程序默认凭据。示例:set GOOGLE_APPLICATION_CREDENTIALS=c:\config\service-account.json
下一步是将此令牌交换为 Identity Platform 令牌:
def exchange_google_id_token_for_gcip_id_token(google_open_id_connect_token):
SIGN_IN_WITH_IDP_API = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp'
API_KEY = '';
url = SIGN_IN_WITH_IDP_API + '?key=' + API_KEY;
data={
'requestUri': 'http://localhost',
'returnSecureToken': True,
'postBody':'id_token=' + google_open_id_connect_token + '&providerId=google.com'}
try:
resp = requests.post(url, data)
res = resp.json()
if 'error' in res:
print("Error: {}".format(res['error']['message']))
exit(1)
# print(res)
return res['idToken']
except Exception as ex:
print("Exception: {}".format(ex))
exit(1)
API 密钥可以在 Google Cloud Console -> Identity Platform 中找到。右上角的“应用程序设置详细信息”。这将显示 apiKey
和 authDomain
.
可在此处找到更多信息 link:
我正在尝试通过 Python 从 GCP 环境外部以编程方式访问受 IAP 保护的 App Engine 标准应用程序。 我尝试了各种方法,包括此处文档中显示的方法:https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python。这是我的代码:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
print(f'{open_id_connect_token=}')
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
print(f'{resp=}')
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
if __name__ == '__main__':
res = make_iap_request(
'https://MYAPP.ue.r.appspot.com/',
'Client ID from IAP>App Engine app>Edit OAuth Client>Client ID'
)
print(res)
当我在本地 运行 时,我将 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为本地 JSON 凭证文件,其中包含我要使用的服务帐户的密钥。我也在 Cloud Functions 中尝试了 运行ning 这个,所以它可能会使用元数据服务来获取 App Engine 默认服务帐户(我认为?)。
在这两种情况下,我都能生成一个看起来有效的令牌。使用 jwt.io,我看到它包含预期的数据并且签名有效。但是,当我使用令牌向应用程序发出请求时,我总是会收到此异常:
Bad response from application: 401 / {'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Tue, 09 Feb 2021 19:25:43 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '47', '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"'} / 'Invalid GCIP ID token: JWT signature is invalid'
我可能做错了什么?
此问题的解决方案是将 Google 身份令牌交换为身份平台身份令牌。
错误 Invalid GCIP ID token: JWT signature is invalid
的原因是使用 Google 身份令牌引起的,该令牌由 Google RSA 私钥而非 Google 身份签名平台 RSA 私钥。我忽略了错误消息中的 GCIP
,一旦我们验证令牌在使用中未损坏,它就会告诉我解决方案。
在问题中,这行代码获取 Google Identity Token:
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
以上代码行要求设置 Google 云应用程序默认凭据。示例:set GOOGLE_APPLICATION_CREDENTIALS=c:\config\service-account.json
下一步是将此令牌交换为 Identity Platform 令牌:
def exchange_google_id_token_for_gcip_id_token(google_open_id_connect_token):
SIGN_IN_WITH_IDP_API = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp'
API_KEY = '';
url = SIGN_IN_WITH_IDP_API + '?key=' + API_KEY;
data={
'requestUri': 'http://localhost',
'returnSecureToken': True,
'postBody':'id_token=' + google_open_id_connect_token + '&providerId=google.com'}
try:
resp = requests.post(url, data)
res = resp.json()
if 'error' in res:
print("Error: {}".format(res['error']['message']))
exit(1)
# print(res)
return res['idToken']
except Exception as ex:
print("Exception: {}".format(ex))
exit(1)
API 密钥可以在 Google Cloud Console -> Identity Platform 中找到。右上角的“应用程序设置详细信息”。这将显示 apiKey
和 authDomain
.
可在此处找到更多信息 link: