身份验证与授权

本部分介绍与 Fleet Engine 实现相关的身份验证和授权概念。它详细介绍了保护 Fleet Engine 函数调用所需执行的流程。

您可以通过 Google Cloud 控制台配置 Last Mile Fleet 解决方案提供的功能。这些 API 和 SDK 需要使用通过 Cloud 控制台创建的服务帐号签名的 JSON Web 令牌 (JWT)。

概览

作为其授权机制的一部分,Fleet Engine 针对源自低信任环境的调用提供额外的安全性。低信任环境包括智能手机和浏览器。此外,Fleet Engine 采用最小权限原则,即应该仅向调用提供完成其任务所需的权限。

为了保护源自低信任环境的函数调用,Google 设计了一种机制,在该机制中,您的代码会在后端服务器(一个完全可信的环境)上创建令牌。每个调用都带有完整的安全说明,这些说明随后会被加密到从任何环境中通过调用传递的 JWT 中。

身份验证设计原则

Fleet Engine 的身份验证流程包含以下设计原则。

  • IAM 角色定义了调用者允许的活动范围。例如,SuperUser角色可以执行所有操作,而SuperUser角色只能执行最少量的位置信息更新。

  • IAM 角色与服务账号相关联。

  • JWT 声明会进一步限制调用方可操作的实体。这些可以是特定任务或送货车辆。

  • 发送到 Fleet Engine 的请求始终包含 JWT。

    • 由于 JWT 与服务帐号关联,因此发送到 Fleet Engine 的请求会隐式与与 JWT 关联的服务帐号关联。
  • 为了请求随后可以传递给 Fleet Engine 的相应 JWT,在低信任环境中运行的代码必须先调用在完全可信的环境中运行的代码。

  • Fleet Engine 会执行以下安全检查:

    1. 与服务帐号相关联的 IAM 角色为调用者发出 API 调用提供正确的授权。

    2. 请求中传递的 JWT 声明为调用方提供正确的实体操作授权。

身份验证流程

以下序列图演示了这些身份验证流程的详细信息。

  1. 舰队管理员会创建服务账号。

  2. 舰队管理员为服务账号分配特定的 IAM 角色。

  3. 舰队管理员使用服务帐号配置其后端。

  4. 客户端应用从合作伙伴的后端请求 JWT。请求者可以是驱动程序应用、消费者应用或监控应用。

  5. Fleet Engine 为相应的服务帐号颁发 JWT。客户端应用接收 JWT。

  6. 客户端应用使用 JWT 连接到 Fleet Engine 以读取或修改数据,具体取决于设置阶段分配给它的 IAM 角色。

身份验证序列图

Cloud 项目设置

如需设置云项目,请先创建项目,然后再创建服务帐号。

如需创建 Google Cloud 项目,请执行以下操作:

  1. 使用 Google Cloud 控制台创建 Google Cloud 项目。
  2. 使用 API 和服务信息中心,启用 Local Rides and Deliveries API。

服务账号和 IAM 角色

服务帐号是一种由应用(而不是个人)使用的特殊帐号。通常,服务帐号用于创建 JWT,以便根据角色授予不同权限集。为了降低滥用的可能性,您可以创建多个服务帐号,每个服务帐号只需拥有最少的角色集。

Last Mile Fleet 解决方案使用以下角色:

角色说明
Fleet Engine Delivery 可信司机用户

roles/fleetengine.deliveryTrustedDriver
授予创建和更新送货车辆和任务的权限,包括更新送货车辆的位置和任务状态或结果。具有此角色的服务帐号生成的令牌通常从配送司机的移动设备或后端服务器使用。
Fleet Engine Delivery 不受信任的司机用户

roles/fleetengine.deliveryUntrustedDriver
授予更新送货车辆位置的权限。由具有此角色的服务帐号创建的令牌通常在送货司机的移动设备上使用。
Fleet Engine Delivery Consumer User

roles/fleetengine.deliveryConsumer
授予使用跟踪 ID 搜索任务以及读取但不更新任务信息的权限。具有此角色的服务帐号生成的令牌通常通过传送使用方的网络浏览器使用。
Fleet Engine Delivery 超级用户

