#azure #azure-web-app-service #azure-keyvault #azure-managed-identity #azure-bicep
Вопрос:
В настоящее время я пытаюсь развернуть группу ресурсов с помощью azure bicep, однако у меня возникла проблема с использованием хранилища ключей для моей службы приложений azure. Я хотел бы знать, действительно ли я делаю это правильно. У меня есть основной файл бицепса, который соответствует:
// params removed for brevity...
targetScope = 'subscription'
resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: 'rg-${appName}-${region}'
location: 'centralus'
}
module appServicePlan 'appplan.bicep' = {
params: {
sku: appServicePlanSku
appName: appName
region: region
}
scope: rg
name: 'AppServicePlanDeploy'
}
module keyVault 'keyvault.bicep' = {
params: {
keyVaultName: keyVaultName
sqlPassword: sqlServerPassword
webSiteManagedId: webSite.outputs.webAppPrincipal
}
scope: rg
name: 'KeyVaultDeploy'
dependsOn: [
webSite
]
}
module ai 'ai.bicep' = {
scope: rg
name: 'ApplicationInsightsDeploy'
params: {
name: appName
region: region
keyVaultName: keyVault.outputs.keyVaultName
}
dependsOn: [
keyVault
]
}
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: keyVaultName
scope: rg
}
module sql 'sqlserver.bicep' = {
scope: rg
name: 'SQLServerDeploy'
params: {
appName: appName
region: region
sqlPassword: kv.getSecret('sqlPassword')
sqlCapacitity: sqlCapacitity
sqlSku: sqlSku
sqlTier: sqlTier
}
dependsOn: [
keyVault
]
}
module webSite 'site.bicep' = {
params: {
appName: appName
region: region
keyVaultName: keyVaultName
serverFarmId: appServicePlan.outputs.appServicePlanId
}
scope: rg
name: 'AppServiceDeploy'
dependsOn: [
appServicePlan
]
}
Мой вопрос связан с реализацией сайта.бицепс, я начал с передачи секретного uri из экспортируемых переменных и создания веб-приложения в качестве последнего в app insights, sql и т. Д… все они должны быть настроены и в keyvault, прежде чем мы будем использовать их экспортированный секретный uri для создания конфигурации. У меня было что-то вроде:
сайт.бицепс (раньше):
properties: {
serverFarmId: serverFarmId
keyVaultReferenceIdentity: userAssignedId
siteConfig: {
appSettings: [
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: '@Microsoft.KeyVault(SecretUri=${appInsightsConnectionString})'
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: '@Microsoft.KeyVault(SecretUri=${appInsightsKey})'
}
]
netFrameworkVersion: 'v5.0'
}
}
Единственная проблема с этой реализацией заключается в том, что хранилище ключей ДОЛЖНО быть создано до веб-сайта, поскольку sql, ai и другие службы будут хранить свои значения внутри хранилища ключей, чтобы веб-приложение могло использовать их соответствующие uri. Проблема в том, что KeyVault по праву не имеет представления, какой службе azure разрешить доступ к своим ключам.
Мой вопрос заключается в том, что решение создания веб-приложения перед хранилищем ключей является единственным способом решения этой проблемы? Я использую управляемые удостоверения в веб-приложении и хотел бы продолжать делать это, если это возможно. Мое окончательное решение закончилось примерно так:
site.bicep (final)
// params removed for brevity...
resource webApplication 'Microsoft.Web/sites@2020-12-01' = {
name: 'app-${appName}-${region}'
location: resourceGroup().location
tags: {
'hidden-related:${resourceGroup().id}/providers/Microsoft.Web/serverfarms/appServicePlan': 'Resource'
}
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: serverFarmId
siteConfig: {
appSettings: [
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultName}.vault.azure.net/secrets/aiConnectionString)'
}
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultName}.vault.azure.net/secrets/aiInstrumentationKey)'
}
{
name: 'AngularConfig:ApplicationInsightsKey'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultName}.vault.azure.net/secrets/aiInstrumentationKey)'
}
]
netFrameworkVersion: 'v5.0'
}
}
}
output webAppPrincipal string = webApplication.identity.principalId
И KeyVault, который займет веб-сайт dependsOn
Кейволт.бицепс(финал):
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: keyVaultName
location: resourceGroup().location
properties: {
enabledForDeployment: true
enabledForTemplateDeployment: true
enabledForDiskEncryption: true
enableRbacAuthorization: true
tenantId: subscription().tenantId
sku: {
name: 'standard'
family: 'A'
}
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: webSiteManagedId
permissions: {
keys: [
'get'
]
secrets: [
'list'
'get'
]
}
}
]
}
}
Ответ №1:
Просто рассматривайте свой accessPolicies
ресурс как отдельный и добавляйте его при создании Хранилища ключей и службы приложений. То же самое относится к разделу конфигурации и строкам подключения. Ознакомьтесь с документацией здесь.
В шаблонах ARM вы можете добиться того же эффекта, используя вложенные шаблоны. В Bicep это примерно то же самое, но вы объявляете их как отдельный ресурс, который обычно содержит имя родителя (например name: '${kv.name}/add'
, name: '${webSite.name}/connectionstrings'
)
Образец
Шаг 1. Создайте службу приложений без раздела конфигурации
resource webSite 'Microsoft.Web/sites@2020-12-01' = {
name: webSiteName
location: location
properties: {
serverFarmId: hostingPlan.id
siteConfig:{
netFrameworkVersion: 'v5.0'
}
}
identity: {
type:'SystemAssigned'
}
}
Шаг 2. Создайте хранилище ключей без политик доступа
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: keyVaultName
location: location
properties:{
sku:{
family: 'A'
name: 'standard'
}
tenantId: tenantId
enabledForTemplateDeployment: true
accessPolicies:[
]
}
}
Шаг 3. Создайте новую политику доступа и ссылку на управляемую идентификацию веб-приложений
resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = {
name: '${kv.name}/add'
properties: {
accessPolicies: [
{
tenantId: tenantId
objectId: webSite.identity.principalId
permissions: {
keys: [
'get'
]
secrets: [
'list'
'get'
]
}
}
]
}
}
Шаг 4. Обновите раздел конфигурации приложения Webb
resource webSiteConnectionStrings 'Microsoft.Web/sites/config@2020-06-01' = {
name: '${webSite.name}/connectionstrings'
properties: {
DefaultConnection: {
value: '@Microsoft.KeyVault(SecretUri=${keyVaultName}.vault.azure.net/secrets/aiConnectionString)'
type: 'SQLAzure'
}
}
}
Ответ №2:
Одним из решений может быть использование идентификатора Назначенного пользователя вместо назначенного системой. Затем вы развернете следующее:
- Развертывание идентификатора, назначенного пользователю
- Хранилище ключей и назначение разрешений для удостоверения, присвоенного пользователю
- Развертывание веб-приложения с присвоенным пользователем идентификатором и секретами чтения / записи
Назначенный пользователь не зависит от ресурсов, и поэтому вы избегаете проблем с курицей и яйцом.
Еще:
Ответ №3:
Вам следует разделить три части вашего развертывания на отдельные ресурсы:
- Разверните хранилище ключей — без каких-либо политик доступа!
- Разверните службу приложений — с назначенным системой идентификатором, но без настроек приложения
- Разверните политику доступа к хранилищу ключей для MSI
- Разверните настройки приложения