在 Bicep 部署过程中使用 Azure Key Vault 传递安全参数值

在部署过程中,可以从 Azure 密钥保管库中检索安全值,而不是直接在 Bicep 文件或参数文件中放置安全值(如密码)。 当模块需要具有 secure:true 修饰符的 string 参数时,可以使用 getSecret 函数来获取密钥保管库机密。 值永远不会公开,因为仅引用其密钥保管库 ID。

重要

本文重点介绍如何将敏感值作为模板参数传递。 机密作为参数传递时,密钥保管库与部署到的资源组不需要位于同一订阅中。

本文并不涉及如何将虚拟机属性设置为密钥保管库中证书的 URL。 有关该方案的快速入门模板,请参阅在虚拟机上安装来自 Azure Key Vault 的证书

部署密钥保管库和机密

若要在 Bicep 部署过程中访问密钥保管库,请将密钥保管库上的 enabledForTemplateDeployment 设置为 true

如果你已有密钥保管库,请确保它允许进行模板部署。

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

若要创建新的密钥保管库并添加机密,请使用:

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"

作为密钥保管库的所有者,你可以自动获得创建机密的权限。 如果使用机密的用户不是密钥保管库的所有者,请使用以下命令授予访问权限:

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

若要详细了解如何创建密钥保管库和添加机密,请参阅:

授予对机密的访问权限

部署 Bicep 文件的用户必须在资源组和密钥保管库范围内具有 Microsoft.KeyVault/vaults/deploy/action 权限。 所有者参与者角色均授予该访问权限。 如果是你创建了密钥保管库,那么你就是所有者且具有相关权限。

以下过程展示了如何创建具有最小权限的角色,以及如何分配用户。

  1. 创建自定义角色定义 JSON 文件:

    {
      "Name": "Key Vault Bicep deployment operator",
      "IsCustom": true,
      "Description": "Lets you deploy a Bicep file 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。

  2. 使用 JSON 文件创建新角色:

    az role definition create --role-definition "<path-to-role-file>"
    az role assignment create \
      --role "Key Vault Bicep deployment operator" \
      --scope /subscriptions/<Subscription-id>/resourceGroups/<resource-group-name> \
      --assignee <user-principal-name>
    

    此示例在资源组级别为用户分配自定义角色。

将密钥保管库与 Bicep 文件配合用于托管应用程序时,必须向设备资源提供程序服务主体授予访问权限。 有关详细信息,请参阅部署 Azure 托管应用程序时访问 Key Vault 机密

使用 getSecret 函数

可以使用 getSecret 函数获取密钥保管库机密并将值传递给模块的 string 参数。 只能对 Microsoft.KeyVault/vaults 资源调用 getSecret 函数,并且该函数只能与带有 @secure() 修饰器的参数一起使用。

以下 Bicep 文件创建 Azure SQL Server。 adminPassword 参数具有 @secure() 修饰器。

param sqlServerName string
param adminLogin string

@secure()
param adminPassword string

resource sqlServer 'Microsoft.Sql/servers@2020-11-01-preview' = {
  name: sqlServerName
  location: resourceGroup().location
  properties: {
    administratorLogin: adminLogin
    administratorLoginPassword: adminPassword
    version: '12.0'
  }
}

让我们使用前面的 Bicep 文件作为模块,假定文件的名称为 sql.bicep,与主 Bicep 文件位于同一目录。

以下 Bicep 文件使用 sql.bicep 作为模块。 Bicep 文件引用现有的密钥保管库,并调用 getSecret 函数来检索密钥保管库机密,然后将值作为参数传递到模块中。

param sqlServerName string
param adminLogin string

param subscriptionId string
param kvResourceGroup string
param kvName string

resource kv 'Microsoft.KeyVault/vaults@2023-02-01' existing = {
  name: kvName
  scope: resourceGroup(subscriptionId, kvResourceGroup )
}

module sql './sql.bicep' = {
  name: 'deploySQL'
  params: {
    sqlServerName: sqlServerName
    adminLogin: adminLogin
    adminPassword: kv.getSecret('vmAdminPassword')
  }
}

此外,还可以在 .bicepparam 文件中使用 getSecret 函数(或使用命名空间限定符 az.getSecret)从密钥保管库检索机密值。

using './main.bicep'

param secureUserName = getSecret('exampleSubscription', 'exampleResourceGroup', 'exampleKeyVault', 'exampleSecretUserName', 'exampleSecretVersion')
param securePassword = az.getSecret('exampleSubscription', 'exampleResourceGroup', 'exampleKeyVault', 'exampleSecretPassword')

在参数文件中引用机密

如果不想使用模块,可以直接在参数文件中引用密钥保管库。 下图显示参数文件如何引用机密并将该值传递给 Bicep 文件。

Resource Manager key vault integration diagram

注意

目前,只能在 JSON 参数文件中引用密钥保管库。 不能在 Bicep 参数文件中引用密钥保管库。

以下 Bicep 文件部署包含管理员密码的 SQL Server。 密码参数设置为安全字符串。 但是,Bicep 未指定该值的来源。

param location string = resourceGroup().location
param adminLogin string

@secure()
param adminPassword string

param sqlServerName string

resource sqlServer 'Microsoft.Sql/servers@2022-11-01-preview' = {
  name: sqlServerName
  location: location
  properties: {
    administratorLogin: adminLogin
    administratorLoginPassword: adminPassword
    version: '12.0'
  }
}

现在,为前面的 Bicep 文件创建参数文件。 在参数文件中,指定与 Bicep 文件中的参数名称相匹配的参数。 对于参数值,请从 key vault 中引用机密。 可以通过传递密钥保管库的资源标识符和机密的名称来引用机密:

在以下参数文件中,密钥保管库机密必须已存在,而且为其资源 ID 提供了静态值。

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-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 属性。

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

部署模板并传入参数文件:

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

后续步骤