为实例创建和启用服务帐号

本页面介绍如何创建和使用虚拟机实例的服务帐号。服务帐号是一种特殊帐号,您可以在应用代码中使用其凭据来访问其他 Google Cloud Platform (GCP) 服务。

要了解服务帐号,请阅读服务帐号概览

准备工作

创建新的服务帐号

您可以使用 Google Cloud Identity and Access Management (IAM) 创建并设置新的服务帐号。创建帐号后,为该帐号授予一个或多个 IAM 角色,然后授权虚拟机实例以该服务帐号的身份运行。

要创建新的服务帐号,请执行以下操作:

  1. 按照 IAM 服务帐号文档中的说明创建新的服务帐号

  2. 获取服务帐号的电子邮件地址。 您需要使用该电子邮件地址将实例设置为以此服务帐号的身份运行。在 Console 中验证服务帐号的电子邮件地址:

    1. 转到 GCP Console 中的“服务帐号”页面。

      转到“服务帐号”页面

    2. 如果出现提示,请选择项目。
    3. 查找您的新服务帐号并记下服务帐号电子邮件地址。

    通常,服务帐号的电子邮件地址来源于服务帐号 ID,格式如下:

    [SERVICE-ACCOUNT-NAME]@[PROJECT_ID].iam.gserviceaccount.com
    
  3. 向服务帐号授予 IAM 角色。如果您不授予任何角色,则服务帐号将无权访问任何服务。如需查看 IAM 角色的完整列表,请参阅 IAM 文档中的了解角色部分。

  4. 然后将实例设置为以服务帐号的身份运行。 按照以下说明将实例设置为以服务帐号的身份运行

将新实例设置为以服务帐号的身份运行

创建新的服务帐号之后,您可以创建以该服务帐号的身份运行的新虚拟机实例。如果要为现有实例分配或更改服务帐号,请参阅更改实例的服务帐号和访问范围

您可以允许多个虚拟机实例使用同一个服务帐号,但一个虚拟机实例只能具有一个服务帐号身份。如果将同一服务帐号分配给多个虚拟机实例,则您对该服务帐号所做的任何后续更改都将影响使用该服务帐号的实例。这包括您对授予服务帐号的 IAM 角色所做的任何更改。例如,如果删除一个角色,则使用该服务帐号的所有实例都将失去该角色授予的权限。

您可以通过 Google Cloud Platform Consolegcloud 命令行工具或直接通过 API 将新实例设置为以服务帐号的身份运行。

Console

  1. 在 GCP Console 中,转到“虚拟机实例”页面。

    转到“虚拟机实例”页面

  2. 点击创建实例
  3. 创建新实例页面上,为实例填写所需的属性。
  4. 身份和 API 访问权限部分,从下拉列表中选择要使用的服务帐号。
  5. 点击创建以创建实例。

gcloud

要使用 gcloud 命令行工具创建新实例并授权该实例以自定义服务帐号的身份运行,请提供服务帐号电子邮件地址和该实例所需的访问权限范围。通常,您可以只设置 cloud-platform 访问范围。授予虚拟机实例的访问范围与授予服务帐号的 IAM 角色共同决定了服务帐号对该实例具有的访问权限大小。仅当访问范围和 IAM 角色两者都允许时,服务帐号才能执行 API 方法。

或者,您也可以选择设置特定范围,授予服务将调用的特定 API 方法的访问权限。例如,要调用 instances.insert 方法,需要获得 https://www.googleapis.com/auth/compute 范围或 https://www.googleapis.com/auth/cloud-platform 范围的授权以及授予对该方法的访问权限的 IAM 角色。您可以设置 compute 范围来代替 cloud-platform 范围,这将授权服务在 Compute Engine 中调用方法,但并未授权服务在 Compute Engine 之外调用 API 方法。

gcloud compute instances create [INSTANCE_NAME] \
    --service-account [SERVICE_ACCOUNT_EMAIL] \
    --scopes [SCOPES,...]

其中:

  • [SERVICE_ACCOUNT_EMAIL] 是您要使用的服务帐号电子邮件地址。例如:my-sa-123@my-project-123.iam.gserviceaccount.com。如果您不清楚具体电子邮件地址,请了解如何获取服务帐号电子邮件地址
  • [INSTANCE_NAME] 是实例的名称。
  • [SCOPES]--scopes 标志的说明中提供的完整范围 URI范围别名的以英文逗号分隔的列表。

