创建短期有效的服务帐号凭据

本页面介绍了如何为服务帐号创建短期有效凭据来模拟其身份。

服务帐号可以使用短期有效凭据来验证对 Google Cloud API 和其他非 Google API 的调用。短期有效凭据的生命周期有限,持续时间仅为几个小时或更短。如果您需要为信任的服务帐号授予对资源的有限访问权限,则短期有效服务帐号凭据会很有用。与服务帐号密钥等长期有效凭据相比,短期有效凭据还可以降低风险。

支持的凭据类型包括 OAuth 2.0 访问令牌、OpenID Connect ID 令牌、自签名 JSON Web 令牌 (JWT) 和自签名二进制对象 (blob)。最常用的凭据类型是 OAuth 2.0 访问令牌OpenID Connect (OIDC) ID 令牌。以下是一些示例场景:

  • OAuth 2.0 访问令牌:OAuth 2.0 访问令牌可用于向 Google Cloud API 验证服务帐号的身份。请考虑以下示例用例:为了获得对项目的提升权限,服务管理员可以创建属于某个服务帐号的 OAuth 2.0 访问令牌,以模拟该服务帐号来调用 Google Cloud API。该令牌的生命周期很短,因此提升的权限是临时性的。当生产环境中出现紧急情况,使服务管理员需要使用临时提升的授权来进行调试时,此令牌尤其有用。

  • OIDC ID 令牌:OIDC ID 令牌可用于向接受 OpenID Connect 的服务验证服务帐号的身份。 请考虑以下示例用例:通过创建属于某个服务帐号的 OIDC ID 令牌,在 Google Cloud 上运行的服务可以向第三方云服务提供程序上部署的其他服务(例如数据流水线作业)验证自己的身份。如果目标服务配置了 OIDC,则身份验证会成功。

准备工作

创建服务帐号

首先,请创建一个新的服务帐号

授予必要权限

调用者可以使用两种不同的流程为服务帐号创建短期有效凭据。每种流程都需要具备相应权限:

  • 直接请求:调用者被验证为 Google 帐号或服务帐号,并直接发出创建短期有效凭据的请求。此流程涉及两种身份:调用者以及为其创建凭据的服务帐号。
  • 委托请求:与直接请求流程一样,调用者被验证为 Google 帐号或服务帐号,但会将请求委托给委托链中的一个或多个服务帐号。在此流程中,多个服务帐号会充当原始调用者与为其创建凭据的服务帐号之间的中介。委托链中的每个服务帐号都必须具有传递请求所需的权限。

    当项目包含多个层级的权限有限的服务帐号,且每个层级都配置为对特定资源执行特定或有限的功能时,此流程很有用。例如,一个服务帐号仅被授予对 Cloud Storage 资源的权限,另一个服务帐号仅被授予对 Compute Engine 资源的权限,等等。如需成功跨多个服务帐号委托请求,必须在委托链中列出每个服务帐号。

直接请求权限

如本页面上的授予必要权限所述,直接请求仅涉及两种身份:调用者以及为其创建凭据的服务帐号。在此流程中,请考虑使用以下身份:

  • 服务帐号 1 (sa-1):发出短期有效凭据请求的调用者。
  • 服务帐号 2 (sa-2):为其创建凭据的权限有限的帐号。

如需授予 sa-1 创建短期有效凭据的权限,请在 sa-2 上为其授予 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)。这是一个将服务帐号视为资源而非身份的示例:必须授予 sa-1sa-2 签发凭据的权限。如需详细了解如何将服务帐号视为身份或资源,请参阅服务帐号权限

以下步骤使用 REST API 来授予所需的权限,但您也可以使用 Cloud Console 或 gcloud 命令行工具进行授权。

API

首先,请阅读 sa-2 的 IAM 政策

如需了解详情,请参阅 serviceAccounts.getIamPolicy() 参考文档。

请求:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-2@project-id.iam.gserviceaccount.com:getIamPolicy

响应:

{
  "etag": "BwUqLaVeua8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
          "user:my-user@example.com"
      ]
    }
  ]
}

如果您尚未将角色分配给服务帐号,则响应将只包含 etag 值。请在下一步中添加该 etag 值。

接下来,请修改政策以授予 sa-1 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)

{
  "policy": {
    "etag": "BwUqLaVeua8=",
    "bindings": [
      {
        "role": "roles/iam.serviceAccountUser",
        "members": [
          "user:my-user@example.com"
        ]
      },
      {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
          "serviceAccount:sa-1@project-id.iam.gserviceaccount.com"
        ]
      }
    ]
  }
}

