在 Azure AI 搜索中配置客户管理的密钥以用于数据加密

Azure AI 搜索会自动使用服务管理的密钥加密静态数据。 如果需要更多保护,可以使用在 Azure Key Vault 中创建和管理的密钥,用另一个加密层来补充默认加密。

本文将指导你完成设置客户管理的密钥 (CMK) 或“自带密钥”(BYOK) 加密的步骤。 下面是要记住的一些要点:

  • CMK 加密是对单个对象执行的。 如果需要跨搜索服务使用 CMK,请设置强制策略

  • CMK 加密依赖于 Azure Key Vault。 你可以创建自己的加密密钥并将其存储在密钥保管库中,或使用 Azure Key Vault API 来生成加密密钥。

  • 创建对象时,CMK 加密将开始运行。 不能加密已经存在的对象。 每次将对象保存到磁盘时,就会进行 CMK 加密,无论是用于长期存储的静态数据还是用于短期存储的临时数据。 使用 CMK 时,磁盘永远不会看到未加密的数据。

注意

如果索引已使用 CMK 加密,则仅当搜索服务有权访问密钥时,才能访问该索引。 如果撤销了访问权限,则索引不可用,并且在删除索引或还原对密钥的访问权限之前,服务将无法缩放。

CMK 加密的对象

可加密的对象包括索引、同义词列表、索引器、数据源和技能组。 加密的计算开销高于解密,因此只会加密敏感内容。

加密对以下内容执行:

  • 索引和同义词列表中的所有内容,包括说明。

  • 对于索引器、数据源和技能组,只会加密存储了连接字符串、说明、密钥和用户输入的字段。 例如,技能组有 Azure 认知服务密钥,而某些技能接受用户输入,例如自定义实体。 在这两种情况下,技能中的密钥和用户输入将会进行加密。

先决条件

本方案中使用了以下工具和服务。

你应该有一个可创建加密的对象的搜索客户端。 你需要将密钥保管库密钥和应用程序注册信息引用到此代码中。 此代码可以是某个工作应用,也可以是原型代码,例如 C# 代码示例 DotNetHowToEncryptionUsingCMK

提示

可以使用 REST 客户端Azure PowerShell 创建包含加密密钥参数的索引和同义词映射。 也可以使用 Azure SDK。 不支持在门户中将密钥添加到索引或同义词映射。

Key Vault 提示

如果你不熟悉 Azure Key Vault,请查看以下快速入门来了解基本任务:使用 PowerShell 在 Azure Key Vault 中设置和检索机密。 下面是有关使用 Key Vault 的一些提示:

  • 使用所需数量的密钥保管库。 管理的密钥可以位于不同的密钥保管库中。 一个搜索服务可以有多个已加密的对象,每个对象通过不同密钥保管库中存储的不同客户管理的加密密钥进行加密。

  • 在 Key Vault 上启用日志记录,以便监视密钥使用情况。

  • 请记得在密钥保管库密钥和 Active Directory 应用程序机密的例行轮换期间以及注册期间遵循严格的过程。 在删除旧机密和密钥之前,始终更新所有已加密内容以使用新机密和密钥。 如果缺少此步骤,你的内容将无法解密。

1 - 启用清除保护

首先,请确保在密钥保管库上启用软删除清除保护。 删除你的 Azure Key Vault 密钥后,无人可以检索你的数据,这是使用客户管理的密钥进行的加密的本质决定的。

若要防止意外删除 Key Vault 密钥造成数据丢失,必须在密钥保管库上启用“软删除”和“清除保护”。 默认情况下会启用“软删除”,因此,只有在你特意禁用了此功能时才会遇到问题。 “清除保护”在默认情况下不启用,但它是 Azure AI 搜索中客户管理的密钥加密所必需的。

可以使用门户、PowerShell 或 Azure CLI 命令设置这两项属性。

  1. 登录到 Azure 门户,然后打开密钥保管库概述页面。

  2. 在“概述”页的“概要”下,启用“软删除”和“清除保护”。

2 - 在 Key Vault 中创建密钥