例如:

gcloud compute instances create example-vm \
    --service-account 123-my-sa@my-project-123.iam.gserviceaccount.com \
    --scopes https://www.googleapis.com/auth/cloud-platform

gcloud 工具还提供范围别名来代替较长的范围 URI。例如,对 Google Cloud Storage 的完整访问权限的范围是 https://www.googleapis.com/auth/devstorage.full_control。此范围的别名是 storage-full

您可以在 --scopes 标志说明中的 instances create 页面上查看范围和范围别名列表。instances create 命令帮助还列出了以下范围和别名:

gcloud compute instances create --help

按照与指定普通范围 URI 相同的方式指定别名。例如:

gcloud compute instances create [INSTANCE_NAME] \
    --service-account [SERVICE_ACCOUNT_EMAIL] \
    --scopes cloud-platform

API

在 API 中,构造一项标准请求来创建实例,但同时添加 serviceAccounts 属性。 获取您的服务帐号电子邮件地址,并将其添加为 email 属性,此外还要添加实例所需的访问权限范围。通常,您可以只设置 cloud-platform 访问范围。授予服务帐号的访问范围和 IAM 角色共同决定了服务帐号对该实例具有的访问权限大小。仅当访问范围和 IAM 角色两者都允许时,服务帐号才能执行 API 方法。

或者,您可以选择设置特定范围,授予服务将调用的特定 API 方法的访问权限。例如,要调用 instances.insert 方法,需要获得 https://www.googleapis.com/auth/compute 范围或 https://www.googleapis.com/auth/cloud-platform 范围的授权。您可以设置 compute 范围来代替 cloud-platform 范围,这将授权服务在 Compute Engine 中调用方法,但并未授权服务在 Compute Engine 之外调用 API 方法。

POST https://www.googleapis.com/compute/v1/projects/zones/[ZONE]/instances

{
  "machineType": "https://www.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/machineTypes/[MACHINE_TYPE]",
  "name": "[INSTANCE_NAME]",
  "serviceAccounts": [
   {
    "email": "[SERVICE_ACCOUNT_EMAIL]",
    "scopes": ["https://www.googleapis.com/auth/cloud-platform"]
   }
  ],
  ...
}

在将实例设置为以服务帐号的身份运行后,您可以通过以下几种方式在实例中使用服务帐号凭据:

使用服务帐号凭据对应用进行身份验证

在将实例设置为以服务帐号的身份运行后,您可以使用服务帐号凭据对实例上运行的应用进行身份验证。

使用客户端库对应用进行身份验证

客户端库可以使用应用默认凭据在 Google API 中进行身份验证,并向这些 API 发送请求。应用默认凭据允许应用从多个源获取凭据,因此您可以在本地测试应用,然后将其部署到 Compute Engine 实例,而无需更改应用代码。在本地开发应用时,应用可以使用环境变量或 Google Cloud SDK 进行身份验证。当应用在实例上运行时,它可以使用已在实例上启用的服务帐号进行身份验证。

此示例使用 Python 客户端库进行身份验证,并向 Cloud Storage API 发出请求以列出项目中的存储分区。该示例使用了以下过程:

  1. 获取 Cloud Storage API 所需的必要身份验证凭据,并使用 build() 方法和凭据初始化 Cloud Storage 服务。
  2. 列出 Cloud Storage 中的存储分区。

您可以在有权管理 Google Cloud Storage 中的存储分区的实例上运行此示例。

import argparse

import googleapiclient.discovery

def create_service():
    # Construct the service object for interacting with the Cloud Storage API -
    # the 'storage' service, at version 'v1'.
    # Authentication is provided by application default credentials.
    # When running locally, these are available after running
    # `gcloud auth application-default login`. When running on Compute
    # Engine, these are available from the environment.
    return googleapiclient.discovery.build('storage', 'v1')

def list_buckets(service, project_id):
    buckets = service.buckets().list(project=project_id).execute()
    return buckets

def main(project_id):
    service = create_service()
    buckets = list_buckets(service, project_id)
    print(buckets)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('project_id', help='Your Google Cloud Project ID.')

    args = parser.parse_args()

    main(args.project_id)

直接使用访问令牌对应用进行身份验证

