如何使用用户默认凭据以编程方式对受Cloud Identity-Aware代理(Cloud IAP)保护的资源进行身份验证?

Bap*_*les 3 python google-cloud-platform google-cloud-python google-iap

我希望能够使用开发环境上的用户默认凭据以编程方式为Iap生成一个ID令牌(即,我自己的装有Google Cloud SDK并登录的笔记本电脑)。

遵循文档时,我设法使用服务帐户文件生成了授权令牌。

google.auth.default个人计算机上使用时,我可以看到type的凭据google.oauth2.credentials.Credentials带有refresh_token。我想用它,因为它是在做卷曲生成令牌文档Authenticating from a desktop app -> Accessing the application,但我不能使它工作。有人知道是否可以通过这种方式进行身份验证吗?

Nik*_*aev 5

如Matthew所述,用于获取刷新令牌的Client ID项目应与IAP Client ID项目匹配。Gcloud使用客户端ID和中定义的密码path_to/google-cloud-sdk/lib/googlecloudsdk/api_lib/auth/util.py作为默认凭据(DEFAULT_CREDENTIALS_DEFAULT_CLIENT_IDDEFAULT_CREDENTIALS_DEFAULT_CLIENT_SECRET)。正因为如此,你不能使用刷新令牌从google.auth.default()没有util.py改变,作为一种尝试,以获得ID令牌将失败:

{
 "error": "invalid_audience",
 "error_description": "The audience client and the client need to be in the same project."
}
Run Code Online (Sandbox Code Playgroud)

您的选择是:

  1. 根据Matthew的回复/文档获取刷新令牌(将其缓存以避免每次都需要用户授予权限)和ID令牌。
  2. 修补程序客户端ID和gcloud util.py中存在的密码(可能会随gcloud更新而更改)。

这两个选项的示例代码:

import google.auth
import requests
import json

from webbrowser import open_new_tab
from time import sleep

# use gcloud app default credentials if gcloud's util.py is patched
def id_token_from_default_creds(audience): 
    cred, proj = google.auth.default()
    # data necessary for ID token
    client_id = cred.client_id
    client_secret= cred.client_secret
    refresh_token = str(cred.refresh_token)
    return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)

def id_token_from_refresh_token(client_id, client_secret, refresh_token, audience):
    oauth_token_base_URL = "https://www.googleapis.com/oauth2/v4/token"
    payload = {"client_id": client_id, "client_secret": client_secret,
                "refresh_token": refresh_token, "grant_type": "refresh_token",
                "audience": audience}
    res = requests.post(oauth_token_base_URL, data=payload)
    return (str(json.loads(res.text)[u"id_token"]))

# obtain ID token for provided Client ID: get authorization code -> exchange for refresh token -> obtain and return ID token
def id_token_from_client_id(client_id, client_secret, audience):
    auth_code = get_auth_code(client_id)
    refresh_token = get_refresh_token_from_code(auth_code, client_id, client_secret)
    return id_token_from_refresh_token(client_id, client_secret, refresh_token, audience)

def get_auth_code(client_id):
    auth_url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=openid%%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob"%client_id
    open_new_tab(auth_url)
    sleep(1)
    return raw_input("Authorization code: ")

def get_refresh_token_from_code(auth_code, client_id, client_secret):
    oauth_token_base_URL = 'https://www.googleapis.com/oauth2/v4/token'
    payload = {"code": auth_code, "client_id": client_id, "client_secret": client_secret,
                "redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "grant_type": "authorization_code"}
    res = requests.post(oauth_token_base_URL, data=payload)
    return (str(json.loads(res.text)[u"refresh_token"]))

print("ID token from client ID: %s" % id_token_from_client_id("<Other client ID>", "<Other client secret>", "<IAP Client ID>")) # other client ID should be from the same project as IAP Client ID 
print("ID token from \"default\" credentials: %s" % id_token_from_default_creds("<IAP Client ID>"))
Run Code Online (Sandbox Code Playgroud)


Mat*_*chs 3

感谢您指出了这一点!如果我们有这方面的代码示例,我会很高兴,但正如您所发现的,至少对于 Python,我们用于服务帐户身份验证的代码示例不适用于用户帐户。

我对我们的 Python 客户端库不够熟悉,无法告诉您它们是否可以帮助您解决这些问题,但https://cloud.google.com/iap/docs/authentication-howto#authentication_from_a_desktop_app的要点是指导您完成的是:

  1. 为您的客户端应用程序创建一个新的客户端 ID(与受 IAP 保护的应用程序位于同一项目中),并使用该客户端 ID 获取刷新令牌。您不能只使用应用程序默认凭据中的刷新令牌,因为这将具有错误的客户端 ID 和可能的范围。相反,您需要向应用程序添加“gcloud auth login”等功能并保留刷新令牌。

  2. 拥有刷新令牌后,当您的客户端应用程序想要访问 IAP 应用程序时:使用应用程序的 OAuth 客户端的客户端 ID 和密钥、刷新令牌POST 到https://www.googleapis.com/oauth2/v4/token,以及 IAP 客户端 ID。这将返回一个 OpenID Connect 令牌,该令牌对 IAP 进行身份验证的有效期为一小时。

这至少足以开始吗?