如果 Azure Key Vault 中已包含你要使用的密钥,请跳过密钥生成步骤,但要收集密钥标识符。 创建加密的对象时需要此信息。

  1. 登录到 Azure 门户,然后打开密钥保管库概述页面。

  2. 选择左侧的“密钥”,然后选择“+ 生成/导入”。

  3. 在“创建密钥”窗格中,从“选项”列表中,选择要用于创建密钥的方法。 可以生成新密钥、上传现有密钥,或使用“备份还原”选择密钥的备份。

  4. 输入密钥的名称,并根据需要选择其他密钥属性。

  5. 选择“创建”以开始部署。

  6. 选择密钥,选择当前版本,然后记下密钥标识符。 它由键值 URI、密钥名称和密钥版本组成。 稍后需要使用该标识符在 Azure AI 搜索中定义加密的索引。

    创建新的 Key Vault 密钥

3 - 创建安全主体

在运行时,可以使用多个选项来访问加密密钥。 最简单的方法是使用搜索服务的托管标识和权限来检索密钥。 可以使用系统托管标识或用户管理的标识。 这样做可以省略应用程序注册和应用程序机密的步骤,并简化加密密钥的定义。

或者,可以创建和注册 Microsoft Entra 应用程序。 搜索服务提供请求的应用程序 ID。

搜索服务可以使用托管标识向 Azure Key Vault 进行身份验证,而无需在代码中存储凭据(ApplicationID 或 ApplicationSecret)。 此类托管标识的生命周期与只包含一个托管标识的搜索服务的生命周期密切相关。 若要详细了解托管标识工作原理,请参阅什么是 Azure 资源托管标识?

  1. 使搜索服务成为受信任的服务。

    打开系统分配的托管标识

有一些情况会导致你无法采用这种方法,其中包括:

  • 无法直接授予搜索服务对密钥保管库的访问权限(例如,如果搜索服务与 Azure Key Vault 位于不同的 Microsoft Entra ID 租户中)。

  • 必须使用单个搜索服务来托管多个已加密的索引或同义词映射,其中每个索引/同义词映射使用不同密钥保管库中的不同密钥,而每个密钥保管库必须使用不同的标识进行身份验证。 由于一个搜索服务只能有一个托管标识,因此,如果需要多个标识,则无法对你的方案使用简化的方法。

4 - 授予权限

此步骤将在 Key Vault 中创建一个访问策略。 此策略为已注册到 Microsoft Entra ID 的应用程序提供使用客户管理的密钥的权限。

可在任意给定时间撤销访问权限。 撤销后,使用该 Key Vault 的任何搜索服务索引或同义词映射都将不可用。 以后还原 Key Vault 访问权限会还原索引和同义词映射访问权限。 有关详细信息,请参阅保护对 Key Vault 的访问

  1. 在 Azure 门户中打开密钥保管库“概述”页。

  2. 选择左侧的“访问策略”,然后选择“+ 创建”以启动“创建访问策略”向导。

    创建访问策略。

  3. 在“权限”页上,针对“密钥权限”、“机密权限”和“证书权限”选择“获取”。 选择“解包密钥”和“包装密钥”,以便对密钥执行 ** 加密操作。

    在“权限”页中选择权限。

  4. 选择“下一步”。

  5. 在“原则”页上,找到并选择搜索服务用来访问加密密钥的安全主体。 这将是搜索服务的系统托管标识或用户管理的标识,或已注册的应用程序。

  6. 依次选择“下一步”和“创建”。

重要

Azure AI 搜索中已加密的内容被配置为使用特定版本的特定 Azure 密钥保管库密钥。 如果更改了密钥或版本,必须先更新索引或同义词映射以使用它,然后才能删除前一个密钥或版本。 否则,将无法使用索引或同义词映射。 如果密钥丢失,你将无法解密内容。

5 - 加密内容

