简体   繁体   English

如何创建带有特定服务帐户设置的Google Compute Engine实例?

[英]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实例中有效。

  1. To do that go to the Cloud Console > Project > APIs & Auth > Credentials. 为此,请转到Cloud Console>项目> API和身份验证>凭据。
  2. Create new Client ID 创建新的客户ID
  3. Service Account 服务帐号
  4. Download the .p12 file and load that as the private key. 下载.p12文件,并将其作为私钥加载。 (See example below) (请参见下面的示例)

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中,您通常会获得两个默认服务帐户:

  • -compute@developer.gserviceaccount.com -compute@developer.gserviceaccount.com
  • @cloudservices.gserviceaccount.com @ cloudservices.gserviceaccount.com

Note the different Email suffix ( developer.gserviceaccount.com vs. cloudservices.gserviceaccount.com ). 请注意不同的电子邮件后缀( developer.gserviceaccount.comcloudservices.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.

相关问题 如何在不下载服务帐户凭据的情况下从 Google Compute Engine 和本地验证 Google API(Google Drive API)? - How to authenticate Google APIs (Google Drive API) from Google Compute Engine and locally without downloading Service Account credentials? 使用Google Compute Engine默认服务帐户签名Google Cloud Storage URL - Sign Google Cloud Storage URLs with Google Compute Engine default service account 如何从实例模板创建 Google Cloud Compute Instance - How to create a Google Cloud Compute Instance from the an instance template 列出谷歌云计算引擎活动实例 - List google cloud compute engine active instance 谷歌计算引擎api:创建全局地址 - Google compute engine api: create global address 将 Google colab 连接到 Google Compute Engine 实例上的运行时 - Connect Google colab to a runtime on a Google Compute Engine instance 如何在计算引擎实例上运行google appengine docker镜像? - How do I run a google appengine docker image on a compute engine instance? 无法将带有paramiko的SSH连接到Google Compute Engine实例 - Can't connect SSH with paramiko to a Google Compute Engine instance Google Compute Engine VM实例的“ Cloud Datastore”权限 - “Cloud Datastore” permission for Google Compute Engine VM instance 无法绑定到谷歌计算引擎虚拟机实例的外部 IP 地址 - Cannot bind to external IP address of google compute engine VM instance
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM