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

时间:2014-05-14 10:42:03

标签: python google-compute-engine

在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' ;,这没有任何意义。

2 个答案:

答案 0 :(得分:1)

我认为您需要创建一个新的服务帐户才能使用非GCE实例中的API。您引用的服务帐户仅在GCE实例中工作。

  1. 要执行此操作,请转到云控制台>项目> API& Auth>凭证。
  2. 创建新的客户ID
  3. 服务帐户
  4. 下载.p12文件并将其作为私钥加载。 (见下面的例子)
  5. 此外,您还需要从引导磁盘创建一个实例,该实例通常是从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中,您通常会获得两个默认服务帐户:

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

请注意不同的电子邮件后缀(developer.gserviceaccount.comcloudservices.gserviceaccount.com)。似乎使用您自己的服务帐户,即使它具有Owner角色,也不会授予您访问<number>@cloudservices.gserviceaccount.com帐户的权限,只允许您访问第一个帐户({{ 1}})。

就我而言,我在尝试使用自己的服务帐户创建实例时遇到了上述错误,同时指定实例将使用上面的第二个服务帐户。一旦我修复了呼叫以请求实例将使用第一个帐户,它就可以工作。