roles/fleetengine.deliverySuperUser
授予对所有配送工具和任务 API 的权限。具有此角色的服务帐号生成的令牌通常使用您的后端服务器。
Fleet Engine Delivery Fleet Reader

roles/fleetengine.deliveryFleetReader
授予读取送货车辆和任务的权限,以及使用跟踪 ID 搜索任务的权限。具有此角色的服务帐号生成的令牌通常通过交付舰队运营商的网络浏览器使用。

如果组织使用由公司 IT 管理的设备为配送司机提供设备,则可以利用 Fleet Engine 可信司机用户角色提供的灵活性,并选择将部分或全部 Fleet Engine 互动集成到移动应用中。

支持“自带设备”政策的组织应选择确保 Fleet Engine 不受信任的司机用户角色的安全性,并且仅依赖移动应用将车辆位置信息更新发送到 Fleet Engine。所有其他互动都应来自客户后端服务器。

驱动程序 SDK 和消费者 SDK 是围绕这些标准角色构建的。但是,您可以创建自定义角色,来允许将一组任意权限捆绑在一起。如果缺少所需权限,驱动程序 SDK 和消费者 SDK 将显示错误消息。因此,我们强烈建议使用上述标准角色,而不是自定义角色。

创建服务账号

您可以使用 Google Cloud 控制台中的 IAM & Admin > Service Accounts 标签页创建服务帐号。从“角色”下拉列表中,选择 Fleet Engine,然后将其中一个角色分配给服务帐号。最好指明与每个角色关联的帐号。例如,为服务账号指定一个有意义的名称。

为方便起见,如果您需要为不受信任的客户端创建 JWT,可以将用户添加到 Service Account Token Creator 角色,这样他们就可以使用 gcloud 命令行工具创建令牌。

gcloud projects add-iam-policy-binding project-id \
       --member=user:my-user@example.com \
       --role=roles/iam.serviceAccountTokenCreator

其中,my-user@example.com 是用于通过 gcloud 进行身份验证的电子邮件地址 (gcloud auth list --format='value(account)')。

Fleet Engine 身份验证库

Fleet Engine 使用 JWT 限制对 Fleet Engine API 的访问。GitHub 上提供了新的 Fleet Engine Auth 库,它简化了 Fleet Engine JWT 的构建并对其进行安全签名。

该库具有以下优势:

  • 简化创建 Fleet Engine 令牌的过程。
  • 提供除使用凭据文件以外的令牌签名机制(例如模拟服务帐号)。
  • 将已签名的令牌附加到从 gRPC 桩或 GAPIC 客户端发出的出站请求。

创建 JSON Web 令牌 (JWT) 以进行授权

如果不使用 Fleet Engine Auth 库,您需要直接在代码库中创建 JWT。因此,您需要深入了解 JWT 及其与 Fleet Engine 的关系。因此,我们强烈建议利用 Fleet Engine Auth 库。

在 Fleet Engine 中,JWT 提供短期身份验证,并确保设备只能修改其获得授权的车辆或任务。JWT 包含一个标头和一个声明部分。 标头部分包含要使用的私钥(从服务帐号中获取)和加密算法等信息。声明部分包含如下信息:令牌的创建时间、令牌的存留时间、令牌声明所有权的服务,以及用于缩小访问权限范围的其他授权信息(例如送货车辆 ID)。

JWT 标头部分包含以下字段:

字段说明
alg 要使用的算法。`RS256`。
typ 令牌的类型。“JWT”。
儿童 您的服务帐号的私钥 ID。您可以在服务帐号 JSON 文件的“private_key_id”字段中找到此值。请务必使用具有正确级别权限的服务账号的密钥。

JWT 声明部分包含以下字段:

