你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 web 服务的 OAuth 2.0 代理刷新令牌

Azure CLI
Azure DevOps
Azure Functions
Azure Key Vault
Azure Pipelines

开发 Web 服务时,可能需要使用 OAuth 2.0 代理 (OBO) 流获取令牌。 OBO 流适用于这样的用例:其中一个应用程序调用某个服务或 Web API,而后者又需要调用另一个服务或 Web API。 OBO 通过请求链传播委托用户权标识和权限。 当应用程序需要无限期地使用访问令牌和刷新令牌时(通常在脱机访问方案中)时,安全存储刷新令牌至关重要。

警告

请仔细考虑存储任何安全令牌所涉及的风险和责任,因为这些令牌可能使恶意执行组件能够访问受组织 Microsoft Entra ID 保护的资源。 针对任何组织目录(任何 Microsoft Entra 目录 - 多租户)中的帐户的应用程序安全漏洞可能特别具有灾难性。

存储访问令牌会带来更大的安全风险,因为其中的访问令牌及本身可以访问资源。 建议的方法不是存储访问令牌,而是根据需要获取访问令牌。 仅安全存储刷新令牌,其严格程度与访问令牌一样。

如有必要,可以在遭到入侵时撤销刷新令牌

可能的用例

此解决方案使用 Azure Key Vault、Azure Functions 和 Azure DevOps 来安全地更新和存储 OBO 刷新令牌。

体系结构

密钥和令牌刷新过程的示意图。

下载此体系结构的 Visio 文件

数据流

  • Azure Key Vault 保存每个 Microsoft Entra ID 租户的机密加密密钥。
  • Azure Functions 计时器触发的函数从 Key Vault 获取最新的密钥。 另一个 Azure Functions 函数从 Microsoft 标识平台检索刷新令牌,然后使用最新的密钥版本保存该令牌。
  • 数据库存储最新的加密密钥和不透明数据。
  • Azure DevOps 持续交付管道管理并同步机密轮换和令牌刷新过程。

如果已将管道用于基础结构即代码 (IaC) 或持续集成和交付 (CI/CD),则 Azure Pipelines 是添加密钥轮换策略的方便位置。 无需使用 Azure Pipelines,只要限制用于设置和检索机密的路径即可。

应用以下策略以允许 Azure DevOps 服务连接的服务主体在Key Vault 中设置保密。 将 <Key Vault Name><Service Connection Principal> 变量替换为环境的正确值。

az keyvault set-policy --name $<Key Vault Name> --spn $<Service Connection Principal> --secret-permissions set

设置 Azure Pipelines 创建和更新密钥后,可以计划管道定期运行。 管道将更新 Key Vault 密钥以与密钥轮换同步,并使用新的机密版本保存加密令牌。 有关详细信息,请参阅配置管道的计划

托管标识

Azure 服务(例如 Azure Functions)访问 Key Vault 的首选方法是使用服务的托管标识。 可以通过 Azure 门户、Azure CLI 或 Azure 资源管理器 (ARM) 模板为 IaC 方案授予访问权限。

Azure 门户

在 Azure 门户,添加 Key Vault 访问策略,以允许 Azure Functions 标识对象 ID 获取和设置机密。 有关详细信息,请参阅添加系统分配的标识使用应用服务和 Azure Functions 的 Key Vault 引用

屏幕截图显示如何在 Azure 门户中启用托管标识。

Azure CLI

还可使用 Azure CLI 设置 Azure Key Vault 策略:

az keyvault set-policy --name $<Key Vault Name> --spn $<Service Connection Principal> --secret-permissions set
az keyvault set-policy --name $<Key Vault Name> --spn $<Managed Identity Principal> --secret-permissions get

ARM 模板

以下 ARM 模板授予 Azure Functions 对 Azure Key Vault 的访问权限。 将 *** 变量替换为环境的正确值。

{
  "type": "Microsoft.KeyVault/vaults",
  "apiVersion": "2019-09-01",
  "name": "***",
  "location": "***",
  "properties": {
    "sku": {
      "family": "A",
      "name": "standard"
    },
    "tenantId": "***",
    "enableSoftDelete": true,
    "enabledForDeployment": false,
    "enabledForTemplateDeployment": false,
    "enabledForDiskEncryption": false,
    "accessPolicies": [
      {
        "tenantId": "***",
        "objectId": "<Managed Identity Principal>",
        "permissions": {
          "secrets": [
            "get"
          ]
        }
      },
      {
        "tenantId": "***",
        "objectId": "<Service Connection Principal>",
        "permissions": {
          "secrets": [
            "set"
          ]
        }
      }
    ]
  }
}

令牌存储

可以使用任何数据库以加密形式存储令牌。 下图显示了在数据库中存储刷新令牌的序列:

添加令牌序列的示意图。

序列有两个函数:userId()secretId()。 可以将这些函数定义为 token.oidtoken.tidtoken.sub 的某种组合。 有关详细信息,请参阅使用 id_token

将加密密钥存储为机密后,可以在 Azure Key Vault 中查找密钥的最新版本。

令牌使用情况

使用密钥非常简单。 以下序列根据最新的密钥版本查询密钥。

存储的令牌使用情况序列的示意图。

令牌刷新与 DoWork 函数正交,因此 Azure Functions 使用 Durable Functions 异步执行 DoWork 和令牌刷新。 有关具有持久函数的 HTTP 触发函数的详细信息,请参阅 HTTP 功能

不建议在 HTTP 请求管道中使用 Azure Key Vault,因此请尽可能缓存响应。 在示例中,Key Vault 对 getSecret(secretId, secretVersion) 调用的响应可缓存。

密钥轮换和令牌刷新

可以在刷新令牌的同时轮换密钥,以便使用最新版本的加密机密对最新令牌进行加密。 此进程使用内置 Azure Functions 计时器触发器支持。 有关详细信息,请参阅适用于 Azure Functions 的计时器触发器

以下序列图演示了将令牌刷新与密钥轮换同步的过程:

使用密钥轮换同步令牌刷新序列的示意图。

用户和访问控制

Microsoft 标识平台提供在泄露时撤销刷新令牌的功能。 请参阅令牌撤销Revoke-AzureADUserAllRefreshToken

注意

自 2024 年 3 月 30 日起,Azure AD 和 MSOnline PowerShell 模块已弃用。 若要了解详细信息,请阅读有关弃用的更新。 在此日期之后,对这些模块的支持仅限于到 Microsoft Graph PowerShell SDK 的迁移帮助和安全性修复。 弃用的模块将持续运行至 2025 年 3 月 30 日。

我们建议迁移到 Microsoft Graph PowerShell,以便与 Microsoft Entra ID(以前称为 Azure AD)进行交互。 有关常见迁移问题,请参阅迁移常见问题解答注意:2024 年 6 月 30 日之后,MSOnline 版本 1.0.x 可能会遇到中断。

若要从 Microsoft Entra ID 中删除用户,只需删除该用户的记录。 若要删除每个用户的应用程序访问权限,请删除用户数据的 refreshToken 部分。

若要删除一组用户(例如目标租户中的所有用户)的访问权限,可以使用 Azure Pipelines 基于 secretId() 删除组的机密。

作者

本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。

首席作者:

后续步骤