英文:
Maps containing keys with spaces are not properly validated when those keys are used as resource names
问题
我在terraform导入某些角色分配资源时遇到了问题,特别是在terraform中涉及到"APP CONFIG DATA READER"角色分配方面。
我需要解决的问题是由于我们的基础设施即代码(IaC)的演进,以使terraform计划更加可读和明确。以下是更改的角色分配代码:
module "my_role_assignment_slot_to_app_config" {
for_each = local.map_slot_app_config
source = "../../resourceModules/role_assignment"
scope = each.value.config_id
role_definition_names = ["Reader","App Configuration Data Reader"]
principal_id = each.value.slot_guid
}
以及角色分配的以下模块:
resource "azurerm_role_assignment" "my_role_assignment" {
for_each = toset(var.role_definition_names)
scope = var.scope
role_definition_name = each.value
principal_id = var.principal_id
}
此代码将计划如下,更加可读:
但是,如您所见,azurerm_role_assignment.my_role_assignment
的索引包含空格。
这导致我们无法使用Azure DevOps上的AzureCli任务中的PowerShell脚本对角色分配进行terraform导入(因为在编写IaC之前已手动创建):
- task: AzureCli@2
displayName: Runs tfImport.ps1
condition: and(succeeded(), eq(variables['toUpdate.scriptExists'], 'true')) # test script presence
name: tfImport.ps1
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
scriptType: ps
scriptLocation: InlineScript
inlineScript: |
$Env:ARM_CLIENT_ID = "$Env:servicePrincipalId"
$Env:ARM_CLIENT_SECRET = "$Env:servicePrincipalKey"
$Env:ARM_TENANT_ID = "$Env:tenantId"
$Env:ARM_SUBSCRIPTION_ID = az account list --query "[?isDefault].id" -o tsv
$Env:TF_LOG = "${{ parameters.TF_LOG }}"
terraform init `
-migrate-state `
-backend-config="resource_group_name=${{ parameters.storageAccountResourceGroup }}" `
-backend-config="storage_account_name=${{ parameters.storageAccount}}" `
-backend-config="key=${{ parameters.storageContainer }}" `
-backend-config="container_name=${{ parameters.stateBlobContainer }}"
// 在此运行我的tfImport.ps1脚本
./tfImport.ps1
workingDirectory: $(pipeline_artefact_folder_extract)/
addSpnToEnvironment: true
failOnStderr: false
continueOnError: true
我使用的脚本包含以下terraform导入行:
terraform import 'module.my_role_assignment_slot_to_app_config["sit03_z-adf-ftnd-shrd-npd-ew1-cfg01"].azurerm_role_assignment.my_role_assignment["App Configuration Data Reader"]' /subscriptions/**********/resourceGroups/*********/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/<role_assignment_id>
因此,我遇到了以下错误:
(ID已删除)
经过一些研究,我找到了以下链接,解释了原因并为我提供了一种解决方案的起点:
https://github.com/hashicorp/terraform/issues/25116
但我必须进一步查找一种在不使用startProcess方法的情况下使用我的PowerShell脚本的方法。
由于我还必须根据其PrincipalId获取角色分配的resourceId(可以使用以下方法获取具有"App Configuration Data Reader"角色的app_config上的资源的PrincipalId):
# 特定范围(如app_config)上的角色分配
$rsRolesCfg = az role assignment list --scope /subscriptions/******/resourceGroups/*******/providers/Microsoft.AppConfiguration/configurationStores/******-cfg01 | ConvertFrom-Json
$myRole = $rsRolesCfg | Where-Object roleDefinitionName -eq 'App Configuration Data Reader' | Where-Object id -like "<app_config_resourceId>"
## principalId是在范围上获取角色的对象的ID!
# 从PrincipalId / ObjetcId获取resourceId(不包括'<> '在body中,当然 :)
$resourceId = (az rest --method POST --url 'https://graph.microsoft.com/v1.0/directoryObjects/getByIds' --headers 'Content-Type=application/json' --body '{"ids":["<PrincipalId>"]}' | ConvertFrom-Json | Select-Object value).value.alternativeNames[1]
来自https://stackoverflow.com/questions/67943880/how-to-get-azure-ad-object-by-object-id-using-azure-cli的解决方案(非常感谢!)
我不得不在PowerShell终端中本地测试它...所以它并没有按预期工作。
因此,然后,我稍微更改了脚本并找到了解决方案(作为我的问题的解决方案的下一篇帖子)。
英文:
I faced an issue when I had to terraform import some role_assignment resources, specially regarding the APP CONFIG DATA READER role assignment, in terraform.
the problem I had to solve was due to an evolution of our iac to make the terraform plan more readable and explicit.
Here is the code for role assignment that changed :
module "my_role_assignment_slot_to_app_config" {
for_each = local.map_slot_app_config
source = "../../resourceModules/role_assignment"
scope = each.value.config_id
role_definition_names = ["Reader","App Configuration Data Reader"]
principal_id = each.value.slot_guid
}
with the following module for role assignments :
```hcl
resource "azurerm_role_assignment" "my_role_assignment" {
for_each = toset(var.role_definition_names)
scope = var.scope
role_definition_name = each.value
principal_id = var.principal_id
}
This code would plan the following, more readable :
But as you can see, the index for the azurerm_role_assignment.my_role_assignment
contains spaces.
This was preventing us to terraform import the role assignment (as it has been created manually before the iac was coded) using powershell script in an azureCli task on azure Devops :
- task: AzureCli@2
displayName: Runs tfImport.ps1
condition: and(succeeded(), eq(variables['toUpdate.scriptExists'], 'true')) # test script presence
name: tfImport.ps1
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
scriptType: ps
scriptLocation: InlineScript
inlineScript: |
$Env:ARM_CLIENT_ID = "$Env:servicePrincipalId"
$Env:ARM_CLIENT_SECRET = "$Env:servicePrincipalKey"
$Env:ARM_TENANT_ID = "$Env:tenantId"
$Env:ARM_SUBSCRIPTION_ID = az account list --query "[?isDefault].id" -o tsv
$Env:TF_LOG = "${{ parameters.TF_LOG }}"
terraform init `
-migrate-state `
-backend-config="resource_group_name=${{ parameters.storageAccountResourceGroup }}"`
-backend-config="storage_account_name=${{ parameters.storageAccount}}" `
-backend-config="key=${{ parameters.storageContainer }}" `
-backend-config="container_name=${{ parameters.stateBlobContainer }}"
// runs my tfImport.ps1 script here
./tfImport.ps1
workingDirectory: $(pipeline_artefact_folder_extract)/
addSpnToEnvironment: true
failOnStderr: false
continueOnError: true
The script I used had the following terraform import line,
terraform import 'module.my_role_assignment_slot_to_app_config[\"sit03_z-adf-ftnd-shrd-npd-ew1-cfg01\"].azurerm_role_assignment.my_role_assignment[\"App Configuration Data Reader\"]' /subscriptions/**********/resourceGroups/*********/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/<role_assignment_id>
and so I've had the following error :
(id datas removed)
After some researches, I've found the following link that explains the why and give to me one start of solution :
https://github.com/hashicorp/terraform/issues/25116
But I had to go further and find a way to use my powershell script without the startProcess method.
And as I had also to get my role_assignment resourceId from its PrincipalId (as we can gets the PrincipalId of resources that have the 'App Configuration Data Reader' role on the app_config using the following)
# role assignment over a specific scope (such as app_config)
$rsRolesCfg = az role assignment list --scope /subscriptions/******/resourceGroups/*******/providers/Microsoft.AppConfiguration/configurationStores/******-cfg01 | ConvertFrom-Json
$myRole = $rsRolesCfg | Where-Object roleDefinitionName -eq 'App Configuration Data Reader' | Where-Object id -like "*<app_config_resourceId>"
## principalId is the id of the object that get the role over the scope !
# GetsresourceId from PrincipalId / ObjetcId (without the '<>' on body, off course :) ) :
$resourceId = (az rest --method POST --url 'https://graph.microsoft.com/v1.0/directoryObjects/getByIds' --headers 'Content-Type=application/json' --body '{\"ids\":[\"<PrincipalId>\"]}' | ConvertFrom-Json | Select-Object value).value.alternativeNames[1]
Solution from https://stackoverflow.com/questions/67943880/how-to-get-azure-ad-object-by-object-id-using-azure-cli (thanks a lot !)
I had to test it locally in powershell terminal... So it did not work as expected.
So then, I change a little bit the script and got the solution (next post, as solution from my problem).
答案1
得分: 0
所以我不得不在本地测试我的get_ResourceId方法,在一个不接受上述代码的PowerShell VSCode终端上,因为Powershell会误解空格。
所以,在快速搜索之后,我明白了"`"是Powershell的转义字符,我测试了这个方法,并且得到了我期望的role_assignment的resourceId:
$rsRolesCfg = az role assignment list --scope /subscriptions/************/resourceGroups/******/providers/Microsoft.AppConfiguration/configurationStores/<app_configuration_name> | ConvertFrom-Json
($rsRolesCfg | Where-Object roleDefinitionName -eq 'App Configuration Data Reader') | ForEach-Object {$local=$_.principalId; (az rest --method POST --url 'https://graph.microsoft.com/v1.0/directoryObjects/getByIds' --headers 'Content-Type=application/json' --body "{`"ids`":[`"$local`"]}" | ConvertFrom-Json | Select-Object value).value.alternativeNames[1] }
所以,使用"`"对于我的问题是解决方案,所以我尝试在我的terraform导入脚本(在第一篇帖子中)中使用它,它也正常工作:
terraform import "module.my_role_assignment_slot_to_app_config[``"sit03_z-adf-ftnd-shrd-npd-ew1-cfg01``"].azurerm_role_assignment.my_role_assignment[``"App Configuration Data Reader``"]" /subscriptions/*****/resourceGroups/******/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/<role_assignment_id>
但是我还必须更改yaml任务,使用pscore而不是ps,如下所示:
- task: AzureCli@2
displayName: Runs tfImport.ps1
condition: and(succeeded(), eq(variables['toUpdate.scriptExists'], 'true')) # test script presence
name: tfImport.ps1
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
scriptType: **pscore**
然后,terraform导入脚本成功运行!
我为这个StackOverflow问题/解决方案使用了与GitHub中相同的“title”,这样那些正在寻找解决方案的人可以轻松地找到问题的解决方案...至少,我希望如此
感谢阅读!
英文:
So I've had to test my get_ResourceId methods in local on a powershell VSCode terminal, that does not accept the above code (as the paces wher badly interpreted by powershell)
So, after a quick search that explain to me that the "`" was the escape character for Powershell, I've tested this that works and give to me the expected resourceId for role_assignment :
$rsRolesCfg = az role assignment list --scope /subscriptions/************/resourceGroups/******/providers/Microsoft.AppConfiguration/configurationStores/<app_configuration_name> | ConvertFrom-Json
($rsRolesCfg | Where-Object roleDefinitionName -eq 'App Configuration Data Reader') | ForEach-Object {$local=$_.principalId; (az rest --method POST --url 'https://graph.microsoft.com/v1.0/directoryObjects/getByIds' --headers 'Content-Type=application/json' --body "{\`"ids\`":[\`"$local\`"]}" | ConvertFrom-Json | Select-Object value).value.alternativeNames[1] }
So, the use of "`" was the solution for my point, so I've tried to use it on my terraform import script (on first post) and it works fine also :
terraform import "module.my_role_assignment_slot_to_app_config[\`"sit03_z-adf-ftnd-shrd-npd-ew1-cfg01\`"].azurerm_role_assignment.my_role_assignment[\`"App Configuration Data Reader\`"]" /subscriptions/*****/resourceGroups/******/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/<role_assignment_id>
But I had also to change the yaml task, using pscore rather than ps, like the following :
- task: AzureCli@2
displayName: Runs tfImport.ps1
condition: and(succeeded(), eq(variables['toUpdate.scriptExists'], 'true')) # test script presence
name: tfImport.ps1
inputs:
azureSubscription: ${{ parameters.serviceConnection }}
scriptType: **pscore**
So then, the terrform import script was running with success !
I've used the same "title" for this stackOverflow question / solution as the one in the GitHub, so them peoples who are lokking for that solution could find easily the solution with the question... At least, I hope so
thanks for reading !
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论