mirror of
https://github.com/hanzo-ml/kserve.git
synced 2026-10-30 20:53:49 +00:00
* Fix python linter Signed-off-by: Sivanantham Chinnaiyan <[email protected]> * Format e2e tests Signed-off-by: Sivanantham Chinnaiyan <[email protected]> * Format hack, docs Signed-off-by: Sivanantham Chinnaiyan <[email protected]> * Add py-fmt target Signed-off-by: Sivanantham Chinnaiyan <[email protected]> * Update python lint workflow Signed-off-by: Sivanantham Chinnaiyan <[email protected]> * Rebase master Signed-off-by: Sivanantham Chinnaiyan <[email protected]> --------- Signed-off-by: Sivanantham Chinnaiyan <[email protected]>
167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Reference:
|
|
# https://cloud.google.com/iap/docs/authentication-howto#iap-make-request-python
|
|
# https://github.com/kubeflow/pipelines/blob/85cb99173dead8bd2ca09c8e040b137f59d00ad7/sdk/python/kfp/_auth.py#L183
|
|
# This is a helper function to make KFserving inferenceService
|
|
# call to a GCP cluster with IAP enabled.
|
|
# The id token is retrieved using `authenticate from desktop app` approach.
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
|
|
# from google.auth.transport.requests import Request
|
|
from webbrowser import open_new_tab
|
|
|
|
import requests
|
|
|
|
IAM_SCOPE = "https://www.googleapis.com/auth/iam"
|
|
# OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'
|
|
OAUTH_TOKEN_URI = "https://oauth2.googleapis.com/token"
|
|
|
|
try:
|
|
import http.client as http_client
|
|
except ImportError:
|
|
# Python 2
|
|
import httplib as http_client
|
|
http_client.HTTPConnection.debuglevel = 1
|
|
|
|
# You must initialize logging, otherwise you'll not see debug output.
|
|
logging.basicConfig()
|
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
requests_log = logging.getLogger("requests.packages.urllib3")
|
|
requests_log.setLevel(logging.DEBUG)
|
|
requests_log.propagate = True
|
|
|
|
|
|
def getToken(iap_client_id, desktop_client_id, desktop_client_secret):
|
|
token = None
|
|
if desktop_client_id is None or desktop_client_secret is None:
|
|
raise ValueError("desktop client id or secret is empty")
|
|
else:
|
|
# fetch IAP auth token: user account
|
|
# Obtain the ID token for provided Client ID with user accounts.
|
|
# Flow: get authorization code ->
|
|
# exchange for refresh token ->
|
|
# obtain and return ID token
|
|
refresh_token = getRefreshTokenFromClientId(
|
|
desktop_client_id, desktop_client_secret
|
|
)
|
|
|
|
token = idTokenFromRefreshToken(
|
|
desktop_client_id, desktop_client_secret, refresh_token, iap_client_id
|
|
)
|
|
return token
|
|
|
|
|
|
def getRefreshTokenFromClientId(desktop_client_id, desktop_client_secret):
|
|
auth_code = getAuthCode(desktop_client_id)
|
|
auth_code = auth_code.strip()
|
|
return getRefreshTokenFromCode(auth_code, desktop_client_id, desktop_client_secret)
|
|
|
|
|
|
def getAuthCode(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
|
|
print(auth_url)
|
|
open_new_tab(auth_url)
|
|
return input(
|
|
"If there's no browser window prompt,"
|
|
+ " please direct to the URL above,"
|
|
+ "then copy and paste the authorization code here: "
|
|
)
|
|
|
|
|
|
def getRefreshTokenFromCode(auth_code, client_id, client_secret):
|
|
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",
|
|
}
|
|
# req = requests.Request('POST',OAUTH_TOKEN_URI,data=payload)
|
|
|
|
res = requests.post(OAUTH_TOKEN_URI, data=payload)
|
|
print(res.text)
|
|
return str(json.loads(res.text)["refresh_token"])
|
|
|
|
|
|
def idTokenFromRefreshToken(client_id, client_secret, refresh_token, audience):
|
|
payload = {
|
|
"client_id": client_id,
|
|
"client_secret": client_secret,
|
|
"refresh_token": refresh_token,
|
|
"grant_type": "refresh_token",
|
|
"audience": audience,
|
|
}
|
|
res = requests.post(OAUTH_TOKEN_URI, data=payload)
|
|
return str(json.loads(res.text)["id_token"])
|
|
|
|
|
|
def makeRequest(url, input_file, user_account, id_token):
|
|
if input_file:
|
|
with open(input_file) as f:
|
|
data = f.read()
|
|
resp = requests.post(
|
|
url,
|
|
verify=False,
|
|
data=data,
|
|
headers={
|
|
"Authorization": "Bearer {}".format(id_token),
|
|
"x-goog-authenticated-user-email": "accounts.google.com:{}".format(
|
|
user_account
|
|
),
|
|
},
|
|
)
|
|
else:
|
|
resp = requests.get(
|
|
url, verify=False, headers={"Authorization": "Bearer {}".format(id_token)}
|
|
)
|
|
if resp.status_code == 403:
|
|
raise Exception(
|
|
"Service account {} does not have permission to "
|
|
"access the IAP-protected application.".format("var signer_email")
|
|
)
|
|
elif resp.status_code != 200:
|
|
raise Exception(
|
|
"Bad response from application: {!r} / {!r} / {!r}".format(
|
|
resp.status_code, resp.headers, resp.text
|
|
)
|
|
)
|
|
else:
|
|
print(resp.text)
|
|
|
|
|
|
def main():
|
|
# TODO: Use pythonfire to parse arguments.
|
|
# fire.Fire()
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--url", help="External URL of service endpoint")
|
|
parser.add_argument("--iap_client_id", help="The client id used to setup IAP")
|
|
parser.add_argument(
|
|
"--desktop_client_id", help="The client id for Desktop OAuth client"
|
|
)
|
|
parser.add_argument(
|
|
"--desktop_client_secret", help="The client secret for Desktop OAuth client"
|
|
)
|
|
parser.add_argument(
|
|
"--user_account",
|
|
help="The user email address " + "which can access the namespace",
|
|
)
|
|
parser.add_argument("--input", help="The input file.")
|
|
args = parser.parse_args()
|
|
|
|
id_token = getToken(
|
|
args.iap_client_id, args.desktop_client_id, args.desktop_client_secret
|
|
)
|
|
makeRequest(args.url, args.input, args.user_account, id_token)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|