我正在尝试创建两个可重复使用的二头肌模块,以允许读取所选 keystore 中的特定 secret 。为此,我首先声明角色定义:
targetScope = 'subscription'
param subscriptionId string
param resourceGroupName string
param keyVaultName string
param allowedSecrets array
param managementGroupRoot string
var keyVaultScope = '/subscriptions/${subscriptionId}/resourcegroups/${resourceGroupName}/providers/Microsoft.KeyVault/vaults/${keyVaultName}'
var assignableScopes = [for secretName in allowedSecrets: '${keyVaultScope}/secrets/${secretName}']
var roleName = 'Limitied ${keyVaultName} secret reader ${managementGroupRoot}'
// Permissions based on Key Vault Secrets User
// https://www.azadvertizer.net/azrolesadvertizer/4633458b-17de-408a-b874-0445c86b69e6.html
resource key_vault_secrets_user_role_definition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
name: '4633458b-17de-408a-b874-0445c86b69e6'
}
resource role_definition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' = {
name: guid(roleName)
properties: {
roleName: roleName
description: 'Allows reading specific secrets in the ${keyVaultName} key vault in ${managementGroupRoot}'
assignableScopes: assignableScopes
permissions: key_vault_secrets_user_role_definition.properties.permissions
}
}
output roleDefinitionId string = role_definition.id
角色定义创建效果很好,并且产生了以下角色定义:
{
"assignableScopes": [
"/subscriptions/subscriptionId/resourcegroups/resourceGroupName/providers/Microsoft.KeyVault/vaults/keyVaultName/secrets/secretName",
"/subscriptions/subscriptionId/resourcegroups/resourceGroupName/providers/Microsoft.KeyVault/vaults/keyVaultName/secrets/anotherSecret"
],
"description": "Allows reading specific secrets in the xxx} key vault in xxx",
"id": "/subscriptions/xxx/providers/Microsoft.Authorization/roleDefinitions/xxx",
"name": "c64aa8eb-479d-5c2d-8f25-b1acb151c0af",
"permissions": [
{
"actions": [],
"dataActions": [
"Microsoft.KeyVault/vaults/secrets/getSecret/action",
"Microsoft.KeyVault/vaults/secrets/readMetadata/action"
],
"notActions": [],
"notDataActions": []
}
],
"roleName": "Limitied key vault secret reader xxx",
"roleType": "CustomRole",
"type": "Microsoft.Authorization/roleDefinitions"
}
接下来,我想将此角色分配给服务主体。这里的细节我并不完全清楚,但由于我希望这个主体能够读取 n 个单独的 secret ,所以我假设我需要迭代可分配的范围.
为此,我有一个主文件:
targetScope = 'managementGroup'
resource roleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
name: roleDefinitionId
}
module example 'module.bicep' = {
name: 'example-${managementGroup().name}'
scope: resourceGroup(keyVaultSubscriptionId, keyVaultResourceGroupName)
params: {
roleDefinitionId: roleDefinitionId
assignableScopes: roleDefinition.properties.assignableScopes
managementGroupName: managementGroup().name
keyVaultName: keyVaultName
}
}
模块看起来像这样:
targetScope = 'resourceGroup'
param roleDefinitionId string
param assignableScopes array = []
param managementGroupName string
param keyVaultName string
param principalId string
// Full scope looks like this:
// '/subscriptions/<sub>/resourcegroups/<rg>/providers/Microsoft.KeyVault/vaults/<vault>/<secret>'
// Hence 8 is the secret name
// Also verifies that the secrets exist
var secretNames = [for scope in assignableScopes: split(scope, '/')[8]]
resource secretResources 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' existing = [for secret in secretNames: {
name: '${keyVaultName}/${secret}'
}]
// Iterating the secretResources array is not supported, so we iterate the scope which they are based
resource regressionTestKeyVaultReaderAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for (scope, index) in assignableScopes: {
name: guid(managementGroupName, principalId, scope)
scope: secretResources[index] // Access by index and apply this role assignment to all assignable scopes
properties: {
principalId: principalId
roleDefinitionId: roleDefinitionId
}
}]
但是,此操作失败并出现以下错误:
ERROR: ***"code": "InvalidTemplate", "message": "Deployment template validation failed: 'The template resource 'exmaple-xxx' at line '97' and column '5' is not valid: Unable to evaluate template language function 'extensionResourceId': function requires exactly two multi-segmented arguments. The first must be the parent resource id while the second must be resource type including resource provider namespace. Current function arguments '/providers/Microsoft.Management/managementGroups/ESD,Microsoft.Authorization/roleDefinitions,/subscriptions/***/providers/Microsoft.Authorization/roleDefinitions/xxx'. Please see https://aka.ms/arm-template-expressions/#extensionresourceid for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.", "additionalInfo": [***"type": "TemplateViolation", "info": ***"lineNumber": 97, "linePosition": 5, "path": "properties.template.resources[6]"***]***
我正在使用 az 在 GitHub 管道中部署,因此我尝试访问请求和响应,但无济于事:
$deployment = az deployment mg create | ConvertFrom-Json // additional params
Write-Host "Request: $(ConvertTo-Json -InputObject $deployment.request)" // Request: null
Write-Host "Response: $(ConvertTo-Json -InputObject $deployment.response)" // Response: null
这个错误对我来说非常神秘,我真的不知道发生了什么,因为我什至没有使用正在引用的实用方法。我猜测向 ARM 的转换会在后台执行一些操作。 vscode 说一切都很好。
我做错了什么?我唯一的猜测是作业的范围部分,但我不知道如何纠正它。
任何帮助将不胜感激。
更新
我在尝试解决此问题时发现的一些其他信息。模板验证失败,部署甚至无法启动。我构建了主文件和模块二头肌文件,看看这是否会提供一些额外的上下文。该模块看起来不错,但 main 的模块资源有错误:
因此,这是在 main 文件中,targetScope = 'managementGroup'
,而 targetScope = 'resourceGroup'
的模块未显示任何验证构建时出错。
更新2
当编译到 ARM 时,我看到以下值从 main 传递到模块:
"assignableScopes": {
"value": "[reference(extensionResourceId(managementGroup().id, 'Microsoft.Authorization/roleDefinitions', parameters('secretReaderRoleDefinitionId')), '2018-01-01-preview').assignableScopes]"
},
AFAICT 这是 3 个参数,我在 GitHub 管道中收到的错误是:
Unable to evaluate template language function 'extensionResourceId': function requires exactly two multi-segmented arguments.
阅读 docs 时,情况似乎并非如此。关于该功能。
更新3
该错误是在我在 ubuntu-latest 上运行的 GitHub 管道中产生的。我将在本地复制相同的命令,看看是否可以在出现运行程序问题时让它在这里工作。
更新4
在 GitHub 管道之外重现了完全相同的错误。
最佳答案
一些想法...
从安全角度来看,创建具有有限可分配范围的自定义 roleDef 并没有太多值(value),因为内置的 roleDef 具有相同的权限,具有更广泛的范围 - 并且分配权限的主体将是能够分配另一个。
如果您的目标是简单地迭代 secret 并将角色分配给这些 secret ,那么您所需要的只是这些 secret 的 ResourceId。看起来您正在尝试从 roleDefinition 中提取该列表(而不是传递给模板),这是可能的,但看起来有些复杂。这意味着每当您想要“调整”此部署时,您都必须定义新角色或修改现有角色,两者都会产生一些下游后果。租户中可以定义的自定义角色数量有限,当您更改它们时,您可能会无意中破坏现有分配(删除访问权限或无意中授予新角色访问权限)。
也就是说,我在您的代码中没有看到该特定错误,但也许还有其他一些错误 - 试试这个:
main.bicep
targetScope = 'managementGroup'
param roleDefinitionId string
param keyVaultSubscriptionId string
param keyVaultResourceGroupName string
param keyVaultName string
param principalId string
resource roleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
scope: subscription(keyVaultSubscriptionId)
name: roleDefinitionId
}
module example 'module.bicep' = {
name: 'example-${managementGroup().name}'
scope: resourceGroup(keyVaultSubscriptionId, keyVaultResourceGroupName)
params: {
roleDefinitionId: roleDefinitionId
assignableScopes: roleDefinition.properties.assignableScopes
keyVaultName: keyVaultName
principalId: principalId
}
}
module.bicep
targetScope = 'resourceGroup'
param roleDefinitionId string
param assignableScopes array
param keyVaultName string
param principalId string
var secretNames = [for scope in assignableScopes: last(split(scope, '/'))]
resource secretResources 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' existing = [for secret in secretNames: {
name: '${keyVaultName}/${secret}'
}]
resource roleDef 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: roleDefinitionId
}
resource regressionTestKeyVaultReaderAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for (scope, index) in assignableScopes: {
name: guid(roleDef.id, principalId, scope)
scope: secretResources[index]
properties: {
principalId: principalId
roleDefinitionId: roleDef.id
}
}]
关于azure - 使用二头肌的 secret 范围角色定义和分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73884372/