最后,请写入更新后的政策

发出 serviceAccounts.setIamPolicy() 请求(更新后的政策作为请求正文):

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-2@project-id.iam.gserviceaccount.com:setIamPolicy

响应中包含更新后的政策:

{
  "etag": "BwUqMqbViM8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
        "user:my-user@example.com"
      ]
    },
    {
      "role": "roles/iam.serviceAccountTokenCreator",
      "members": [
        "serviceAccount:sa-1@project-id.iam.gserviceaccount.com"
      ]
    }
  ]
}

委托请求权限

如本页面上的授予必要权限所述,委托请求涉及的身份超过两种:调用者、委托链中的一个或多个服务帐号,以及当前的服务帐号。在此流程中,请考虑使用以下身份:

  • 服务帐号 1 (sa-1):发出短期有效凭据请求的调用者。
  • 服务帐号 2 (sa-2):中间服务帐号,将初始请求委托给 sa-3
  • 服务帐号 3 (sa-3):为其创建凭据的权限有限的帐号。

如需允许委托,则每个帐号必须向委托链中的前一个帐号授予 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)。

在此特定示例中,必须在 sa-2 上授予 sa-1 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)。这是一个将服务帐号视为资源而非身份的示例:必须授予 sa-1sa-2 委托访问权限的权限。如需详细了解如何将服务帐号视为身份或资源,请参阅服务帐号权限

在此示例流程中,只有一个中间服务帐号。要通过多个服务帐号委托访问权限,您还必须将此角色分配给委托链中的任何其他服务帐号。

接下来,您还必须在 sa-3 上授予 sa-2 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)。这样,sa-2 就能为 sa-3 创建短期有效凭据。

以下步骤使用 REST API 来授予所需的权限,但您也可以使用 Cloud Console 或 gcloud 命令行工具进行授权。

API

首先,请获取 sa-2(中间服务帐号)的 IAM 政策

如需了解详情,请参阅 serviceAccounts.getIamPolicy() 参考文档。

请求:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-2@project-id.iam.gserviceaccount.com:getIamPolicy

响应:

{
  "etag": "BwUqLaVeua8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
          "user:my-user@example.com"
      ]
    }
  ]
}

如果您尚未将角色分配给服务帐号,则响应将只包含 etag 值。请在下一步中添加该 etag 值。

接下来,请修改政策以授予 sa-1 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator)

{
  "policy": {
    "etag": "BwUqLaVeua8=",
    "bindings": [
      {
        "role": "roles/iam.serviceAccountUser",
        "members": [
          "user:my-user@example.com"
        ]
      },
      {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
          "serviceAccount:sa-1@project-id.iam.gserviceaccount.com"
        ]
      }
    ]
  }
}

然后,请写入 sa-2 的更新政策

使用更新后的政策执行 serviceAccounts.setIamPolicy() 请求:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-2@project-id.iam.gserviceaccount.com:setIamPolicy

响应中包含更新后的政策:

{
  "etag": "BwUqMqbViM8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
        "user:my-user@example.com"
      ]
    },
    {
      "role": "roles/iam.serviceAccountTokenCreator",
      "members": [
        "serviceAccount:sa-1@project-id.iam.gserviceaccount.com"
      ]
    }
  ]
}

现在,请获取 sa-3(为其创建凭据的服务帐号)的 IAM 政策

请求:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-3@project-id.iam.gserviceaccount.com:getIamPolicy

响应:

{
  "etag": "BwUqLaVeua8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
        "user:my-user@example.com"
      ]
    }
  ]
}

如果您尚未将角色分配给服务帐号,则响应将只包含 etag 值。请在下一步中添加该 etag 值。

接下来,请修改政策以授予 sa-2 roles/iam.serviceAccountTokenCreator 角色

{
  "policy": {
    "etag": "BwUqLaVeua8=",
    "bindings": [
      {
        "role": "roles/iam.serviceAccountUser",
        "members": [
          "user:my-user@example.com"
        ]
      },
      {
        "role": "roles/iam.serviceAccountTokenCreator",
        "members": [
          "serviceAccount:sa-2@project-id.iam.gserviceaccount.com"
        ]
      }
    ]
  }
}

最后,请写入更新后的政策

使用更新后的政策执行 serviceAccounts.setIamPolicy() 请求:

POST https://iam.googleapis.com/v1/projects/-/serviceAccounts/sa-3@project-id.iam.gserviceaccount.com:setIamPolicy

响应中包含更新后的政策:

