在部署过程中使用 Azure Key Vault 传递安全参数值Use Azure Key Vault to pass secure parameter value during deployment

在部署过程中,可以从 Azure Key Vault 中检索一个安全值,而不是直接在模板或参数文件中放置该值(如密码)。Instead of putting a secure value (like a password) directly in your template or parameter file, you can retrieve the value from an Azure Key Vault during a deployment. 通过引用参数文件中的密钥保管库和密钥来检索值。You retrieve the value by referencing the key vault and secret in your parameter file. 值永远不会公开,因为仅引用其密钥保管库 ID。The value is never exposed because you only reference its key vault ID. 密钥保管库可以与要部署到的资源组位于不同的订阅中。The key vault can exist in a different subscription than the resource group you're deploying to.

本文重点介绍将敏感值作为模板参数传入的方案。This article focuses on the scenario of passing a sensitive value in as a template parameter. 它不涉及将虚拟机属性设为 Key Vault 中的证书 URL 的方案。It doesn't cover the scenario of setting a virtual machine property to the URL of a certificate in a Key Vault. 有关该方案的快速入门模板,请参阅在虚拟机上安装来自 Azure Key Vault 的证书For a quickstart template of that scenario, see Install a certificate from Azure Key Vault on a Virtual Machine.

部署密钥保管库和机密Deploy key vaults and secrets

若要在模板部署期间访问密钥保管库,请将密钥保管库上的 enabledForTemplateDeployment 设置为 trueTo access a key vault during template deployment, set enabledForTemplateDeployment on the key vault to true.

如果你已有 Key Vault,请确保它允许进行模板部署。If you already have a Key Vault, make sure it allows template deployments.

az keyvault update  --name ExampleVault --enabled-for-template-deployment true

若要新建 Key Vault 并添加机密,请使用:To create a new Key Vault and add a secret, use:

az group create --name ExampleGroup --location chinaeast
az keyvault create \
  --name ExampleVault \
  --resource-group ExampleGroup \
  --location chinaeast \
  --enabled-for-template-deployment true
az keyvault secret set --vault-name ExampleVault --name "ExamplePassword" --value "hVFkk965BuUv"

作为密钥保管库的所有者,你可以自动获得创建机密的权限。As the owner of the key vault, you automatically have access to creating secrets. 如果使用机密的用户不是密钥保管库的所有者,请使用以下命令授予访问权限:If the user working with secrets isn't the owner of the key vault, grant access with:

az keyvault set-policy \
  --upn <user-principal-name> \
  --name ExampleVault \
  --secret-permissions set delete get list

若要详细了解如何创建密钥保管库和添加机密,请参阅:For more information about creating key vaults and adding secrets, see:

授予对机密的访问权限Grant access to the secrets

部署模板的用户必须在资源组和密钥保管库范围内具有 Microsoft.KeyVault/vaults/deploy/action 权限。The user who deploys the template must have the Microsoft.KeyVault/vaults/deploy/action permission for the scope of the resource group and key vault. 所有者参与者角色均授予该访问权限。The Owner and Contributor roles both grant this access. 如果你创建了密钥保管库,则你是所有者,因此具有权限。If you created the key vault, you're the owner so you have the permission.

以下过程展示了如何创建具有最小权限的角色,以及如何分配用户The following procedure shows how to create a role with the minimum permission, and how to assign the user

  1. 创建自定义角色定义 JSON 文件:Create a custom role definition JSON file:

    {
      "Name": "Key Vault resource manager template deployment operator",
      "IsCustom": true,
      "Description": "Lets you deploy a resource manager template with the access to the secrets in the Key Vault.",
      "Actions": [
        "Microsoft.KeyVault/vaults/deploy/action"
      ],
      "NotActions": [],
      "DataActions": [],
      "NotDataActions": [],
      "AssignableScopes": [
        "/subscriptions/00000000-0000-0000-0000-000000000000"
      ]
    }
    

    将“00000000-0000-0000-0000-000000000000”替换为订阅 ID。Replace "00000000-0000-0000-0000-000000000000" with the subscription ID.

  2. 使用 JSON 文件创建新角色:Create the new role using the JSON file:

    az role definition create --role-definition "<path-to-role-file>"
    az role assignment create \
      --role "Key Vault resource manager template deployment operator" \
      --assignee <user-principal-name> \
      --resource-group ExampleGroup
    

    此示例在资源组级别为用户分配自定义角色。The samples assign the custom role to the user on the resource group level.

使用 Key Vault 部署托管应用程序的模板时,必须授予对设备资源提供程序 服务主体的访问权限。When using a Key Vault with the template for a Managed Application, you must grant access to the Appliance Resource Provider service principal. 有关详细信息,请参阅部署 Azure 托管应用程序时访问 Key Vault 机密For more information, see Access Key Vault secret when deploying Azure Managed Applications.

通过静态 ID 引用机密Reference secrets with static ID

使用此方法,可以在参数文件(而不是在模板)中引用密钥保管库。With this approach, you reference the key vault in the parameter file, not the template. 下图显示了参数文件如何引用机密并将该值传递到模板。The following image shows how the parameter file references the secret and passes that value to the template.

资源管理器密钥保管库集成静态 ID 图

教程:在资源管理器模板部署中集成 Azure Key Vault 使用了此方法。Tutorial: Integrate Azure Key Vault in Resource Manager Template deployment uses this method.

