在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; some_name@developer.gserviceaccount.com'",但" ;用户"它指的是' some_name@developer.gserviceaccount.com'本身!这意味着' some_name@developer.gserviceaccount.com'无法访问' some_name@developer.gserviceaccount.com' ;,这没有任何意义。
答案 0 :(得分:1)
我认为您需要创建一个新的服务帐户才能使用非GCE实例中的API。您引用的服务帐户仅在GCE实例中工作。
此外,您还需要从引导磁盘创建一个实例,该实例通常是从GCE supplied images之一创建的。
这是一个使用适合我的JSON Web Tokens的示例。它改编自这里的文档: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()
答案 1 :(得分:0)
仅供参考:在GCE中,您通常会获得两个默认服务帐户:
请注意不同的电子邮件后缀(developer.gserviceaccount.com
与cloudservices.gserviceaccount.com
)。似乎使用您自己的服务帐户,即使它具有Owner
角色,也不会授予您访问<number>@cloudservices.gserviceaccount.com
帐户的权限,只允许您访问第一个帐户({{ 1}})。
就我而言,我在尝试使用自己的服务帐户创建实例时遇到了上述错误,同时指定实例将使用上面的第二个服务帐户。一旦我修复了呼叫以请求实例将使用第一个帐户,它就可以工作。