{
  "etag": "BwUqMqbViM8=",
  "bindings": [
    {
      "role": "roles/iam.serviceAccountUser",
      "members": [
        "user:my-user@example.com"
      ]
    },
    {
      "role": "roles/iam.serviceAccountTokenCreator",
      "members": [
        "serviceAccount:sa-2@project-id.iam.gserviceaccount.com"
      ]
    }
  ]
}

请求短期有效凭据

为每种身份授予适当的权限后,您便可以请求属于所需服务帐号的短期有效凭据。系统支持以下几种凭据类型:

如需了解如何为这些请求指定委托链,请参阅本页面上的指定委托链部分。

生成 OAuth 2.0 访问令牌

默认情况下,OAuth 2.0 访问令牌的有效期最长为 1 小时(3600 秒)。不过,您可以将这些令牌的最长生命周期延长至 12 小时(43200 秒)。为此,请确定需要延长令牌有效期的服务帐号,然后将这些服务帐号添加到包含 constraints/iam.allowServiceAccountCredentialLifetimeExtension 列表限制条件的组织政策中。随后,您在为这些服务帐号创建令牌时,可以指定最长为 43200 秒的生命周期。

如需为服务帐号生成 OAuth 2.0 访问令牌,请执行以下操作:

API

执行 generateAccessToken 请求,其中 sa-4@project-id.iam.gserviceaccount.com 是为其创建令牌的服务帐号的名称。

必须通过在请求的 Authorization 标头中包含访问令牌来验证请求。如需详细了解如何获取访问令牌以调用 Google API,请参阅主题 OAuth 2.0 概览适用于服务帐号的 OAuth 2.0

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-4@project-id.iam.gserviceaccount.com:generateAccessToken

在请求正文中指定以下字段:

{
  "delegates": [],
  "scope": [
    "https://www.googleapis.com/auth/cloud-platform"
  ],
  "lifetime": "300s"
}

上述各字段及其示例值的说明如下:

如果 generateAccessToken 请求成功,响应正文会包含一个 OAuth 2.0 访问令牌和一个到期时间:

{
   "accessToken": "eyJ0eXAi...NiJ9",
   "expireTime": "2020-04-07T15:01:23.045123456Z"
}

然后,便可以使用 accessToken 代表服务帐号验证请求,直至到达 expireTime 时限。

生成 OpenID Connect ID 令牌

OpenID Connect ID 令牌的有效期为 1 小时(3600 秒)。如需为服务帐号生成 ID 令牌,请执行以下操作:

API

执行 generateIdToken 请求,其中 sa-4@project-id.iam.gserviceaccount.com 是为其创建令牌的服务帐号的名称。

必须通过在请求的 Authorization 标头中包含访问令牌来验证请求。如需详细了解如何获取访问令牌以调用 Google API,请参阅主题 OAuth 2.0 概览适用于服务帐号的 OAuth 2.0

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-4@project-id.iam.gserviceaccount.com:generateIdToken

在请求正文中指定以下字段:

{
  "delegates": [],
  "audience": "sa-4@project-id.iam.gserviceaccount.com",
  "includeEmail": "true"
}

上述各字段及其示例值的说明如下:

  • delegates[]:如果您使用的是委托请求流程,请参阅本页面上的指定委托链部分。如果您使用的是没有委托的直接请求流程,请在请求正文中省略 delegates[] 字段。
  • audience:服务的网址或为其创建凭据的服务帐号的电子邮件地址。例如:

    {
      "audience": "sa-4@project-id.iam.gserviceaccount.com"
    }
    
  • includeEmail:如果设置为 true,则 ID 令牌中的 email 声明将包含服务帐号的电子邮件地址。此外,email_verified 声明将设置为 true 且包含在 ID 令牌中。例如:

    {
      "includeEmail": true
    }
    

如果 generateIdToken 请求成功,则响应正文会包含一个有效期为 1 小时的 ID 令牌:

{
  "token": "eyJ0eXAi...NiJ9"
}

然后,便可以使用 token 代表服务帐号验证请求。

创建自签名 JSON Web 令牌 (JWT)

自签名 JWT 在各种场景中都很有用,例如:

  • 按照 Google 的身份验证指南中的说明验证对 Google API 的调用。
  • 在 Google Cloud 或非 Google 服务(例如 App Engine 应用)之间安全地进行通信。在此场景中,一个应用可对一个令牌签名,而在进行身份验证时,该令牌可以由另一个应用进行验证。
  • 通过签署包含有关用户、帐号或设备的任意声明的 JWT,将服务帐号视为身份提供方。

如需为服务帐号生成自签名 JSON Web 令牌 (JWT),请执行以下操作:

API