创建对象时会添加加密密钥。 若要在索引、同义词映射、索引器、数据源或技能组上添加客户管理的密钥,请使用搜索 REST API 或 Azure SDK 创建已启用加密的对象。 门户不允许在创建对象时有加密属性。

  1. 调用“创建”API 以指定 encryptionKey 属性:

  2. 将 encryptionKey 构造插入到对象定义中。 此属性是一级属性,其级别与名称和说明相同。 以下 REST 示例显示了属性的位置。 如果你使用的是相同的保管库、密钥和版本,可以将相同的“encryptionKey”构造粘贴到每个对象定义中。

    第一个示例展示了使用托管标识连接的搜索服务的“encryptionKey”:

    {
      "encryptionKey": {
        "keyVaultUri": "https://demokeyvault.vault.azure.cn",
        "keyVaultKeyName": "myEncryptionKey",
        "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660"
      }
    }
    

    第二个示例包括“accessCredentials”,这在 Microsoft Entra ID 中注册应用程序时是必需的:

    {
      "encryptionKey": {
        "keyVaultUri": "https://demokeyvault.vault.azure.cn",
        "keyVaultKeyName": "myEncryptionKey",
        "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
        "accessCredentials": {
          "applicationId": "00000000-0000-0000-0000-000000000000",
          "applicationSecret": "myApplicationSecret"
        }
      }
    }
    

在搜索服务上创建加密的对象后,可以像使用其他任何相同类型的对象一样使用它。 加密对于用户和开发人员是透明的。

注意

这些密钥保管库详细信息都不被视为机密,在 Azure 门户中浏览到相关的 Azure Key Vault 页即可轻松检索这些信息。

6 - 设置策略

Azure 策略可帮助实施组织标准并大规模评估合规性。 Azure AI 搜索具有一个可选的适用于服务级 CMK 实施的内置策略

在本部分中,你将设置为搜索服务定义 CMK 标准的策略。 然后,你将设置你的搜索服务来实施此策略。

  1. 在 Web 浏览器中导航到内置策略。 选择“分配”

    分配内置 CMK 策略的屏幕截图。

  2. 设置策略范围。 在“参数”部分中,取消选中“仅显示参数...”并将“效果”设置为拒绝

    在评估请求期间,与拒绝策略定义匹配的请求将被标记为不符合条件。 假设你的服务的标准是 CMK 加密,“拒绝”意味着未指定 CMK 加密的请求不符合条件。

    将内置 CMK 策略效果更改为拒绝的屏幕截图。

  3. 完成策略创建。

  4. 调用服务 - 更新 API 以在服务级别启用 CMK 策略实施。

PATCH https://management.chinacloudapi.cn/subscriptions/[subscriptionId]/resourceGroups/[resourceGroupName]/providers/Microsoft.Search/searchServices/[serviceName]?api-version=2022-11-01

{
    "properties": {
        "encryptionWithCmk": {
            "enforcement": "Enabled",
            "encryptionComplianceStatus": "Compliant"
        }
    }
}

REST 示例

本部分显示了多个对象的 JSON,这样你可以知道要在对象定义中的哪个位置查找“encryptionKey”。

索引加密

创建索引 (REST API) 中详述了如何通过 REST API 创建新索引。唯一的差别在于需要将加密密钥详细信息指定为索引定义的一部分:

