使用 python 对 GCP 计算 API 端点进行身份验证
Posted
技术标签:
【中文标题】使用 python 对 GCP 计算 API 端点进行身份验证【英文标题】:using python to authenticate to GCP compute API endpoint 【发布时间】:2019-11-10 12:11:15 【问题描述】:我的目标是在不依赖 gcloud 二进制文件的情况下重现/复制 gcloud compute addresses create
的功能。
我正在尝试根据https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address 上关于保留静态外部 IP 地址的文档,使用 python 对 googleapis 计算端点的 POST 进行身份验证
但我的 POST 每次都返回 401。
我从 google.auth.jwt python 模块创建了一个 JWT,当我对其进行解码时,JWT 嵌入了我希望存在的所有字符串。
我还尝试了将以下 OAuth 范围组合到 JWT 中: - “https://www.googleapis.com/auth/userinfo.email” - “https://www.googleapis.com/auth/compute” - “https://www.googleapis.com/auth/cloud-platform”
这是我使用服务帐户的 JSON 密钥文件中的信息获取 JWT 的函数
def _generate_jwt( tokenPath, expiry_length=3600 ):
now = int(time.time())
tokenData = load_json_data( tokenPath )
sa_email = tokenData['client_email']
payload =
'iat': now,
# expires after 'expiry_length' seconds.
"exp": now + expiry_length,
'iss': sa_email,
"scope": " ".join( [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/userinfo.email"
] ),
'aud': "https://www.googleapis.com/oauth2/v4/token",
'email': sa_email
# sign with keyfile
signer = google.auth.crypt.RSASigner.from_service_account_file( tokenPath )
jwt = google.auth.jwt.encode(signer, payload)
return jwt
一旦我有了 JWT,我就会发布以下失败的帖子,401,::
gapiURL = 'https://www.googleapis.com/compute/v1/projects/' + projectID + '/regions/' + region + '/addresses'
jwtToken = _generate_jwt( servicetoken )
headers =
'Authorization': 'Bearer '.format( jwtToken ),
'content-type' : 'application/json',
post = requests.post( url=gapiURL, headers=headers, data=data )
post.raise_for_status()
return post.text
无论我在 JWT 中使用了多少范围组合或向我的服务帐户提供了多少权限,我都收到了 401。我做错了什么?
编辑:非常感谢 @JohnHanley 指出我在 GCP 的身份验证序列中缺少到 https://www.googleapis.com/oauth2/v4/token URL 的下一个/第二个 POST。因此,您可以通过 JWT 获取“访问令牌”。
我已将调用更改为使用 python jwt 模块,而不是 google.auth.jwt 模块与 google.auth.crypt.RSASigner 的组合。所以代码比较简单,我把它放在一个方法中
## serviceAccount auth sequence for google :: JWT -> accessToken
def gke_get_token( serviceKeyDict, expiry_seconds=3600 ):
epoch_time = int(time.time())
# Generate a claim from the service account file.
claim =
"iss": serviceKeyDict["client_email"],
"scope": " ".join([
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email"
]),
"aud": "https://www.googleapis.com/oauth2/v4/token",
"exp": epoch_time + expiry_seconds,
"iat": epoch_time
# Sign claim with JWT.
assertion = jwt.encode( claim, serviceKeyDict["private_key"], algorithm='RS256' ).decode()
data = urllib.urlencode(
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": assertion
)
# Request the access token.
result = requests.post(
url="https://www.googleapis.com/oauth2/v4/token",
headers=
"Content-Type": "application/x-www-form-urlencoded"
,
data=data
)
result.raise_for_status()
return loadJsonData(result.text)["access_token"]
【问题讨论】:
您尚未创建访问令牌,您已创建签名 JWT。您需要用签名的 JWT 交换访问令牌。我写了一篇关于如何在 Python 中做到这一点的文章。 jhanley.com/… @JohnHanley - 谢谢你的澄清。我通读了您的文章,并且成功地为我的服务帐户获取了身份验证令牌。请将您的评论更改为答案,以便我可以选择它,因为它是正确的解决方案,我希望您为此获得荣誉。稍后,我将根据阅读您的文章所做的更改来编辑我的问题。 已发布答案。谢谢。 【参考方案1】:在 Google Cloud 中,授予访问权限的“令牌”分为三种类型:
签名的 JWT 访问令牌 身份令牌在您的情况下,您创建了一个签名的 JWT。一些 Google 服务接受此令牌。大多数没有。
创建签名 JWT 后,下一步就是调用 Google OAuth 端点并交换访问令牌。我写了一篇文章详细描述了这一点:
Google Cloud – Creating OAuth Access Tokens for REST API Calls
一些 Google 服务现在接受身份令牌。这称为基于身份的访问控制 (IBAC)。这不适用于您的问题,但它是 Google Cloud Authorization 未来的趋势。一个例子是我关于 Cloud Run + Cloud Storage + KMS 的文章:
Google Cloud – Go – Identity Based Access Control
以下 Python 代码示例展示了如何交换令牌:
def exchangeJwtForAccessToken(signed_jwt):
'''
This function takes a Signed JWT and exchanges it for a Google OAuth Access Token
'''
auth_url = "https://www.googleapis.com/oauth2/v4/token"
params =
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": signed_jwt
r = requests.post(auth_url, data=params)
if r.ok:
return(r.json()['access_token'], '')
return None, r.text
【讨论】:
以上是关于使用 python 对 GCP 计算 API 端点进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章
使用 python api 从 GCP 管理 Kubernetes 集群
使用 GCP API 网关的 Graphql 后端的 OpenAPI 配置?