You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在同一Bicep模板中创建KeyVault并引用其密钥部署资源?

解决Azure MySQL灵活服务器引用KeyVault凭据的部署错误

需求与问题

需要完成以下部署操作:

  • 创建KeyVault及存储MySQL管理员用户名/密码的密钥
  • 创建MySQL数据库并使用KeyVault中的凭据(尝试用KeyVault引用但失败)
  • 创建App Service,通过托管标识读取KeyVault中的凭据配置数据库连接字符串

部署时遇到错误,提示administratorLogin参数值无效,希望在单个Bicep模板中完成所有部署,避免拆分步骤。

错误信息

ERROR: {"status":"Failed","error":{"code":"DeploymentFailed","target":"/subscriptions/xxxxxxxxxxxx/resourceGroups/rg-yyyy-dev/providers/Microsoft.Resources/deployments/main","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-deployment-operations for usage details.","details":[{"code":"InvalidParameterValue","message":"Invalid value given for parameter administratorLogin. Specify a valid parameter value."}]}}

原Bicep代码

param appNamePrefix string = 'foobar'
param location string = 'West Europe'
param env string = 'dev'
param mysqlDbName string = '${appNamePrefix}-${env}'
param mysqlUsername string = 'admin'

@secure()
@minLength(10)
param mysqlPassword string

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31'  = {
  location: location
  name: toLower('${appNamePrefix}-uami-${env}')
}

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: '${appNamePrefix}-keyvault-${env}'
  location: location
  properties: {
    sku: {
      family: 'A'
      name: 'standard'
    }
    tenantId: subscription().tenantId
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: managedIdentity.properties.principalId
        permissions: {
          secrets: ['get']
        }
      }
    ]
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'None'
    }
  }
}

resource mysqlAdminUsernameSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'adminUsername'
  properties: {
    value: mysqlUsername
  }
}

resource mysqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'adminPassword'
  properties: {
    value: mysqlPassword
  }
}
resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2023-06-30' = {
  name: '${appNamePrefix}-${env}-mysql-server'
  location: location
  sku: {
    tier: 'Burstable'
    name: 'Standard_B1s' 
  }
  properties: {
    createMode: 'Default'
    administratorLogin: '@Microsoft.KeyVault(SecretUri=${mysqlAdminUsernameSecret.properties.secretUri})'
    administratorLoginPassword: '@Microsoft.KeyVault(SecretUri=${mysqlAdminPasswordSecret.properties.secretUri})'
    version: '8.0'
    storage: {
      storageSizeGB: 20
      iops: 360
      autoGrow: 'Enabled'
    }
    backup: {
      backupRetentionDays: 7
      geoRedundantBackup: 'Disabled'
    }
    network: {
      delegatedSubnetResourceId: subnet.id
    }
  }

  resource db 'databases' = {
    name: mysqlDbName
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: '${appNamePrefix}-plan-${env}'
  location: location
  sku: {
    name: 'B1'
    tier: 'Basic'
  }
}

resource appService 'Microsoft.Web/sites@2023-01-01' = {
  name: '${appNamePrefix}-app-${env}'
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
    siteConfig: {
      ftpsState: 'Disabled'
      minTlsVersion: '1.2'
      connectionStrings: [
        {
          name: 'DefaultConnection'
          type: 'MySql'
          connectionString: 'Server=${mysqlServer.name}.mysql.database.azure.com;Database=${mysqlDbName};User=@Microsoft.KeyVault(SecretUri=${mysqlAdminUsernameSecret.properties.secretUri});Password=@Microsoft.KeyVault(SecretUri=${mysqlAdminPasswordSecret.properties.secretUri})'
        }
      ]
    }
    keyVaultReferenceIdentity: managedIdentity.id
  }
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${managedIdentity.id}': {}
    }
  }
}

output appEndpoint string = appService.properties.defaultHostName

解决方案

核心问题:Azure MySQL灵活服务器的administratorLogin和administratorLoginPassword字段不支持KeyVault引用,必须直接传入明文值(但可以通过Bicep的@secure()参数保证密码的安全性,同时将凭据存入KeyVault供App Service后续使用)。

修改步骤:

  1. MySQL服务器创建时直接使用参数中的mysqlUsername和mysqlPassword作为管理员凭据
  2. 保留KeyVault及密钥的创建逻辑,确保托管标识拥有读取密钥的权限
  3. App Service的连接字符串继续使用KeyVault引用,同时正确配置托管标识和keyVaultReferenceIdentity
  4. 修正原代码中未定义的subnet变量(添加参数或引用现有子网资源)

修改后的Bicep代码

param appNamePrefix string = 'foobar'
param location string = 'West Europe'
param env string = 'dev'
param mysqlDbName string = '${appNamePrefix}-${env}'
param mysqlUsername string = 'admin'

// 添加子网ID参数,根据实际环境传入
param subnetId string

@secure()
@minLength(10)
param mysqlPassword string

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31'  = {
  location: location
  name: toLower('${appNamePrefix}-uami-${env}')
}

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: '${appNamePrefix}-keyvault-${env}'
  location: location
  properties: {
    sku: {
      family: 'A'
      name: 'standard'
    }
    tenantId: subscription().tenantId
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: managedIdentity.properties.principalId
        permissions: {
          secrets: ['get']
        }
      }
    ]
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'None'
    }
  }
}

resource mysqlAdminUsernameSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'adminUsername'
  properties: {
    value: mysqlUsername
  }
}

resource mysqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
  parent: keyVault
  name: 'adminPassword'
  properties: {
    value: mysqlPassword
  }
}

resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2023-06-30' = {
  name: '${appNamePrefix}-${env}-mysql-server'
  location: location
  sku: {
    tier: 'Burstable'
    name: 'Standard_B1s' 
  }
  properties: {
    createMode: 'Default'
    // 直接使用参数值,不再用KeyVault引用
    administratorLogin: mysqlUsername
    administratorLoginPassword: mysqlPassword
    version: '8.0'
    storage: {
      storageSizeGB: 20
      iops: 360
      autoGrow: 'Enabled'
    }
    backup: {
      backupRetentionDays: 7
      geoRedundantBackup: 'Disabled'
    }
    network: {
      delegatedSubnetResourceId: subnetId
    }
  }

  resource db 'databases' = {
    name: mysqlDbName
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
  name: '${appNamePrefix}-plan-${env}'
  location: location
  sku: {
    name: 'B1'
    tier: 'Basic'
  }
}

resource appService 'Microsoft.Web/sites@2023-01-01' = {
  name: '${appNamePrefix}-app-${env}'
  location: location
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
    siteConfig: {
      ftpsState: 'Disabled'
      minTlsVersion: '1.2'
      connectionStrings: [
        {
          name: 'DefaultConnection'
          type: 'MySql'
          connectionString: 'Server=${mysqlServer.name}.mysql.database.azure.com;Database=${mysqlDbName};User=@Microsoft.KeyVault(SecretUri=${mysqlAdminUsernameSecret.properties.secretUri});Password=@Microsoft.KeyVault(SecretUri=${mysqlAdminPasswordSecret.properties.secretUri})'
        }
      ]
    }
    keyVaultReferenceIdentity: managedIdentity.id
  }
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${managedIdentity.id}': {}
    }
  }
}

output appEndpoint string = appService.properties.defaultHostName

内容的提问来源于stack exchange,提问作者Andreas F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:07:35