[英]How to authenticate Google APIs (Google Drive API) from Google Compute Engine and locally without downloading Service Account credentials?
[英]How to create Google Compute Engine instance with particular service account setup on it?
當您在Google Compute Engine中創建實例A時,該實例將獲得預定義的“默認”服務帳戶(這基本上意味着您可以從A查詢google API,並通過“默認”服務帳戶進行身份驗證)。 我想做的是使用服務帳戶設置GCE實例,這與默認帳戶不同。 在給定GCE API的情況下,這在概念上應該是可能的,但會失敗,但出現以下異常:
{
"name": "operation-1400060483459-4f958fbc7d7b9-cd817778-b80d1cad",
"operationType": "insert",
"status": "DONE",
"user": "some_name@developer.gserviceaccount.com",
"error": {
"errors": [ {
"code": "SERVICE_ACCOUNT_ACCESS_DENIED",
"message": "The user does not have access to service account 'some_name@developer.gserviceaccount.com'"
} ] } }
這是我在python中設置實例的代碼:
discovery_service = discovery.build('compute',
config['compute_api_version'],
http=SignedJwtAssertionCredentials(
service_account_name="some_name@developer.gserviceaccount.com",
private_key=key_data,
scope='https://www.googleapis.com/auth/compute')
.authorize(httplib2.Http()))
instance = {}
# sets instance configuration details here
# ...
# ...
instance['serviceAccounts'] = [{
'email': "some_name@developer.gserviceaccount.com",
'scopes': ['https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/compute',
'https://www.googleapis.com/auth/userinfo.email', ]
}]
discovery_service.instances().insert(project=project, zone=zone, body=instance)
它最奇怪的部分是,異常顯示“用戶無權訪問服務帳戶'some_name@developer.gserviceaccount.com'”,但它所指的“用戶”是“ some_name@developer.gserviceaccount.com”本身! 這意味着“ some_name@developer.gserviceaccount.com”無權訪問“ some_name@developer.gserviceaccount.com”,這沒有任何意義。
我相信您需要創建一個新的服務帳戶才能使用非GCE實例中的API。 您引用的服務帳戶僅在GCE實例中有效。
另外,您還需要從啟動盤創建實例,該啟動盤通常是由GCE提供的映像之一創建的。
這是一個對我有用的使用JSON Web令牌的示例。 它是根據位於以下位置的文檔改編而成的: https : //cloud.google.com/compute/docs/tutorials/python-guide#addinganinstance 。
from apiclient import discovery
from oauth2client.file import Storage
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
import os.path
INSTANCE_NAME = 'my-instance'
API_VERSION = 'v1'
GCE_URL = 'https://www.googleapis.com/compute/%s/projects/' % (API_VERSION)
PROJECT_ID = '***'
SERVICE_ACOUNT_CLIENT_ID = '***.apps.googleusercontent.com'
SERVICE_ACCOUNT_EMAIL_ADDRESS = '***@developer.gserviceaccount.com'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'
ZONE = 'us-central1-a'
DEFAULT_SERVICE_EMAIL = 'default'
DEFAULT_SCOPES = ['https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/compute']
SOURCE_IMAGE_URL = 'projects/ubuntu-os-cloud/global/images/ubuntu-1410-utopic-v20141217'
def main():
f = file('private-key.p12', 'rb')
oauth_key_data = f.read()
f.close()
http = httplib2.Http()
oauth_storage = Storage('compute-creds.dat')
oauth_credentials = oauth_storage.get()
if oauth_credentials is None or oauth_credentials.invalid:
oauth_credentials = SignedJwtAssertionCredentials(
service_account_name=SERVICE_ACCOUNT_EMAIL_ADDRESS,
private_key=oauth_key_data,
scope=GCE_SCOPE)
oauth_storage.put(oauth_credentials)
else:
oauth_credentials.refresh(http)
http = oauth_credentials.authorize(http)
gce_service = discovery.build('compute', 'v1', http=http)
project_url = '%s%s' % (GCE_URL, PROJECT_ID)
image_url = '%s%s/global/images/%s' % (
GCE_URL, 'ubuntu-os-cloud', 'ubuntu-1410-utopic-v20141217')
machine_type_url = '%s/zones/%s/machineTypes/%s' % (
project_url, ZONE, 'n1-standard-1')
network_url = '%s/global/networks/%s' % (project_url, 'default')
instance = {
'name': INSTANCE_NAME,
'machineType': machine_type_url,
'disks': [{
'autoDelete': 'true',
'boot': 'true',
'type': 'PERSISTENT',
'initializeParams' : {
'diskName': INSTANCE_NAME,
'sourceImage': SOURCE_IMAGE_URL
}
}],
'networkInterfaces': [{
'accessConfigs': [{
'type': 'ONE_TO_ONE_NAT',
'name': 'External NAT'
}],
'network': network_url
}],
'serviceAccounts': [{
'email': DEFAULT_SERVICE_EMAIL,
'scopes': DEFAULT_SCOPES
}]
}
# Create the instance
request = gce_service.instances().insert(
project=PROJECT_ID, body=instance, zone=ZONE)
response = request.execute(http=http)
response = _blocking_call(gce_service, http, response)
print response
def _blocking_call(gce_service, auth_http, response):
"""Blocks until the operation status is done for the given operation."""
status = response['status']
while status != 'DONE' and response:
operation_id = response['name']
# Identify if this is a per-zone resource
if 'zone' in response:
zone_name = response['zone'].split('/')[-1]
request = gce_service.zoneOperations().get(
project=PROJECT_ID,
operation=operation_id,
zone=zone_name)
else:
request = gce_service.globalOperations().get(
project=PROJECT_ID, operation=operation_id)
response = request.execute(http=auth_http)
if response:
status = response['status']
return response
main()
僅供參考:在GCE中,您通常會獲得兩個默認服務帳戶:
請注意不同的電子郵件后綴( developer.gserviceaccount.com
與cloudservices.gserviceaccount.com
)。 似乎使用您自己的服務帳戶,即使它具有Owner
角色,也不會授予您對<number>@cloudservices.gserviceaccount.com
帳戶的訪問權限,而僅授予第一個帳戶( <number>-compute@developer.gserviceaccount.com
)。
就我而言,在嘗試使用自己的服務帳戶創建實例同時指定該實例將使用上方的第二個服務帳戶時,出現上述錯誤。 一旦我修復了要求實例將使用第一個帳戶的呼叫,它便開始工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.