包含带有空格的键的地图,在这些键被用作资源名称时未能得到适当验证。

huangapple go评论72阅读模式
英文:

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 &quot;my_role_assignment_slot_to_app_config&quot; {
  for_each = local.map_slot_app_config
  source = &quot;../../resourceModules/role_assignment&quot;
  scope = each.value.config_id
  role_definition_names = [&quot;Reader&quot;,&quot;App Configuration Data Reader&quot;]
  principal_id = each.value.slot_guid
}

with the following module for role assignments : 

```hcl
resource &quot;azurerm_role_assignment&quot; &quot;my_role_assignment&quot; {
  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[&#39;toUpdate.scriptExists&#39;], &#39;true&#39;))  # test script presence
        name: tfImport.ps1
        inputs:
          azureSubscription: ${{ parameters.serviceConnection }}
          scriptType: ps
          scriptLocation: InlineScript
          inlineScript: |
            $Env:ARM_CLIENT_ID       = &quot;$Env:servicePrincipalId&quot;
            $Env:ARM_CLIENT_SECRET   = &quot;$Env:servicePrincipalKey&quot;
            $Env:ARM_TENANT_ID       = &quot;$Env:tenantId&quot;
            $Env:ARM_SUBSCRIPTION_ID = az account list --query &quot;[?isDefault].id&quot; -o tsv        
            $Env:TF_LOG = &quot;${{ parameters.TF_LOG }}&quot;            
        
            terraform init `
              -migrate-state `
              -backend-config=&quot;resource_group_name=${{ parameters.storageAccountResourceGroup }}&quot;`
              -backend-config=&quot;storage_account_name=${{ parameters.storageAccount}}&quot; `
              -backend-config=&quot;key=${{ parameters.storageContainer }}&quot; `
              -backend-config=&quot;container_name=${{ parameters.stateBlobContainer }}&quot;
        
            // 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  &#39;module.my_role_assignment_slot_to_app_config[\&quot;sit03_z-adf-ftnd-shrd-npd-ew1-cfg01\&quot;].azurerm_role_assignment.my_role_assignment[\&quot;App Configuration Data Reader\&quot;]&#39;  /subscriptions/**********/resourceGroups/*********/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/&lt;role_assignment_id&gt;

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 &#39;App Configuration Data Reader&#39;  | Where-Object id -like &quot;*&lt;app_config_resourceId&gt;&quot;
    ## principalId is the id of the object that get the role over the scope !
    
    # GetsresourceId from PrincipalId / ObjetcId (without the &#39;&lt;&gt;&#39; on body, off course :) ) : 
    $resourceId = (az rest --method POST --url &#39;https://graph.microsoft.com/v1.0/directoryObjects/getByIds&#39; --headers &#39;Content-Type=application/json&#39;  --body &#39;{\&quot;ids\&quot;:[\&quot;&lt;PrincipalId&gt;\&quot;]}&#39; | 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/&lt;app_configuration_name&gt; | 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/&lt;role_assignment_id&gt;

但是我还必须更改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/&lt;app_configuration_name&gt; | ConvertFrom-Json

($rsRolesCfg | Where-Object roleDefinitionName -eq &#39;App Configuration Data Reader&#39;) | ForEach-Object {$local=$_.principalId; (az rest --method POST --url &#39;https://graph.microsoft.com/v1.0/directoryObjects/getByIds&#39; --headers &#39;Content-Type=application/json&#39;  --body &quot;{\`&quot;ids\`&quot;:[\`&quot;$local\`&quot;]}&quot; | 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 &quot;module.my_role_assignment_slot_to_app_config[\`&quot;sit03_z-adf-ftnd-shrd-npd-ew1-cfg01\`&quot;].azurerm_role_assignment.my_role_assignment[\`&quot;App Configuration Data Reader\`&quot;]&quot;  /subscriptions/*****/resourceGroups/******/providers/Microsoft.AppConfiguration/configurationStores/z-adf-ftnd-shrd-npd-ew1-cfg01/providers/Microsoft.Authorization/roleAssignments/&lt;role_assignment_id&gt;

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[&#39;toUpdate.scriptExists&#39;], &#39;true&#39;))  # 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 !

huangapple
  • 本文由 发表于 2023年6月2日 15:03:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76387859.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定