对于某些应用,您可能需要请求 OAuth2 访问令牌并直接使用,而无需通过客户端库或者使用 gcloudgsutil 工具。在获取并使用这些访问令牌对应用进行身份验证时,有几种方法可供选择。例如,您可以使用 curl 创建简单请求,或使用 Python 之类的编程语言实现更大的灵活性。

cURL

要使用 curl 请求访问令牌并向 API 发送请求,请执行以下操作:

  1. 在应用运行的实例上,通过运行以下命令在元数据服务器中查询访问令牌:

    $ curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
    -H "Metadata-Flavor: Google"

    该请求会返回如下所示的响应:

    {
          "access_token":"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_QtAS08i85nHq39HE3C2LTrCARA",
          "expires_in":3599,
          "token_type":"Bearer"
     }
  2. 从响应中复制 access_token 属性的值,并使用该值向 API 发送请求。例如,以下请求输出了项目中某个地区的实例列表:

    $ curl https://www.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/instances \
    -H "Authorization":"Bearer [ACCESS_TOKEN]"
    

    其中:

    • [PROJECT_ID] 是此请求的项目 ID。
    • [ZONE] 是列出实例所在的地区。
    • [ACCESS_TOKEN] 是您在步骤 1 中获得的访问令牌值。

    要了解可在请求中设置的参数,请参阅参数文档。

Python

此示例演示如何请求令牌以在 Python 应用中访问 Google Cloud Storage API。该示例采用以下过程:

  1. 从元数据服务器请求访问令牌。
  2. 从服务器响应中提取访问令牌。
  3. 使用访问令牌向 Google Cloud Storage 发出请求。
  4. 如果请求成功,脚本将输出响应内容。
import argparse

import requests

METADATA_URL = 'http://metadata.google.internal/computeMetadata/v1/'
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
SERVICE_ACCOUNT = 'default'

def get_access_token():
    url = '{}instance/service-accounts/{}/token'.format(
        METADATA_URL, SERVICE_ACCOUNT)

    # Request an access token from the metadata server.
    r = requests.get(url, headers=METADATA_HEADERS)
    r.raise_for_status()

    # Extract the access token from the response.
    access_token = r.json()['access_token']

    return access_token

def list_buckets(project_id, access_token):
    url = 'https://www.googleapis.com/storage/v1/b'
    params = {
        'project': project_id
    }
    headers = {
        'Authorization': 'Bearer {}'.format(access_token)
    }

    r = requests.get(url, params=params, headers=headers)
    r.raise_for_status()

    return r.json()

def main(project_id):
    access_token = get_access_token()
    buckets = list_buckets(project_id, access_token)
    print(buckets)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('project_id', help='Your Google Cloud project ID.')

    args = parser.parse_args()

    main(args.project_id)

访问令牌会在短时间后过期。元数据服务器会缓存访问令牌,直到离到期时间还有 60 秒。您可以根据需要随时请求新令牌,但应用必须具有有效的访问令牌,其 API 调用才能成功。

使用服务帐号在实例上对工具进行身份验证

某些应用可能使用 gcloudgsutil 工具中的命令,大多数 Compute Engine 映像中都会默认附带这些工具。这些工具会自动识别实例的服务帐号和授予服务帐号的相关权限。具体来说,如果您向服务帐号授予正确的角色,则可以使用实例中的 gcloudgsutil 工具,而无需使用 gcloud auth login

这种服务帐号识别会自动发生,且仅适用于实例随附的 gcloudgsutil 工具。如果您要创建新工具或添加自定义工具,则必须使用客户端库直接在应用中使用访问令牌对应用进行授权。

要利用自动服务帐号识别功能,请向服务帐号授予相应 IAM 角色,并将实例设置为以服务帐号的身份运行。例如,如果您授予服务帐号 roles/storage.objectAdmin 角色,则 gsutil 工具可以自动管理和访问 Google Cloud Storage 对象。

同样,如果为该服务帐号启用 roles/compute.instanceAdmin.v1,则 gcloud compute 工具可自动管理实例。

更改实例的服务帐号和访问范围

如果您想要以不同身份运行虚拟机,或者确定实例需要另一组范围来调用所需的 API,则可以更改现有实例的服务帐号和访问范围。例如,您可以更改访问范围以授予对新 API 的访问权限,或者更改实例,使其以您创建的服务帐号的身份运行,而不是以 Compute Engine 默认服务帐号的身份运行。

