问题描述
我正在尝试构建一小部分 python 以获取有关谷歌云中组织的所有项目的帐单信息。
我按照官方的“操作方法”https://cloud.google.com/billing/docs/reference/libraries
在完成所有步骤后(我检查了两次),我的小程序无法正常工作。 我无法获得任何信息或直接收到 403 错误。
我认为这是“服务帐户”权限的问题,但此“服务帐户”具有所有者权限,如文档所示。
我目前非常迷茫,花了很多时间在互联网上阅读和寻找例子......所以我在这里发帖,寻找可以帮助我或找到正确方向的人。
from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
from urllib.error import HTTPError
import json
ScopES = [
'https://www.googleapis.com/auth/cloud-billing.readonly','https://www.googleapis.com/auth/cloud-billing','https://www.googleapis.com/auth/cloud-platform'
]
JSON_KEY_FILE = '/Users/alek/lab/gcloud-billing/JSON_KEY.json'
def main():
creds = None
if os.path.exists(JSON_KEY_FILE):
creds = ServiceAccountCredentials.from_json_keyfile_name(
JSON_KEY_FILE,scopes=ScopES)
with build('cloudbilling','v1',credentials=creds) as service:
print(service.billingAccounts().list().execute())
request = service.billingAccounts().list()
try:
response = request.execute()
except HTTPError as e:
print('Error response status code : {0},reason : {1}'.format(
e.status_code,e.error_details))
print(json.dumps(response,sort_keys=True,indent=4))
#
# Second test over a kNowing ID
#
request = service.billingAccounts().get(
name="billingAccounts/XXXXXX-YYYYYY-ZZZZZZ")
try:
response = request.execute()
except HTTPError as e:
print('Error response status code : {0},e.error_details))
if __name__ == '__main__':
main()
和输出:
{'billingAccounts': [],'nextPagetoken': ''}
{
"billingAccounts": [],"nextPagetoken": ""
}
Traceback (most recent call last):
File "/Users/alek/lab/gcloud-billing/test01.py",line 73,in <module>
main()
File "/Users/alek/lab/gcloud-billing/test01.py",line 47,in main
response = request.execute()
File "/Users/alek/.pyenv/versions/gcloud-billing/lib/python3.9/site-packages/googleapiclient/_helpers.py",line 134,in positional_wrapper
return wrapped(*args,**kwargs)
File "/Users/alek/.pyenv/versions/gcloud-billing/lib/python3.9/site-packages/googleapiclient/http.py",line 935,in execute
raise HttpError(resp,content,uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 403 when requesting https://cloudbilling.googleapis.com/v1/billingAccounts/XXXXXX-YYYYYY-ZZZZZZ?alt=json returned "The caller does not have permission". Details: "The caller does not have permission">
解决方法
你的代码对我有用,但见下文...
如果您有一个组织(gcloud organizations list
返回一个组织),请参阅评论。
如果不这样做,您需要授予服务帐户权限结算帐户:
PROJECT=... # The Project that owns the Service Account
ACCOUNT=... # The Service Account
EMAIL=${ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
gcloud beta billing accounts add-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}
不要忘记启用cloudbilling
:
gcloud services enable cloudbilling.googleapis.com \
--project=${PROJECT}
那么它应该可以工作了!
{'billingAccounts': [{'name': 'billingAccounts/XXXXXX-XXXXXX-XXXXXX','open': True,'displayName': 'personal','masterBillingAccount': ''}],'nextPageToken': ''}
{
"billingAccounts": [
{
"displayName": "billing-account","masterBillingAccount": "","name": "billingAccounts/XXXXXX-XXXXXX-XXXXXX","open": true
}
],"nextPageToken": ""
}
建议:使用Application Default Credentials
你export GOOGLE_APPLICATION_CREDENTIALS=./${ACCOUNT}.json
然后可以:
from googleapiclient.discovery import build
import google.auth
def main():
creds,project_id = google.auth.default(scopes=SCOPES)
...
从头开始:
BILLING=...
PROJECT=...
ACCOUNT=...
EMAIL=${ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
gcloud projects create ${PROJECT}
gcloud beta billing projects link ${PROJECT} \
--billing-account=${BILLING}
gcloud services enable cloudbilling.googleapis.com \
--project=${PROJECT}
gcloud iam service-accounts create ${ACCOUNT} \
--project=${PROJECT}
gcloud iam service-accounts keys create ./${ACCOUNT}.json \
--iam-account=${EMAIL} \
--project=${PROJECT}
gcloud beta billing accounts add-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}
python3 -m venv venv
source venv/bin/activate
python3 -m pip install google-api-python-client
python3 -m pip install google-auth
export PROJECT
export BILLING
export GOOGLE_APPLICATION_CREDENTIALS=./${ACCOUNT}.json
python3 main.py
完成后,删除权限:
gcloud beta billing accounts remove-iam-policy-binding ${BILLING} \
--role=roles/billing.viewer \
--member=serviceAccount:${EMAIL}
注意您使用的是 Google 的 Billing API 客户端库,但还有一个 Billing 的云客户端库。 Google Cloud 鼓励 Cloud Client over API Client,只需注意 differences。