如何创建使用 Key Vault 的幂等、可重新部署的 ARM 模板?循环依赖存在问题
How to create idempotent, re-deployable ARM templates that utilize Key Vault? Circular dependencies present issues
我正在尝试在我的资源中加入一些额外的安全功能,例如使用客户管理的密钥进行加密。对于服务总线,这需要服务总线创建托管标识并授予对 Key Vault 的访问权限。但是,在服务总线存在之前,托管标识是未知的。
在我的 ARM 模板中,我需要在不加密的情况下初始化服务总线,以便获得托管标识,授予该标识对密钥保管库的访问权限,然后使用加密更新服务总线。但是,此部署过程不可重复。在随后的重新部署中,它将失败,因为加密一旦被授予就无法从服务总线中删除。即使它确实有效,我也会执行不必要的步骤来删除加密并将其重新添加到每个部署中。似乎描述资源预期最终状态的 IAC 模板不能用于维护和 bootstrap 新环境。
API 管理存在同样的问题,我想添加自定义域,但它们需要 Key Vault 访问权限。这意味着当初始化步骤重复时,我无法在不删除自定义域的情况下重新部署我的 ARM 模板(或者为 'initialization' 与 'real deployment'.
保留一组单独的模板
有更好的解决办法吗?我调查了用户分配的身份,这似乎可以解决问题,但 ARM 模板不支持它们。我检查了是否有一种方法可以通过检查资源是否已经存在来使 'init' 步骤成为条件,这也不支持通过 ARM 模板。
如果要维护单个 ARM 模板,可以使用 nested deployments 定义资源然后再次引用它以更新它。
在下面的示例中,我使用系统分配的托管标识、Key Vault 和 RSA 密钥创建服务总线。在取决于所生成的密钥的同一 ARM 模板内的嵌套部署中,我随后更新服务总线以启用加密。全部在同一个模板中的一个优点是 resourceId
和 reference
可以使用缩写语法(即只是资源名称)。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"name": {
"type": "string",
"defaultValue": "[resourceGroup().name]"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"tenantId": {
"type": "string",
"defaultValue": "[subscription().tenantId]"
}
},
"variables": {
"kv_name": "[concat(parameters('name'), 'kv')]",
"kv_version": "2019-09-01",
"sb_name": "[concat(parameters('name'), 'sb')]",
"sb_version": "2018-01-01-preview",
"sb_keyname": "sbkey"
},
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false
}
},
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "[variables('kv_version')]",
"name": "[variables('kv_name')]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('sb_name')]"
],
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[parameters('tenantId')]",
"accessPolicies": [
{
"tenantId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.tenantId]",
"objectId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.principalId]",
"permissions": {
"keys": [
"get",
"wrapKey",
"unwrapKey"
]
}
}
],
// Both must be enabled to encrypt Service Bus at rest.
"enableSoftDelete": true,
"enablePurgeProtection": true
}
},
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "[variables('kv_version')]",
"name": "[concat(variables('kv_name'), '/', variables('sb_keyname'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('kv_name')]"
],
"properties": {
"kty": "RSA",
"keySize": 2048,
"keyOps": [
"wrapKey",
"unwrapKey"
],
"attributes": {
"enabled": true
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-10-01",
"name": "sb_deployment",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('kv_name'), variables('sb_keyname'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false,
"encryption": {
"keySource": "Microsoft.KeyVault",
"keyVaultProperties": [
{
// Ideally should specify a specific version, but no ARM template function to get this currently.
"keyVaultUri": "[reference(variables('kv_name')).vaultUri]",
"keyName": "[variables('sb_keyname')]"
}
]
}
}
}
]
}
}
}
]
}
要使用 Azure CLI 进行部署:
az group create -g rg-example -l westus2
az deployment group create -g rg-example -f template.json --parameters name=example
我正在尝试在我的资源中加入一些额外的安全功能,例如使用客户管理的密钥进行加密。对于服务总线,这需要服务总线创建托管标识并授予对 Key Vault 的访问权限。但是,在服务总线存在之前,托管标识是未知的。
在我的 ARM 模板中,我需要在不加密的情况下初始化服务总线,以便获得托管标识,授予该标识对密钥保管库的访问权限,然后使用加密更新服务总线。但是,此部署过程不可重复。在随后的重新部署中,它将失败,因为加密一旦被授予就无法从服务总线中删除。即使它确实有效,我也会执行不必要的步骤来删除加密并将其重新添加到每个部署中。似乎描述资源预期最终状态的 IAC 模板不能用于维护和 bootstrap 新环境。
API 管理存在同样的问题,我想添加自定义域,但它们需要 Key Vault 访问权限。这意味着当初始化步骤重复时,我无法在不删除自定义域的情况下重新部署我的 ARM 模板(或者为 'initialization' 与 'real deployment'.
保留一组单独的模板有更好的解决办法吗?我调查了用户分配的身份,这似乎可以解决问题,但 ARM 模板不支持它们。我检查了是否有一种方法可以通过检查资源是否已经存在来使 'init' 步骤成为条件,这也不支持通过 ARM 模板。
如果要维护单个 ARM 模板,可以使用 nested deployments 定义资源然后再次引用它以更新它。
在下面的示例中,我使用系统分配的托管标识、Key Vault 和 RSA 密钥创建服务总线。在取决于所生成的密钥的同一 ARM 模板内的嵌套部署中,我随后更新服务总线以启用加密。全部在同一个模板中的一个优点是 resourceId
和 reference
可以使用缩写语法(即只是资源名称)。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"name": {
"type": "string",
"defaultValue": "[resourceGroup().name]"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"tenantId": {
"type": "string",
"defaultValue": "[subscription().tenantId]"
}
},
"variables": {
"kv_name": "[concat(parameters('name'), 'kv')]",
"kv_version": "2019-09-01",
"sb_name": "[concat(parameters('name'), 'sb')]",
"sb_version": "2018-01-01-preview",
"sb_keyname": "sbkey"
},
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false
}
},
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "[variables('kv_version')]",
"name": "[variables('kv_name')]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('sb_name')]"
],
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[parameters('tenantId')]",
"accessPolicies": [
{
"tenantId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.tenantId]",
"objectId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.principalId]",
"permissions": {
"keys": [
"get",
"wrapKey",
"unwrapKey"
]
}
}
],
// Both must be enabled to encrypt Service Bus at rest.
"enableSoftDelete": true,
"enablePurgeProtection": true
}
},
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "[variables('kv_version')]",
"name": "[concat(variables('kv_name'), '/', variables('sb_keyname'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('kv_name')]"
],
"properties": {
"kty": "RSA",
"keySize": 2048,
"keyOps": [
"wrapKey",
"unwrapKey"
],
"attributes": {
"enabled": true
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-10-01",
"name": "sb_deployment",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('kv_name'), variables('sb_keyname'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false,
"encryption": {
"keySource": "Microsoft.KeyVault",
"keyVaultProperties": [
{
// Ideally should specify a specific version, but no ARM template function to get this currently.
"keyVaultUri": "[reference(variables('kv_name')).vaultUri]",
"keyName": "[variables('sb_keyname')]"
}
]
}
}
}
]
}
}
}
]
}
要使用 Azure CLI 进行部署:
az group create -g rg-example -l westus2
az deployment group create -g rg-example -f template.json --parameters name=example