{
 "name": "hotels",
 "fields": [
  {"name": "HotelId", "type": "Edm.String", "key": true, "filterable": true},
  {"name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false},
  {"name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.lucene"},
  {"name": "Description_fr", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "fr.lucene"},
  {"name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
  {"name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true},
  {"name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true},
  {"name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true},
  {"name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true},
  {"name": "Location", "type": "Edm.GeographyPoint", "filterable": true, "sortable": true}
 ],
  "encryptionKey": {
    "keyVaultUri": "https://demokeyvault.vault.azure.cn",
    "keyVaultKeyName": "myEncryptionKey",
    "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
    "accessCredentials": {
      "applicationId": "00000000-0000-0000-0000-000000000000",
      "applicationSecret": "myApplicationSecret"
    }
  }
}

现在,可以发送索引创建请求,然后开始正常使用索引。

同义词映射加密

按照创建同义词映射(Azure AI 搜索 REST API)一文的说明创建加密的同义词映射。 使用“encryptionKey”属性指定要使用的加密密钥。

{
  "name" : "synonymmap1",
  "format" : "solr",
  "synonyms" : "China, The People's Republic of China\n
  Beijing",
  "encryptionKey": {
    "keyVaultUri": "https://demokeyvault.vault.azure.cn",
    "keyVaultKeyName": "myEncryptionKey",
    "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
    "accessCredentials": {
      "applicationId": "00000000-0000-0000-0000-000000000000",
      "applicationSecret": "myApplicationSecret"
    }
  }
}

现在,可以发送同义词映射创建请求,然后开始正常使用同义词映射。

数据源加密

使用创建数据源 (REST API) 创建加密的数据源。 使用“encryptionKey”属性指定要使用的加密密钥。

{
  "name" : "datasource1",
  "type" : "azureblob",
  "credentials" :
  { "connectionString" : "DefaultEndpointsProtocol=https;AccountName=datasource;AccountKey=accountkey;EndpointSuffix=core.chinacloudapi.cn"
  },
  "container" : { "name" : "containername" },
  "encryptionKey": {
    "keyVaultUri": "https://demokeyvault.vault.azure.cn",
    "keyVaultKeyName": "myEncryptionKey",
    "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
    "accessCredentials": {
      "applicationId": "00000000-0000-0000-0000-000000000000",
      "applicationSecret": "myApplicationSecret"
    }
  }
}

现在,可以发送数据源创建请求,然后开始正常使用数据源。

技能组加密

使用创建技能组 REST API 创建加密的技能组。 使用“encryptionKey”属性指定要使用的加密密钥。

{
    "name": "skillset1",
    "skills":  [ omitted for brevity ],
    "cognitiveServices": { omitted for brevity },
      "knowledgeStore":  { omitted for brevity  },
    "encryptionKey": (optional) { 
        "keyVaultKeyName": "myEncryptionKey",
        "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
        "keyVaultUri": "https://demokeyvault.vault.azure.cn",
        "accessCredentials": {
            "applicationId": "00000000-0000-0000-0000-000000000000",
            "applicationSecret": "myApplicationSecret"}
    }
}

现在,可以发送技能组创建请求,然后开始正常使用技能组。

索引器加密

使用创建索引器 REST API 创建加密的索引器。 使用“encryptionKey”属性指定要使用的加密密钥。

{
  "name": "indexer1",
  "dataSourceName": "datasource1",
  "skillsetName": "skillset1",
  "parameters": {
      "configuration": {
          "imageAction": "generateNormalizedImages"
      }
  },
  "encryptionKey": {
    "keyVaultUri": "https://demokeyvault.vault.azure.cn",
    "keyVaultKeyName": "myEncryptionKey",
    "keyVaultKeyVersion": "eaab6a663d59439ebb95ce2fe7d5f660",
    "accessCredentials": {
      "applicationId": "00000000-0000-0000-0000-000000000000",
      "applicationSecret": "myApplicationSecret"
    }
  }
}

现在,可以发送索引器创建请求,然后开始正常使用索引器。

重要

尽管无法将“encryptionKey”添加到现有的搜索索引或同义词映射,但可以通过为三项密钥保管库详细信息的任何一项提供不同的值,来更新该属性(例如,更新密钥版本)。 更改为新的 Key Vault 密钥或新的密钥版本时,必须先将使用该密钥的任何搜索索引或同义词映射更新为使用新的密钥/版本,然后删除以前的密钥/版本。 否则会使该索引或同义词映射变得不可用,因为在失去密钥访问权限后无法解密内容。 不过,以后还原密钥保管库访问权限时会还原内容访问权限。

使用加密内容

使用客户管理的密钥加密时,你会注意到,由于额外的加密/解密工作,索引编制和查询都会出现相应的延迟。 Azure AI 搜索不记录加密活动,但你可以通过密钥保管库日志记录功能来监视密钥访问。 建议在配置密钥保管库的过程中启用日志记录

应每隔一段时间就进行密钥轮换。 每当轮换密钥时,请务必遵循此顺序:

  1. 确定索引或同义词映射所使用的密钥
  2. 在密钥保管库中创建新密钥,但保持原始密钥可用。
  3. 更新索引或同义词映射上的 encryptionKey 属性以使用新值。 只有最初创建时带有此属性的对象才能更新为使用其他值。
  4. 禁用或删除密钥保管库中的上一个密钥。 监视密钥访问以验证是否正在使用新密钥。

出于性能方面的原因,搜索服务最多会缓存此密钥几个小时。 如果在不提供新密钥的情况下禁用或删除该密钥,则查询将暂时性地继续工作,直到缓存过期。 但是,一旦搜索服务无法解密内容,你就会收到以下消息:“禁止访问”。 使用的查询键可能已被撤消 - 请重试。”

后续步骤

如果你不熟悉 Azure 安全体系结构,请查看 Azure 安全文档,具体而言,是以下文章: