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

创建用于部署使用客户管理密钥加密存储帐户的 Azure 托管应用程序

本文介绍如何创建使用客户管理的密钥加密的存储帐户的 Azure 托管应用程序。 存储帐户、Cosmos DB 和 Azure Database for Postgres 支持使用客户管理的密钥或Microsoft管理的密钥进行静态数据加密。 可以使用自己的加密密钥来保护存储帐户中的数据。 指定客户托管密钥时,该密钥用于保护和控制对数据加密密钥的访问。 客户管理的密钥提供更大的灵活性来管理访问控制。

先决条件

托管标识

要为通过托管应用程序部署的存储帐户配置客户管理的密钥,并将其作为托管资源组中的资源,需要用户分配的托管身份。 此用户分配的托管标识可用于向托管应用程序授予对其他现有资源的访问权限。 若要了解如何使用用户分配的托管标识配置托管应用程序,请转到 具有托管标识的 Azure 托管应用程序

你的应用程序可以被授予两种类型的标识:

  • 系统分配的托管标识将分配给应用程序,如果应用被删除,则会将其删除。 应用只能有一个系统分配的托管标识。
  • 用户分配的托管标识是可以分配给应用的独立 Azure 资源。 应用可以具有多个用户分配的管理标识。

若要在托管应用程序的托管资源组中部署存储帐户,该资源组使用现有密钥保管库中的客户密钥加密,需要更多配置。 针对有权访问密钥保管库的托管标识,使用托管应用程序配置的托管标识需要其内置的 Azure 基于角色的访问控制“托管标识操作员”。 更多详细信息,请参阅 托管标识操作员角色

创建具有清除保护的密钥保管库

  1. 登录到 Azure 门户
  2. 在 Azure 门户菜单或“主页”中,选择“创建资源”
  3. 在“搜索”框中,输入 Key Vault
  4. 在结果列表中,选择 Key Vault
  5. “Key Vault ”部分中,选择“ 创建”。
  6. 在“创建密钥保管库”部分中,提供以下信息:
    • 订阅:选择自己的订阅。
    • 资源组:选择 “新建 ”并输入类似于 demo-cmek-rg 的名称。
    • 名称:需要唯一名称,例如 demo-keyvault-cmek
    • 区域:选择美国东部等位置。
    • 定价层:从下拉列表中选择 “标准 ”。
    • 清除保护:选择 “启用清除保护”。
  7. 选择 “下一步 ”,然后转到 “访问策略 ”选项卡。
    • 访问配置:选择 Azure 基于角色的访问控制
    • 接受所有其他选项的默认值。
  8. 选择“查看 + 创建”
  9. 确认设置正确,然后选择“ 创建”。

成功部署后,选择“ 转到资源”。 在“ 概述 ”选项卡上,记下以下属性:

  • 保管库名称:在此示例中,保管库名称为 demo-keyvault-cmek。 你在其它步骤中使用这个名称。
  • 保管库 URI:在此示例中,保管库 URI 为 https://demo-keyvault-cmek.vault.azure.net/

创建用户分配的托管标识

若要创建用户分配的托管标识,帐户需要托管标识参与者角色分配。

  1. 在搜索框中,输入 托管身份
  2. 在“服务”下,选择“托管身份”。
  3. 选择“ 创建 ”并在“ 基本信息 ”选项卡上输入以下值:
    • 订阅:选择自己的订阅。
    • 资源组:选择在前面的步骤中创建的资源组 demo-cmek-rg
    • 区域:选择美国东部等区域。
    • 名称:输入用户分配的托管标识的名称,例如 demokeyvaultmi
  4. 选择“查看 + 创建”
  5. 显示 验证通过 后,选择“ 创建”。

成功部署后,选择“ 转到资源”。

创建角色分配

需要为密钥保管库创建两个角色分配。 有关详细信息,请参阅 使用 Azure 门户分配 Azure 角色

向托管标识授予密钥保管库的密钥权限

为密钥保管库托管标识 demokeyvaultmi 创建角色分配以包装和解包密钥。

  1. 前往密钥库 demo-cmek-keyvault
  2. 选择“访问控制(IAM)”
  3. 选择添加>添加角色分配
  4. 分配以下角色:
    • 角色:Key Vault 加密服务加密用户
    • 分配访问权限:托管身份
    • 成员demokeyvaultmi
  5. 选择 “查看 + 分配 ”以查看设置。
  6. 选择 “查看 + 分配 ”以创建角色分配。