字段说明
iss 您的服务帐号的电子邮件地址。
sub 您的服务帐号的电子邮件地址。
aud 您的服务账号的 SERVICE_NAME,在本示例中为 https://fleetengine.googleapis.com/
iat 创建令牌时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC(世界协调时间)起经过的秒数指定。允许 10 分钟偏差。如果时间戳是过于久远的过去或将来,服务器可能会报告错误。
exp 令牌到期的时间戳,以自世界协调时间 (UTC) 1970 年 1 月 1 日 00:00:00 以来经过的秒数指定。如果时间戳在未来一小时以上,则请求将失败。
授权 根据用例,它可能包含“deliveryvehicleid”“trackingid”“taskid”或“taskids”。

创建 JWT 令牌指的是对其进行签名。如需了解如何创建和为 JWT 签名,请参阅不使用 OAuth 的服务帐号授权。然后,您可以将生成的令牌附加到 gRPC 调用或用于访问 Fleet Engine 的其他方法。

JWT 声明

最后一英里舰队解决方案使用不公开声明。使用私有声明可确保只有获得授权的客户端才能访问自己的数据。例如,当您的后端为送货司机的移动设备颁发 JSON Web 令牌时,该令牌应包含 deliveryvehicleid 声明以及该司机的送货车辆 ID 的值。然后,根据驾驶员角色,令牌仅可访问特定交付车辆 ID,而不能访问任何其他任意车辆 ID。

最后一英里舰队解决方案使用以下不公开声明:

  • deliveryvehicleid - 在调用每辆车的 API 时使用。
  • taskid - 在调用任务级 API 时使用。
  • taskids - 在调用 BatchCreateTasksAPI 时使用。此声明必须采用数组形式,并且该数组应包含完成请求所需的所有任务 ID。请勿包含 delivervehicleidtrackingidtaskid 声明。
  • trackingid - 在调用 SearchTasksAPI 时使用。声明必须与请求中的跟踪 ID 一致。请勿包含 delivervehicleidtaskidtaskids 声明。

当您从后端服务器调用 API 时,该令牌还必须包含相应的声明,但您可以对 deliveryvehicleidtaskidtrackingid 声明使用星号(“*”)的特殊值。星号(“*”)也可以在 taskids 声明中使用,但它必须是数组中的唯一元素。

如果您希望直接以令牌不记名的形式创建 JSON 并为其签名,而不是使用 OAuth 2.0 访问令牌,请参阅 Identity Developer 文档中的不使用 OAuth 的服务帐号授权说明。

将令牌附加到 gRPC 调用的机制取决于用于进行调用的语言和框架。为 HTTP 调用指定令牌的机制是添加带有不记名令牌的授权标头,其值为令牌,如各个运单跟踪舰队性能用例的授权说明中所述。

以下示例展示了后端服务器中每个任务的操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "taskid": "*"
       }
    }

以下示例展示了从后端服务器执行批量创建任务操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "taskids": ["*"]
       }
    }

以下示例展示了来自后端服务器的每个送货车辆操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "deliveryvehicleid": "*"
       }
    }

以下示例展示了面向最终用户客户的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_delivery_consumer_service_account"
    }
    .
    {
      "iss": "consumer@yourgcpproject.iam.gserviceaccount.com",
      "sub": "consumer@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "trackingid": "shipment_12345"
       }
    }

以下示例显示了您的驱动程序应用的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_delivery_driver_service_account"
    }
    .
    {
      "iss": "driver@yourgcpproject.iam.gserviceaccount.com",
      "sub": "driver@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "deliveryvehicleid": "driver_12345"
       }
    }
  • 对于标头中的 kid 字段,请指定服务帐号的私钥 ID。您可以在服务帐号 JSON 文件的 private_key_id 字段中找到此值。
  • 对于 isssub 字段,请指定您的服务帐号的电子邮件地址。您可以在服务帐号 JSON 文件的 client_email 字段中找到此值。
  • 对于 aud 字段,请指定 https://SERVICE_NAME/
  • 对于 iat 字段,请指定创建令牌时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的秒数。允许 10 分钟偏差。如果时间戳是过于久远的过去或将来,服务器可能会报告错误。
  • 对于 exp 字段,请指定令牌到期时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数表示。建议值为 iat + 3600。

对要传递给移动设备或最终用户的令牌进行签名时,请务必使用交付司机或消费者角色的凭据文件。否则,移动设备或最终用户将能够更改或查看他们无权访问的信息。