以下模板部署包含管理员密码的 SQL Server。The following template deploys a SQL server that includes an administrator password. 密码参数设置为安全字符串。The password parameter is set to a secure string. 但是,此模板未指定该值的来源。But, the template doesn't specify where that value comes from.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "adminLogin": {
      "type": "string"
    },
    "adminPassword": {
      "type": "securestring"
    },
    "sqlServerName": {
      "type": "string"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Sql/servers",
      "apiVersion": "2015-05-01-preview",
      "name": "[parameters('sqlServerName')]",
      "location": "[resourceGroup().location]",
      "tags": {},
      "properties": {
        "administratorLogin": "[parameters('adminLogin')]",
        "administratorLoginPassword": "[parameters('adminPassword')]",
        "version": "12.0"
      }
    }
  ],
  "outputs": {
  }
}

现在,为上述模板创建参数文件。Now, create a parameter file for the preceding template. 在参数文件中,指定与模板中的参数名称匹配的参数。In the parameter file, specify a parameter that matches the name of the parameter in the template. 对于参数值,请从 key vault 中引用机密。For the parameter value, reference the secret from the key vault. 可以通过传递密钥保管库的资源标识符和机密的名称来引用机密:You reference the secret by passing the resource identifier of the key vault and the name of the secret:

在以下参数文件中,密钥保管库机密必须已存在,而且你为其资源 ID 提供了静态值。In the following parameter file, the key vault secret must already exist, and you provide a static value for its resource ID.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
      "adminLogin": {
        "value": "exampleadmin"
      },
      "adminPassword": {
        "reference": {
          "keyVault": {
          "id": "/subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.KeyVault/vaults/<vault-name>"
          },
          "secretName": "ExamplePassword"
        }
      },
      "sqlServerName": {
        "value": "<your-server-name>"
      }
  }
}

如果需要使用当前版本以外的机密版本,请使用 secretVersion 属性。If you need to use a version of the secret other than the current version, use the secretVersion property.

"secretName": "ExamplePassword",
"secretVersion": "cd91b2b7e10e492ebb870a6ee0591b68"

部署模板并传入参数文件:Deploy the template and pass in the parameter file:

az group create --name SqlGroup --location chinanorth2
az deployment group create \
  --resource-group SqlGroup \
  --template-uri <template-file-URI> \
  --parameters <parameter-file>

通过动态 ID 引用机密Reference secrets with dynamic ID

上一部分介绍了如何通过参数传递密钥保管库机密的静态资源 ID。The previous section showed how to pass a static resource ID for the key vault secret from the parameter. 但是,在某些情况下,需要引用随当前部署而变的密钥保管库机密。However, in some scenarios, you need to reference a key vault secret that varies based on the current deployment. 或者,你需要将参数值传递到模板而不在参数文件中创建引用参数。Or, you may want to pass parameter values to the template rather than create a reference parameter in the parameter file. 在任何一种情况下,均可使用链接模板为密钥保管库机密动态生成资源 ID。In either case, you can dynamically generate the resource ID for a key vault secret by using a linked template.

不能在参数文件中动态生成资源 ID,因为参数文件中不允许使用模板表达式。You can't dynamically generate the resource ID in the parameters file because template expressions aren't allowed in the parameters file.

在父模板中添加嵌套模板,然后传入包含动态生成的资源 ID 的参数。In your parent template, you add the nested template and pass in a parameter that contains the dynamically generated resource ID. 下图显示链接模板中的参数如何引用机密。The following image shows how a parameter in the linked template references the secret.

动态 ID

以下模板动态创建 Key Vault ID 并将其作为参数传递。The following template dynamically creates the key vault ID and passes it as a parameter.

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
      "location": {
        "type": "string",
        "defaultValue": "[resourceGroup().location]",
        "metadata": {
          "description": "The location where the resources will be deployed."
        }
      },
      "vaultName": {
        "type": "string",
        "metadata": {
          "description": "The name of the keyvault that contains the secret."
        }
      },
      "secretName": {
        "type": "string",
        "metadata": {
          "description": "The name of the secret."
        }
      },
      "vaultResourceGroupName": {
        "type": "string",
        "metadata": {
          "description": "The name of the resource group that contains the keyvault."
        }
      },
      "vaultSubscription": {
        "type": "string",
        "defaultValue": "[subscription().subscriptionId]",
        "metadata": {
          "description": "The name of the subscription that contains the keyvault."
        }
      }
  },
  "resources": [
    {
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2018-05-01",
      "name": "dynamicSecret",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "adminLogin": {
              "type": "string"
            },
            "adminPassword": {
              "type": "securestring"
            },
            "location": {
              "type": "string"
            }
          },
          "variables": {
            "sqlServerName": "[concat('sql-', uniqueString(resourceGroup().id, 'sql'))]"
          },
          "resources": [
            {
              "type": "Microsoft.Sql/servers",
              "apiVersion": "2018-06-01-preview",
              "name": "[variables('sqlServerName')]",
              "location": "[parameters('location')]",
              "properties": {
                "administratorLogin": "[parameters('adminLogin')]",
                "administratorLoginPassword": "[parameters('adminPassword')]"
              }
            }
          ],
          "outputs": {
            "sqlFQDN": {
              "type": "string",
              "value": "[reference(variables('sqlServerName')).fullyQualifiedDomainName]"
            }
          }
        },
        "parameters": {
          "location": {
            "value": "[parameters('location')]"
          },
          "adminLogin": {
            "value": "ghuser"
          },
          "adminPassword": {
            "reference": {
              "keyVault": {
                "id": "[resourceId(parameters('vaultSubscription'), parameters('vaultResourceGroupName'), 'Microsoft.KeyVault/vaults', parameters('vaultName'))]"
              },
              "secretName": "[parameters('secretName')]"
            }
          }
        }
      }
    }
  ],
  "outputs": {
  }
}

后续步骤Next steps