为帐户创建角色分配

创建另一个角色分配,以便帐户可以在密钥保管库中创建新密钥。

  1. 分配以下角色:
    • 角色:Key Vault 加密官
    • 分配访问权限:用户、组或服务主体
    • 成员:你的 Microsoft Entra 帐户
  2. 选择 “查看 + 分配 ”以查看设置。
  3. 选择 “查看 + 分配 ”以创建角色分配。

可以在 访问控制(IAM)>角色分配中验证密钥保管库的角色分配。

创建密钥

您需要创建一个密钥,让您的密钥保管库用它来加密存储帐户。

  1. 转到密钥保管库 demo-cmek-keyvault
  2. 选择 密钥
  3. 选择“生成/导入”。
  4. “创建密钥 ”页上,选择以下值:
    • 选项:生成
    • 名称demo-cmek-key
  5. 接受其他选项的默认值。
  6. 选择 创建

记下密钥名称。 部署托管应用程序时,可以使用它。

为托管应用程序创建用户分配的托管标识

创建用户分配的托管标识,用作托管应用程序的托管标识。

  1. 在搜索框中输入“托管标识”
  2. 在“服务”下,选择“托管身份”。
  3. 选择 创建
    • 订阅:选择自己的订阅。
    • 资源组:选择资源组 demo-cmek-rg
    • 区域:选择美国东部等区域。
    • 名称:输入用户分配的托管标识的名称,例如 demomanagedappmi
  4. 选择“查看 + 创建”
  5. 显示 验证通过 后,选择“ 创建”。

成功部署后,选择“ 转到资源”。

为托管标识分配角色权限

在名为 demokeyvaultmi 的用户分配的托管标识的范围内,将托管标识操作员角色分配给托管标识。

  1. 转到名为 demokeyvaultmi 的用户指定的托管标识。
  2. 选择 “访问控制”(IAM)。
  3. 选择“添加”>“添加角色分配”,打开“添加角色分配”页面。
  4. 分配以下角色。
    • 角色:托管标识操作员
    • 分配访问权限:托管身份
    • 成员demomanagedappmi
  5. 选择 “查看 + 分配 ”以查看设置。
  6. 选择 “查看 + 分配 ”以创建角色分配。

可以在访问控制(IAM)>中验证 demokeyvaultmi 的角色分配。

示例托管应用程序模板

创建一个托管应用程序,该应用程序在托管资源组中部署存储帐户,并使用预先存在的密钥保管库的密钥来加密存储帐户中的数据。

若要将托管应用程序发布到服务目录,请执行以下任务:

  1. 从本文中的示例创建 creatUIDefinition.json 文件。 该模板在部署托管应用程序时定义门户的用户界面元素。
  2. 通过将本文中的 Bicep 文件转换为 JSON,创建名为 mainTemplate.json 的 Azure 资源管理器模板。 该模板定义使用托管应用程序部署的资源。
  3. 创建包含所需 JSON 文件的 .zip 包: createUiDefinition.jsonmainTemplate.json
  4. 发布托管应用程序定义,使其在服务目录中可用。 有关详细信息,请转到 快速入门:创建和发布 Azure 托管应用程序定义

创建模板 createUiDefinition.json