为了更改实例的服务帐号和访问范围,您必须暂时停止该实例。要停止实例,请阅读有关停止实例的文档。更改服务帐号或访问权限范围后,请记得重启实例。使用以下一种方法更改已停止实例的服务帐号或访问权限范围。

Console

  1. 转到 Compute Engine 中的“虚拟机实例”页面。

    转到“虚拟机实例”页面

  2. 点击要更改服务帐号的虚拟机实例。
  3. 如果实例未停止,请点击停止按钮。等待实例停止。
  4. 然后点击修改按钮。
  5. 向下滚动到服务帐号部分。
  6. 从下拉菜单中选择所需的服务帐号。
  7. 要更改范围,请在访问权限范围部分根据需要设置适当的范围。最佳做法是仅指定虚拟机实例所需的访问权限范围。如果您不确定要设置的正确访问权限范围,请选择允许所有 Cloud API 的全面访问权限,然后确保通过设置 IAM 角色来限制访问权限。
  8. 点击保存按钮以保存更改。

gcloud

使用命令 instances set-service-account 并提供实例名称、服务帐号电子邮件和所需的范围。您还可以从实例中删除服务帐号和访问范围,从而有效阻止实例访问任何 Google Cloud Platform 服务:

gcloud compute instances set-service-account [INSTANCE_NAME] \
   [--service-account [SERVICE_ACCOUNT_EMAIL] | --no-service-account] \
   [--no-scopes | --scopes [SCOPES,...]]

其中:

  • [SERVICE_ACCOUNT_EMAIL] 是您要使用的服务帐号电子邮件地址。例如:my-sa-123@my-project-123.iam.gserviceaccount.com
  • [INSTANCE_NAME] 是实例的名称。
  • [SCOPES]--scopes 标志说明中提供的完整范围 URI范围别名的以英文逗号分隔的列表。如果要移除实例的所有范围,请改用 --no-scopes 标志。

例如,以下命令将服务帐号 my-sa-123@my-project-123.iam.gserviceaccount.com 分配给名为 example-instance 的实例,并对该实例设置访问权限范围,以允许对 Compute Engine 进行读写访问,同时允许对 Google Cloud Storage 进行只读访问:

gcloud compute instances set-service-account example-instance \
   --service-account my-sa-123@my-project-123.iam.gserviceaccount.com \
   --scopes compute-rw,storage-ro

API

在 API 中,向 setServiceAccount 方法发出 POST 请求:

https://www.googleapis.com/compute/v1/projects[PROJECT_ID]/zones/[ZONE]/instances/[INSTANCE_NAME]/setServiceAccount

其中:

  • [PROJECT_ID] 是此请求的项目 ID。
  • [ZONE] 是实例所属的地区。
  • [INSTANCE_NAME] 是实例的名称。

在请求正文中,提供服务帐号的电子邮件地址和实例的所需范围 URI

{
  "email": "[SERVICE_ACCOUNT_EMAIL]",
  "scopes": [
    "[SCOPE_URI]",
    "[SCOPE_URI]",
    ...
  ]
}

例如,以下请求使用服务帐号电子邮件地址 my-sa-123@my-project-123.iam.gserviceaccount.com 并设置 Google Cloud Storage 和 Google BigQuery 范围:

{
  "email": "my-sa-123@my-project-123.iam.gserviceaccount.com",
  "scopes": [
    "https://www.googleapis.com/auth/bigquery",
    "https://www.googleapis.com/auth/devstorage.read_only"
  ]
}

获取服务帐号电子邮件

要识别服务帐号,您需要服务帐号电子邮件。通过以下选项之一获取服务帐号电子邮件:

Console

  1. 转到 GCP Console 中的“服务帐号”页面。

    转到“服务帐号”页面

  2. 如果出现提示,请选择项目。该服务帐号页面列出了项目的所有服务帐号及其电子邮件地址。

gcloud

在本地计算机上使用 gcloud compute instances describe 命令:

gcloud compute instances describe [INSTANCE_NAME] --format json
{
      ...
      "serviceAccounts":[
         {
            "email":"123845678986-compute@developer.gserviceaccount.com",
            "scopes":[
               "https://www.googleapis.com/auth/devstorage.full_control"
            ]
         }
      ]
      ...
   }

如果实例未使用服务帐号,您会收到不带 serviceAccounts 属性的响应。

元数据服务器

从实例本身查询元数据服务器。向 http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/ 发出请求:

user@myinst:~$ curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" \
-H "Metadata-Flavor: Google"

如果您在创建实例时启用了一个或多个服务帐号,则此 curl 命令将返回如下所示的输出:

123845678986-compute@developer.gserviceaccount.com/
default/

如果实例未使用服务帐号,您会收到空响应。

API

向 Service Accounts API 发出请求

使用 Compute Engine 默认服务帐号

如果您熟悉 Compute Engine 默认服务帐号,并希望使用默认服务帐号提供的凭据而不是创建新服务帐号,则可以将 IAM 角色授予默认服务帐号。

默认情况下,所有 Compute Engine 实例均可以默认服务帐号的身份运行。在使用 gcloud 命令行工具或 GCP Console 创建实例时,若不指定任何服务帐号,则会为该实例分配默认服务帐号。

在将 IAM 角色分配给默认服务帐号之前,请注意:

  • 向默认服务帐号授予 IAM 角色会影响以默认服务帐号的身份运行的所有实例。例如,如果您向默认服务帐号授予 roles/storage.objectAdmin 角色,则具有所需访问权限范围且以默认服务帐号的身份运行的所有实例都将具有 roles/storage.objectAdmin 角色授予的权限。同样,如果通过省略某些角色来限制访问,则会影响以默认服务帐号的身份运行的所有实例。

  • 必须撤消服务帐号的项目编辑者权限。默认情况下,默认服务帐号会作为项目编辑者添加到项目中。为了使用 IAM 角色,您必须撤消项目编辑者权限。

如果您不确定是否要将 IAM 角色授予默认服务帐号,则应该创建新的服务帐号

按照以下说明将 IAM 角色授予默认服务帐号:

  1. 转到 GCP Console 中的 IAM 页面。

    转到 IAM 页面

  2. 如果出现提示,请选择项目。
  3. 查找名为 Compute Engine 默认服务帐号的服务帐号。
  4. 角色列中,展开下拉菜单找到“Compute Engine 默认服务帐号”。
  5. 移除编辑者访问权限并保存更改。
  6. 然后向服务帐号授予 IAM 角色

当前以默认服务帐号身份运行的任何虚拟机实例现在都可以根据您授予该帐号的 IAM 角色访问其他 Google Cloud Platform API。

如果要将新实例设置为以默认服务帐号身份运行,请按照以下说明操作:

Console

  1. 在 GCP Console 中,转到“虚拟机实例”页面。

    转到“虚拟机实例”页面

  2. 点击创建实例
  3. 创建新实例页面上,为实例填写所需的属性。
  4. 身份和 API 访问权限部分,从下拉列表中选择 Compute Engine 默认服务帐号
  5. 点击创建以创建实例。

gcloud

要创建新实例并允许它使用默认服务帐号完全访问所有 Google Cloud Platform 服务,请执行以下操作:

gcloud compute instances create [INSTANCE_NAME] \
     --scopes cloud-platform

API

在 API 中,构造一项标准请求来创建实例,但同时添加 serviceAccounts 属性。 获取默认服务帐号 ID,并将其添加为服务帐号的 email。然后在 scopes 属性中设置一个或多个范围。

POST https://www.googleapis.com/compute/v1/projects/zones/[ZONE]/instances

{
  "machineType": "https://www.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/[ZONE]/machineTypes/[MACHINE_TYPE]",
  "name": "[INSTANCE_NAME]",
  "serviceAccounts": [
   {
    "email": "[DEFAULT_SERVICE_ACCOUNT_EMAIL]",
    "scopes": ["https://www.googleapis.com/auth/cloud-platform"]
   }
  ],
  ...
}

最佳做法

通常,Google 建议每个需要调用 Google API 的实例应以服务帐号的身份运行,该服务帐号具有该实例执行作业所需的最低权限。在实际操作中,这意味着您应该使用以下过程为实例配置服务帐号:

  1. 创建新的服务帐号,而不是使用 Compute Engine 默认服务帐号。
  2. 仅针对所需的资源,将 IAM 角色授予该服务帐号。
  3. 将实例配置为以该服务帐号的身份运行。
  4. 向实例授予 https://www.googleapis.com/auth/cloud-platform 范围,以允许对所有 Google Cloud API 的全面访问权限,从而使实例的 IAM 权限完全由服务帐号的 IAM 角色决定。

请避免授予超出需求的访问权限,并定期检查服务帐号权限以确保其始终能满足需求。

后续步骤

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
Compute Engine 文档