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

使用 Bicep 管理机密

部署通常需要在整个 Azure 环境中安全地存储和传播机密。 Bicep 和 Azure 提供许多功能,有助于管理部署中的机密。

尽可能避免使用机密

许多情况下可以避免使用机密。 许多 Azure 资源支持托管标识,因此可以在进行身份验证后获得访问 Azure 中的其他资源的权限,不需要你处理或管理任何凭据。 此外,某些 Azure 服务可以自动为你生成 HTTPS 证书,使你不需要处理证书和私钥。 尽可能使用托管标识和服务托管证书。

使用安全参数

需要将机密作为参数提供给 Bicep 部署时,请使用 @secure() 修饰器。 将某个参数标记为安全参数时,Azure 资源管理器会避免在 Azure 门户、Azure CLI 或 Azure PowerShell 中记录值或显示值。

避免机密输出

不要将 Bicep 输出用于安全数据。 输出会记录到部署历史记录中,有权访问部署的任何人都可以查看部署的输出的值。

如果需要在 Bicep 部署中生成机密并使其可供调用方或其他资源使用,请考虑使用以下方法之一。

动态查找机密

有时,你需要访问一个资源的机密,以配置另一资源。

例如,你可能已在另一个部署中创建了一个存储帐户,需要访问其主密钥来配置 Azure Functions 应用。 你可以使用 existing 关键字来获取对预先创建的存储帐户的强类型引用,然后使用该存储帐户的 listKeys() 方法创建具有主密钥的连接字符串:

以下示例是较大示例的一部分。 有关可以部署的 Bicep 文件,请参阅完整文件

param location string = resourceGroup().location
param storageAccountName string
param functionAppName string = 'fn-${uniqueString(resourceGroup().id)}'

var appServicePlanName = 'MyPlan'
var applicationInsightsName = 'MyApplicationInsights'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' existing = {
  name: storageAccountName
}

var storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'

resource functionApp 'Microsoft.Web/sites@2023-12-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp'
  properties: {
    httpsOnly: true
    serverFarmId: appServicePlan.id
    siteConfig: {
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: applicationInsights.properties.InstrumentationKey
        }
        {
          name: 'AzureWebJobsStorage'
          value: storageAccountConnectionString
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~3'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'dotnet'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: storageAccountConnectionString
        }
      ]
    }
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
  name: appServicePlanName
  location: location
  sku: {
    name: 'Y1' 
    tier: 'Dynamic'
  }
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: applicationInsightsName
  location: location
  kind: 'web'
  properties: { 
    Application_Type: 'web'
    publicNetworkAccessForIngestion: 'Enabled'
    publicNetworkAccessForQuery: 'Enabled'
  }
}

通过使用此方法,可以避免将机密传入或传出 Bicep 文件。

还可以使用此方法将机密存储在密钥保管库中。

使用 Key Vault

Azure Key Vault 旨在存储和管理安全数据。 使用密钥保管库来管理需保护和共享的机密、证书、密钥和其他数据。

可以通过使用 Bicep 创建和管理保管库和机密。 通过创建类型为 Microsoft.KeyVault/vaults 的资源来定义保管库。

创建保管库时,需要确定可以访问其数据的人员和项目。 如果计划从 Bicep 文件内部读取保管库的机密,请将 enabledForTemplateDeployment 属性设置为 true

向密钥保管库添加机密

机密是子资源,可以使用类型 Microsoft.KeyVault/vaults/secrets 进行创建。 以下示例演示如何创建保管库和机密:

以下示例是较大示例的一部分。 有关可以部署的 Bicep 文件,请参阅完整文件

param location string = resourceGroup().location
param keyVaultName string = 'mykv${uniqueString(resourceGroup().id)}'

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: keyVaultName
  location: location
  properties: {
    enabledForTemplateDeployment: true
    tenantId: tenant().tenantId
    accessPolicies: [
    ]
    sku: {
      name: 'standard'
      family: 'A'
    }
  }
}

resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'MySecretName'
  properties: {
    value: 'MyVerySecretValue'
  }
}

提示

使用自动部署管道时,有时很难确定如何为部署启动密钥保管库机密。 例如,如果你获得了与外部 API 通信时需使用的 API 密钥,则需将该机密添加到保管库,然后才能在部署中使用它。

使用来自第三方的机密时,可能需要手动将其添加到保管库,然后才能引用该机密进行所有后续的使用。

将密钥保管库与模块配合使用

使用 Bicep 模块时,可以使用 getSecret 函数提供安全参数。

还可以通过将 existingscope 关键字配合使用来引用在其他资源组中定义的密钥保管库。 在下面的示例中,Bicep 文件部署到名为“Networking”的资源组。 模块参数 mySecret 的值在 Secrets 资源组中名为 contosonetworkingsecrets 的密钥保管库中定义:

resource networkingSecretsKeyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  scope: resourceGroup('Secrets')
  name: 'contosonetworkingsecrets'
}

module exampleModule 'module.bicep' = {
  name: 'exampleModule'
  params: {
    mySecret: networkingSecretsKeyVault.getSecret('mySecret')
  }
}

在 .bicepparam 文件中使用密钥保管库

使用 .bicepparam 文件格式时,可以使用 getSecret 函数向参数提供安全值。

通过提供订阅 ID、资源组名称和密钥保管库名称来引用 KeyVault。 可以通过提供机密名称来获取机密的值。 可以选择提供机密版本。 如果未提供机密版本,则会使用最新版本。

using './main.bicep'

param secureUserName = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>', '<secretVersion>')
param securePassword = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>')

在管道中使用机密

使用管道部署 Azure 资源时,需要谨慎且适当地处理机密。

  • 避免在代码存储库中存储机密。 例如,不要将机密添加到参数文件,也不要将其添加到管道定义 YAML 文件。
  • 在 GitHub Actions 中,请使用加密的机密来存储安全数据。 使用机密扫描检测任何意外的机密提交。
  • 在 Azure Pipelines 中,使用机密变量来存储安全数据。