以下模板为托管应用程序创建用户分配的托管标识。 在此示例中,将禁用系统分配的托管标识,因为需要提前使用密钥保管库托管标识的托管标识操作员权限来配置用户分配的托管标识。

  1. 在名为 creatUIDefinition.json的 Visual Studio Code 中创建一个新文件。
  2. 将以下代码复制并粘贴到文件中。
  3. 保存文件。
{
  "$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
  "handler": "Microsoft.Azure.CreateUIDef",
  "version": "0.1.2-preview",
  "parameters": {
    "basics": [],
    "steps": [
      {
        "name": "managedApplicationSetting",
        "label": "Application Settings",
        "subLabel": {
          "preValidation": "Configure your application settings and Managed Identity for the application",
          "postValidation": "Done"
        },
        "bladeTitle": "Application Settings - Config",
        "elements": [
          {
            "name": "appIdentity",
            "type": "Microsoft.ManagedIdentity.IdentitySelector",
            "label": "Managed Identity Configuration for the Application (Needs Managed Identity Operator permissions over KV Managed Identity).",
            "toolTip": {
              "systemAssignedIdentity": "Enable system assigned identity to grant the managed application access to additional existing resources.",
              "userAssignedIdentity": "Add user assigned identities to grant the managed application access to additional existing resources."
            },
            "defaultValue": {
              "systemAssignedIdentity": "Off"
            },
            "options": {
              "hideSystemAssignedIdentity": true,
              "hideUserAssignedIdentity": false,
              "readOnlySystemAssignedIdentity": true
            },
            "visible": true
          }
        ]
      },
      {
        "name": "configuration",
        "type": "Microsoft.Common.Section",
        "label": "Configuration",
        "elements": [
          {
            "name": "cmek",
            "type": "Microsoft.Common.Section",
            "label": "Customer Managed Encryption Key (CMEK)",
            "elements": [
              {
                "name": "cmekEnable",
                "type": "Microsoft.Common.CheckBox",
                "label": "Enable CMEK",
                "toolTip": "Enable to provide a CMEK",
                "constraints": {
                  "required": false
                }
              },
              {
                "name": "cmekKeyVaultUrl",
                "type": "Microsoft.Common.TextBox",
                "label": "Key Vault URL",
                "toolTip": "Specify the CMEK Key Vault URL",
                "defaultValue": "",
                "constraints": {
                  "required": "[steps('configuration').cmek.cmekEnable]",
                  "regex": ".*",
                  "validationMessage": "The value must not be empty."
                },
                "visible": "[steps('configuration').cmek.cmekEnable]"
              },
              {
                "name": "cmekKeyName",
                "type": "Microsoft.Common.TextBox",
                "label": "Key Name",
                "toolTip": "Specify the key name from your key vault.",
                "defaultValue": "",
                "constraints": {
                  "required": "[steps('configuration').cmek.cmekEnable]",
                  "regex": ".*",
                  "validationMessage": "The value must not be empty."
                },
                "visible": "[steps('configuration').cmek.cmekEnable]"
              },
              {
                "name": "cmekKeyIdentity",
                "type": "Microsoft.ManagedIdentity.IdentitySelector",
                "label": "Managed Identity Configuration for Key Vault Access",
                "toolTip": {
                  "systemAssignedIdentity": "Enable system assigned identity to grant the managed application access to additional existing resources.",
                  "userAssignedIdentity": "Add user assigned identities to grant the managed application access to additional existing resources."
                },
                "defaultValue": {
                  "systemAssignedIdentity": "Off"
                },
                "options": {
                  "hideSystemAssignedIdentity": true,
                  "hideUserAssignedIdentity": false,
                  "readOnlySystemAssignedIdentity": true
                },
                "visible": "[steps('configuration').cmek.cmekEnable]"
              }
            ],
            "visible": true
          }
        ]
      }
    ],
    "outputs": {
      "location": "[location()]",
      "managedIdentity": "[steps('managedApplicationSetting').appIdentity]",
      "cmekConfig": {
        "kvUrl": "[if(empty(steps('configuration').cmek.cmekKeyVaultUrl), '', steps('configuration').cmek.cmekKeyVaultUrl)]",
        "keyName": "[if(empty(steps('configuration').cmek.cmekKeyName), '', steps('configuration').cmek.cmekKeyName)]",
        "identityId": "[if(empty(steps('configuration').cmek.cmekKeyIdentity), '', steps('configuration').cmek.cmekKeyIdentity)]"
      }
    }
  }
}

创建模板 mainTemplate.json

以下 Bicep 文件是 mainTemplate.json的源代码。 该模板使用 createUiDefinition.json 文件中定义的用户分配的托管标识。

  1. 在名为 mainTemplate.bicep 的 Visual Studio Code 中创建一个新文件。
  2. 将以下代码复制并粘贴到文件中。
  3. 保存文件。
param cmekConfig object = {
  kvUrl: ''
  keyName: ''
  identityId: {}
}
@description('Specify the Azure region to place the application definition.')
param location string = resourceGroup().location
/////////////////////////////////
// Common Resources Configuration
/////////////////////////////////
var commonproperties = {
  name: 'cmekdemo'
  displayName: 'Common Resources'
  storage: {
    sku: 'Standard_LRS'
    kind: 'StorageV2'
    accessTier: 'Hot'
    minimumTlsVersion: 'TLS1_2'

  }
}
var identity = items(cmekConfig.identityId.userAssignedIdentities)[0].key

resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = {
  name: '${commonproperties.name}${uniqueString(resourceGroup().id)}'
  location: location
  sku: {
    name: commonproperties.storage.sku
  }
  kind: commonproperties.storage.kind
  identity: cmekConfig.identityId
  properties: {
    accessTier: commonproperties.storage.accessTier
    minimumTlsVersion: commonproperties.storage.minimumTlsVersion
    encryption: {
      identity: {
        userAssignedIdentity: identity
      }
      services: {
        blob: {
          enabled: true
        }
        table: {
          enabled: true
        }
        file: {
          enabled: true
        }
      }
      keySource: 'Microsoft.Keyvault'
      keyvaultproperties: {
        keyname: '${cmekConfig.keyName}'
        keyvaulturi: '${cmekConfig.kvUrl}'
      }
    }
  }
}

使用 PowerShell 或 Azure CLI 生成 mainTemplate.json 文件。 转到保存 Bicep 文件的目录并运行 build 命令。

bicep build mainTemplate.bicep

将 Bicep 文件转换为 JSON 后, mainTemplate.json 文件应与以下示例匹配。 你在versiontemplateHashmetadata属性中可能具有不同的值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.16.2.56959",
      "templateHash": "1234567891234567890"
    }
  },
  "parameters": {
    "cmekConfig": {
      "type": "object",
      "defaultValue": {
        "kvUrl": "",
        "keyName": "",
        "identityId": {}
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Specify the Azure region to place the application definition."
      }
    }
  },
  "variables": {
    "commonproperties": {
      "name": "cmekdemo",
      "displayName": "Common Resources",
      "storage": {
        "sku": "Standard_LRS",
        "kind": "StorageV2",
        "accessTier": "Hot",
        "minimumTlsVersion": "TLS1_2"
      }
    },
    "identity": "[items(parameters('cmekConfig').identityId.userAssignedIdentities)[0].key]"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2022-05-01",
      "name": "[format('{0}{1}', variables('commonproperties').name, uniqueString(resourceGroup().id))]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('commonproperties').storage.sku]"
      },
      "kind": "[variables('commonproperties').storage.kind]",
      "identity": "[parameters('cmekConfig').identityId]",
      "properties": {
        "accessTier": "[variables('commonproperties').storage.accessTier]",
        "minimumTlsVersion": "[variables('commonproperties').storage.minimumTlsVersion]",
        "encryption": {
          "identity": {
            "userAssignedIdentity": "[variables('identity')]"
          },
          "services": {
            "blob": {
              "enabled": true
            },
            "table": {
              "enabled": true
            },
            "file": {
              "enabled": true
            }
          },
          "keySource": "Microsoft.Keyvault",
          "keyvaultproperties": {
            "keyname": "[format('{0}', parameters('cmekConfig').keyName)]",
            "keyvaulturi": "[format('{0}', parameters('cmekConfig').kvUrl)]"
          }
        }
      }
    }
  ]
}

部署托管应用程序

创建服务目录定义后,可以部署托管应用程序。 有关详细信息,请转到 快速入门:部署服务目录托管应用程序

在部署期间,使用用户分配的托管标识、密钥保管库名称、密钥保管库 URL、密钥保管库的密钥名称。 createUiDefinition.json 文件创建 use 接口。

例如,在门户部署中,在 “应用程序设置” 选项卡上,添加 demomanagedappmi

“应用程序设置”选项卡的屏幕截图,用于添加用户分配的托管标识。

“配置 ”选项卡上,启用客户管理的密钥,并为密钥保管库 demokeyvaultmi 添加用户分配的托管标识。 还可以指定密钥保管库的 URL 和创建的密钥保管库的密钥名称。

配置以启用客户管理的密钥、添加密钥保管库 URL 和密钥名称以及添加用户分配的托管标识的屏幕截图。

验证部署

部署完成后,可以验证托管应用程序的标识分配。 用户分配的托管标识 demomanagedappmi 分配给托管应用程序。

  1. 转到部署托管应用的资源组。
  2. “设置标识”>下,选择“用户分配”(预览版)。

您还可以验证托管应用程序部署的存储帐户。 “加密”选项卡会显示密钥 demo-cmek-key 以及用户分配的托管标识的资源 ID。

  1. 转到托管应用程序的存储帐户被部署的托管资源组。
  2. “安全性 + 网络 ”下,选择“ 加密”。

后续步骤