![](/img/trans.png)
[英]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.