[英]How to create Google Compute Engine instance with particular service account setup on it?
When you create an instance A in Google Compute Engine, it'll get predefined, "default" service account attached to it (this basically means, that you can query google API from A, being authenticated with 'default' service account). 当您在Google Compute Engine中创建实例A时,该实例将获得预定义的“默认”服务帐户(这基本上意味着您可以从A查询google API,并通过“默认”服务帐户进行身份验证)。 What I'd like to do, is to setup GCE instance with service account, that's different than a default one.
我想做的是使用服务帐户设置GCE实例,这与默认帐户不同。 This should be conceptually possible, given GCE API, but fails with exception:
在给定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'"
} ] } }
Here's my code in python, which setups the instance: 这是我在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)
The weirdest part of it, is that exception says "The user does not have access to service account 'some_name@developer.gserviceaccount.com'", but the "user" it refers to is the 'some_name@developer.gserviceaccount.com' itself! 它最奇怪的部分是,异常显示“用户无权访问服务帐户'some_name@developer.gserviceaccount.com'”,但它所指的“用户”是“ some_name@developer.gserviceaccount.com”本身! Which means 'some_name@developer.gserviceaccount.com' does not have access to 'some_name@developer.gserviceaccount.com', which makes no sense.
这意味着“ some_name@developer.gserviceaccount.com”无权访问“ some_name@developer.gserviceaccount.com”,这没有任何意义。
I believe you'll need to create a new service account to use the API from a non-GCE instance. 我相信您需要创建一个新的服务帐户才能使用非GCE实例中的API。 The service account you're referencing works within a GCE instance only.
您引用的服务帐户仅在GCE实例中有效。
Also you'll need to create an instance from a boot disk which is typically created from one of the GCE supplied images . 另外,您还需要从启动盘创建实例,该启动盘通常是由GCE提供的映像之一创建的。
Here's an example using JSON Web Tokens that worked for me. 这是一个对我有用的使用JSON Web令牌的示例。 It was adapted from the docs located here: https://cloud.google.com/compute/docs/tutorials/python-guide#addinganinstance .
它是根据位于以下位置的文档改编而成的: 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()
FYI: in GCE you usually get two default service accounts: 仅供参考:在GCE中,您通常会获得两个默认服务帐户:
Note the different Email suffix ( developer.gserviceaccount.com
vs. cloudservices.gserviceaccount.com
). 请注意不同的电子邮件后缀(
developer.gserviceaccount.com
与cloudservices.gserviceaccount.com
)。 It appears that using your own service account, EVEN if it has the Owner
role, does not grant you access to the <number>@cloudservices.gserviceaccount.com
account, only to the 1st one ( <number>-compute@developer.gserviceaccount.com
). 似乎使用您自己的服务帐户,即使它具有
Owner
角色,也不会授予您对<number>@cloudservices.gserviceaccount.com
帐户的访问权限,而仅授予第一个帐户( <number>-compute@developer.gserviceaccount.com
)。
In my case, I got the aforementioned error when trying to create an instance with my own service account while specifing that the instance will use the 2nd service account from above. 就我而言,在尝试使用自己的服务帐户创建实例同时指定该实例将使用上方的第二个服务帐户时,出现上述错误。 Once I fixed the call to request that the instance will use the 1st account, it worked.
一旦我修复了要求实例将使用第一个帐户的呼叫,它便开始工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.