使用凭据访问边界缩小权限范围

本页面介绍如何使用凭据访问边界来缩小或限制短期有效的凭据可以使用的 Identity and Access Management (IAM) 权限范围。

凭据访问边界的工作原理

要缩小权限范围,您需要定义凭据访问边界(用来指定短期有效的凭据可以访问的资源),以及在各资源上可用权限的上限。然后,您可以创建一个短期有效的凭据,并用其交换遵循凭据访问边界的新凭据。

如果您需要针对每个会话为成员分配一组不同的权限,那么与创建多个不同的服务帐号并为每个服务帐号授予一组不同的角色相比,使用凭据访问边界更高效。例如,如果您的某个客户需要访问您控制的 Cloud Storage 数据,您可以创建一个可以访问您拥有的所有 Cloud Storage 存储分区的服务帐号,然后再应用一个只允许访问包含您的客户数据的存储分区的凭据访问边界。

凭据访问边界的示例

以下各个部分展示了常见使用场景的凭据访问边界示例。

限制存储分区的权限

以下示例展示了一个简单的凭据访问边界。它应用于 Cloud Storage 存储分区 example-bucket,并且将权限上限设置为 Storage Object Viewer 角色 (roles/storage.objectViewer) 中包含的权限:

{
  "accessBoundary": {
    "accessBoundaryRules": [
      {
        "availablePermissions": [
          "inRole:roles/storage.objectViewer"
        ],
        "availableResource": "//storage.googleapis.com/projects/_/buckets/example-bucket"
      }
    ]
  }
}

限制多个存储分区的权限

以下示例展示了一个凭据访问边界,其中包含多个存储分区的规则:

  • Cloud Storage 存储分区 example-bucket-1:对于此存储分区,只有 Storage Object Viewer 角色 (roles/storage.objectViewer) 中的权限可用。
  • Cloud Storage 存储分区 example-bucket-2:对于此存储分区,只有 Storage Object Creator 角色 (roles/storage.objectCreator) 中的权限可用。
{
  "accessBoundary": {
    "accessBoundaryRules": [
      {
        "availablePermissions": [
          "inRole:roles/storage.objectViewer"
        ],
        "availableResource": "//storage.googleapis.com/projects/_/buckets/example-bucket-1"
      },
      {
        "availablePermissions": [
          "inRole:roles/storage.objectCreator"
        ],
        "availableResource": "//storage.googleapis.com/projects/_/buckets/example-bucket-2"
      }
    ]
  }
}

限制特定对象的权限

您还可以使用 IAM Conditions 指定成员可以访问哪些 Cloud Storage 对象。例如,您可以添加一个条件,该条件使权限可用于名称以 customer-a 开头的对象:

{
  "accessBoundary": {
    "accessBoundaryRules": [
      {
        "availablePermissions": [
          "inRole:roles/storage.objectViewer"
        ],
        "availableResource": "//storage.googleapis.com/projects/_/buckets/example-bucket",
        "availabilityCondition": {
          "expression" : "resource.name.startsWith('projects/_/buckets/example-bucket/objects/customer-a')"
        }
      }
    ]
  }
}

列出对象时限制权限

当您列出 Cloud Storage 存储分区中的对象时,会针对存储分区资源(而不是对象资源)调用方法。因此,如果系统为列出请求计算了条件,并且该条件引用了资源名称,则资源名称将标识存储分区,而不是该存储分区中的对象。例如,当您列出 example-bucket 中的对象时,资源名称为 projects/_/buckets/example-bucket

当您列出对象时,此命名惯例可能会导致意外行为。例如,假设您需要一个凭据访问边界,用于允许查看 example-bucket 中前缀为 customer-a/invoices/ 的对象。您可以尝试在凭据访问边界中使用以下条件:

不完整:仅检查资源名称的条件

resource.name.startsWith('projects/_/buckets/example-bucket/objects/customer-a/invoices/')

此条件适用于读取对象,但不适用于列出对象:

  • 当成员尝试读取 example-bucket 中前缀为 customer-a/invoices/ 的对象时,该条件的计算结果为 true
  • 当成员尝试列出具有该前缀的对象时,该条件的计算结果为 falseresource.name 的值为 projects/_/buckets/example-bucket(没有以 projects/_/buckets/example-bucket/objects/customer-a/invoices/ 开头)。

为了防止此问题,除了使用 resource.name.startsWith() 之外,您的条件还可以检查名为 storage.googleapis.com/objectListPrefixAPI 特性。此特性包含用于过滤对象列表的 prefix 参数的值。因此,您可以编写一个引用 prefix 参数的值的条件。

以下示例展示了如何在条件中使用 API 特性。它允许读取和列出 example-bucket 中前缀为 customer-a/invoices/ 的对象:

完整:检查资源名称和前缀的条件

resource.name.startsWith('projects/_/buckets/example-bucket/objects/customer-a/invoices/')  ||
    api.getAttribute('storage.googleapis.com/objectListPrefix', '')
                     .startsWith('customer-a/invoices/')

现在,您可以在凭据访问边界中使用此条件:

{
  "accessBoundary": {
    "accessBoundaryRules": [
      {
        "availablePermissions": [
          "inRole:roles/storage.objectViewer"
        ],
        "availableResource": "//storage.googleapis.com/projects/_/buckets/example-bucket",
        "availabilityCondition": {
          "expression":
            "resource.name.startsWith('projects/_/buckets/example-bucket/objects/customer-a/invoices/') || api.getAttribute('storage.googleapis.com/objectListPrefix', '').startsWith('customer-a/invoices/')"
        }
      }
    ]
  }
}

准备工作

在使用凭据访问边界之前,请确保满足以下要求:

  • 您需要只针对 Cloud Storage 缩小权限范围,而不对其他 Google Cloud 服务这样做。

    如果您需要缩小针对其他 Google Cloud 服务的权限范围,您可以创建多个服务帐号并为每个服务帐号授予一组不同的角色。

  • 您可以使用 OAuth 2.0 访问令牌进行身份验证。 其他类型的短期有效的凭据不支持凭据访问边界功能。

创建具有缩小的权限范围的短期有效的凭据

要创建具有缩小的权限范围的 OAuth 2.0 访问令牌,请按以下步骤操作:

  1. 向用户或服务帐号授予相应的 IAM 角色
  2. 定义一个凭据访问边界,以设置用户或服务帐号可用权限的上限。
  3. 为用户或服务帐号创建 OAuth 2.0 访问令牌
  4. OAuth 2.0 访问令牌交换遵循凭据访问边界的新令牌。

然后,您可以使用具有缩小的权限范围的新 OAuth 2.0 访问令牌,验证针对 Cloud Storage 的请求的身份。

授予 IAM 角色

凭据访问边界设置了可用于特定资源的权限的上限。它可以删减成员已获取的权限,但无法添加该成员尚未拥有的权限。

因此,您还必须在 Cloud Storage 存储分区上,或更高级别的资源(例如项目)上向成员授予提供所需权限的角色。

例如,假设您需要创建一个具有缩小的权限范围的短期有效的凭据,以允许服务帐号在存储分区中创建对象:

  • 您必须至少向服务帐号授予包含 storage.objects.create 权限的角色,例如 Storage Object Creator 角色 (roles/storage.objectCreator)。凭据访问边界也必须包含此权限。
  • 您还可以授予其包含更多权限的角色,例如 Storage Object Admin 角色 (roles/storage.objectAdmin)。服务帐号只能使用同时出现在角色授权和凭据访问边界中的权限。

如需了解 Cloud Storage 的预定义角色,请参阅 Cloud Storage 角色

定义凭据访问边界

凭据访问边界是包含一系列访问边界规则的 JSON 对象。每条规则都包含以下信息:

  • 应用该规则的资源。
  • 在该资源上可用的权限上限。
  • 可选:进一步限制权限的条件。条件包括以下内容:
    • 计算结果为 truefalse 的条件表达式。如果计算结果为 true,则允许访问;否则拒绝访问。
    • 可选:标识条件的标题。
    • 可选:包含有关条件的更多信息的说明。

如果您将凭据访问边界应用于短期有效的凭据,则该凭据只能访问凭据访问边界中的资源,不能获得在其他资源上可用的权限。

凭证访问边界最多可以包含 10 条访问边界规则。您只能为每个短期有效的凭据应用一个凭据访问边界。

每个凭据访问边界都包含以下字段:

字段
accessBoundary

object

凭据访问边界的容器。

accessBoundary.accessBoundaryRules[]

object

应用于短期有效的凭据的访问边界规则的列表。

accessBoundary.accessBoundaryRules[].availablePermissions[]

string

用于定义对于资源可用的权限上限的列表。

每个值都是一个 IAM 预定义角色自定义角色的标识符,并且带有前缀 inRole:。例如:inRole:roles/storage.objectViewer。只能使用这些角色中的权限。

accessBoundary.accessBoundaryRules[].availableResource

string

应用规则的 Cloud Storage 存储分区的完整资源名称。请使用此格式://storage.googleapis.com/projects/_/buckets/bucket-name

accessBoundary.accessBoundaryRules[].availabilityCondition

object

可选。限制对特定 Cloud Storage 对象的权限可用性的条件。

如果要使权限可用于特定的对象(而不是 Cloud Storage 存储分区中的所有对象),请使用此字段。

accessBoundary.accessBoundaryRules[].availabilityCondition.expression

string

一个条件表达式,用于指定可以使用权限的 Cloud Storage 对象。

如需了解如何在条件表达式中引用特定的对象,请参阅 resource.name 特性

accessBoundary.accessBoundaryRules[].availabilityCondition.title

string

可选。标识条件目的的短字符串。

accessBoundary.accessBoundaryRules[].availabilityCondition.description

string

可选。有关条件目的的详细信息。

如需查看示例,请参阅本页面上的凭据访问边界的示例

创建定义凭据访问边界的 JSON 文件。您将在后面的步骤中使用此文件。

创建 OAuth 2.0 访问令牌

要创建具有缩小的权限范围的短期有效的凭据,您必须先创建一个常规的 OAuth 2.0 访问令牌。然后将常规凭据交换为具有缩小的权限范围的凭据。在创建访问令牌时,请使用 OAuth 2.0 范围 https://www.googleapis.com/auth/cloud-platform

要为服务帐号创建访问令牌,您可以完成服务器到服务器的 OAuth 2.0 流程,或者可以使用 Service Account Credentials API 生成 OAuth 2.0 访问令牌

如需为用户创建访问令牌,请参阅获取 OAuth 2.0 访问令牌。您还可以使用 OAuth 2.0 Playground,为您自己的 Google 帐号创建访问令牌。

交换 OAuth 2.0 访问令牌

创建 OAuth 2.0 访问令牌后,您可以将访问令牌交换为符合凭据访问边界的新令牌。您可以通过 Identity Platform 中的 Security Token Service API 来交换访问令牌。

要交换访问令牌,请使用以下 HTTP 方法和网址:

POST https://sts.googleapis.com/v1beta/token

将请求中的 Content-Type 标头设置为 application/x-www-form-urlencoded。在请求正文中添加以下字段:

字段
grant_type

string

使用 urn:ietf:params:oauth:grant-type:token-exchange 值。

options

string

采用百分比编码的凭据访问边界。

requested_token_type

string

使用 urn:ietf:params:oauth:token-type:access_token 值。

subject_token

string

您想要交换的 OAuth 2.0 访问令牌。

subject_token_type

string

使用 urn:ietf:params:oauth:token-type:access_token 值。

响应是包含以下字段的 JSON 对象:

字段
access_token

string

遵循凭据访问边界的全新 OAuth 2.0 访问令牌。

expires_in

number

新访问令牌到期前的时间量(以秒为单位)。

仅当原始访问令牌代表服务帐号时才会显示此字段。如果此字段不存在,则新访问令牌的到期时间与原始访问令牌的到期时间相同。

issued_token_type

string

包含 urn:ietf:params:oauth:token-type:access_token 值。

token_type

string

包含 Bearer 值。

例如,如果凭据访问边界存储在 ./access-boundary.json 文件中,您可以使用以下 curl 命令交换访问令牌。将 original-token 替换为原始访问令牌:

curl -H "Content-Type:application/x-www-form-urlencoded" \
    -X POST \
    https://sts.googleapis.com/v1beta/token \
    -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token_type=urn:ietf:params:oauth:token-type:access_token&requested_token_type=urn:ietf:params:oauth:token-type:access_token&subject_token=original-token" \
    --data-urlencode "options=$(cat ./access-boundary.json)"

响应类似于以下示例:

{
  "access_token": "ya29.dr.AbCDeFg-123456...",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 3600
}

后续步骤