执行 signJwt 请求,其中 sa-4@project-id.iam.gserviceaccount.com 是为其创建 JWT 的服务帐号的名称。

必须通过在请求的 Authorization 标头中包含访问令牌来验证请求。如需详细了解如何获取访问令牌以调用 Google API,请参阅主题 OAuth 2.0 概览适用于服务帐号的 OAuth 2.0

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-4@project-id.iam.gserviceaccount.com:signJwt

在请求正文中指定以下字段:

{
  "delegates": [],
  "payload": "{ \"iss\": \"sa-4@project-id.iam.gserviceaccount.com\", \"sub\": \"sa-4@project-id.iam.gserviceaccount.com\", \"aud\": \"https://firestore.googleapis.com/google.firestore.v1.Firestore\", \"iat\": 1529350000, \"exp\": 1529353600 }"
}

上述各字段及其示例值的说明如下:

  • delegates[]:如果您使用的是委托请求流程,请参阅本页面上的指定委托链部分。如果您使用的是没有委托的直接请求流程,请在请求正文中省略 delegates[] 字段。
  • payload:需要签名的 JWT 负载,它是一个包含 JWT 声明集的 JSON 对象。包含您所需用例必需的且满足下游服务验证要求必需的声明。 如果您要调用 Google API,请参阅 Google 的身份验证指南了解声明要求。

    exp(到期时间)声明必须设置为不超过未来 12 小时,否则将无法验证。如果 JWT 将用于调用 Google API,则 exp 声明必须设置为不超过 1 小时。

    以下示例声明集包含调用 Google API 的示例声明,最长生命周期为 1 小时(3600 秒):

    {
      "payload": "{ \"iss\": \"sa-4@project-id.iam.gserviceaccount.com\", \"sub\": \"sa-4@project-id.iam.gserviceaccount.com\", \"aud\": \"https://firestore.googleapis.com/google.firestore.v1.Firestore\", \"iat\": 1529350000, \"exp\": 1529353600 }"
    }
    

如果 signJwt 请求成功,则响应正文会包含已签名的 JWT 以及用于签署 JWT 的签名密钥 ID。令牌在请求中指定的到期时间内有效:

{
  "keyId": "42ba1e...fc0a",
  "signedJwt": "eyJ0eXAi...NiJ9"
}

然后,便可以将 signedJwt 值用作不记名令牌,以代表服务帐号直接验证请求。

创建自签名 blob

当您需要安全地传输任意二进制数据时,自签名 blob 非常有用,通常可用于进行身份验证。例如,如果要使用自定义协议/令牌类型(而不是 JWT),您可以将该数据包含在已签署的 blob 中,以供下游服务使用。

如需为服务帐号生成自签名 blob,请执行以下操作:

API

执行 signBlob 请求,其中 sa-4@project-id.iam.gserviceaccount.com 是为其创建 blob 的服务帐号的名称。

必须通过在请求的 Authorization 标头中包含访问令牌来验证请求。如需详细了解如何获取访问令牌以调用 Google API,请参阅主题 OAuth 2.0 概览适用于服务帐号的 OAuth 2.0

POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-4@project-id.iam.gserviceaccount.com:signBlob

在请求正文中指定以下字段:

{
  "delegates": [],
  "payload": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"
}

上述各字段及其示例值的说明如下:

  • delegates[]:如果您使用的是委托请求流程,请参阅本页面上的指定委托链部分。如果您使用的是没有委托的直接请求流程,请在请求正文中省略 delegates[] 字段。
  • payload:Base64 编码的字节串。例如:

    {
      "payload": "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cu"
    }
    

如果 signBlob 请求成功,则响应正文会包含已签名的 blob 以及用于签署 blob 的签名密钥 ID。令牌在请求中指定的到期时间内有效:

{
  "keyId": "42ba1e...fc0a",
  "signedBlob": "eyJ0eXAi...NiJ9"
}

指定委托链

使用委托请求流程创建短期服务帐号凭据时,每个 API 的请求正文都必须以正确的顺序按以下格式指定服务帐号委托链:

projects/-/serviceAccounts/account-email-or-unique-id

例如,在从 sa-1(调用者)流向 sa-2(受委托帐号)到 sa-3(受委托帐号)再到 sa-4 的委托链中,delegates[] 字段将按以下顺序包含 sa-2sa-3

{
  "delegates": [
    "projects/-/serviceAccounts/sa-2@project-id.iam.gserviceaccount.com",
    "projects/-/serviceAccounts/sa-3@project-id.iam.gserviceaccount.com"
  ]
}

调用者以及为其创建凭据的服务帐号不包含在委托链中。