Terraform:构建 ARM 配置时出错 - 仅支持使用 Azure CLI 进行身份验证

问题描述 投票:0回答:5

由于 terraform azurerm 提供程序缺少对 azure webapp 访问限制的支持(请参阅 github 问题)。我们使用

null_resource
local-exec
来应用访问限制:


  provisioner "local-exec" {
    command = <<COMMAND
      az webapp config access-restriction add --subscription ${self.triggers.subscription_id} --resource-group ${self.triggers.resource_group} \
        --name ${self.triggers.web_app_name} --rule-name 'allow application gateway' --action Allow --vnet-name ${self.triggers.vnet_name} \
        --subnet ${self.triggers.subnet_name} --priority 100
    COMMAND
  }

我们的 terraform 代码随后由 azure DevOps Pipeline 运行,该管道使用服务连接(带有服务主体)通过 Azure 进行身份验证。以下任务正在尝试应用 terraform 资源:

  - task: TerraformCLI@0
    displayName: "Terraform apply"
    inputs:
      command: 'apply'
      commandOptions: '--var-file="./environments/${{ parameters.environment }}.tfvars"'
      workingDirectory: '$(System.DefaultWorkingDirectory)/${{ parameters.projectFolder }}'
      environmentServiceName: 'shared-${{ parameters.environment }}-001'

这会导致以下错误:

Error: Error running command '      az webapp config access-restriction remove --subscription shared-staging-001 --resource-group rg-hub-network-staging \
        --name landing-webapp-hub --rule-name 'allow application gateway'
': exit status 1. Output: Subscription 'shared-staging-001' not recognized.
Command group 'webapp config access-restriction' is in preview. It may be changed/removed in a future release.
Please run 'az login' to setup account.

不,我们尝试用纯 bash 脚本或 AzureCLI@2 任务替换 TerraformCLI@0 任务。

由于缺少信息,我们无法让 az login 在普通的 bash 脚本中工作。 here描述的方法也不起作用。

在 AzureCLI@2 任务中运行 terraform 命令看起来很有希望,但会导致一些与服务主体登录相关的奇怪错误:

  - task: AzureCLI@2
    displayName: "Terraform init"
    inputs:
      azureSubscription: shared-${{ parameters.environment }}-001
      scriptType: bash
      scriptLocation: inlineScript
      inlineScript: |
        terraform init --backend-config="./environments/${{ parameters.environment }}_backend.tfvars"

这会导致以下错误:

Initializing modules...
- app-gateway in modules/app-gateway
- dummy1 in modules/BRZ365-AppService
- dummy2 in modules/BRZ365-AppService
- hub-network in modules/hub-network
- landing_zone_app in modules/BRZ365-AppService
- squad-area in modules/squad-area

Initializing the backend...

Error: Error building ARM Config: Authenticating using the Azure CLI is only supported as a User (not a Service Principal).

To authenticate to Azure using a Service Principal, you can use the separate 'Authenticate using a Service Principal'
auth method - instructions for which can be found here: 

Alternatively you can authenticate using the Azure CLI by using a User Account.
azure-devops terraform azure-pipelines azure-cli
5个回答
21
投票

我终于让它与我在第一篇文章中描述的 AzureCLI 方法一起使用。我使用

addSpnToEnvironment
(它将服务提供商凭据添加到环境中,如 文档中所述)并按照 terraform 中的描述设置所需的参数。

- task: AzureCLI@2 displayName: "Terraform" inputs: azureSubscription: shared-${{ parameters.environment }}-001 scriptType: bash addSpnToEnvironment: true scriptLocation: inlineScript inlineScript: | export ARM_CLIENT_ID=$servicePrincipalId export ARM_CLIENT_SECRET=$servicePrincipalKey export ARM_TENANT_ID=$tenantId terraform init .....
    

4
投票
我通过

local-exec

解决了这个问题。

provisioner "local-exec" { command = <<COMMAND az login --service-principal --username #{APP_ID}# --password #{SP_PASSWORD}# --tenant #{TENANT_ID}# az webapp config access-restriction add --resource-group ${azurerm_resource_group.example.name} --name ${azurerm_app_service.example.name} --rule-name developers --action Allow --ip-address 130.220.0.0/27 --priority 200 COMMAND interpreter = ["PowerShell", "-Command"] }

不幸的是,我必须为此目的创建另一个服务主体,因为我不想重置 Azure DevOps 使用的服务主体(但您可以尝试并重用这个服务主体)。

我使用了这些命令:

az ad sp create-for-rbac --name sp-for-cli az role assignment create --assignee APP_ID --role Contributor

接下来,我使用上面命令给出的值在发布管道上声明了变量 APP_ID、SP_PASSWORD 和 TENANT_ID。

作为最后一步,我添加了

令牌替换步骤

steps: - task: qetza.replacetokens.replacetokens-task.replacetokens@3 displayName: 'Replace tokens in main.tf' inputs: rootDirectory: '$(System.DefaultWorkingDirectory)/terraform/drop' targetFiles: main.tf

现在当我跑步时

az webapp config access-restriction show --resource-group example-resources --name example-app-service-for-cli

我得到:

"ipSecurityRestrictions": [ { "action": "Allow", "additional_properties": {}, "description": null, "ip_address": "130.220.0.0/27", "name": "developers", "priority": 200, "subnet_mask": null, "subnet_traffic_tag": null, "tag": "Default", "vnet_subnet_resource_id": null, "vnet_traffic_tag": null },

您可以在

here找到完整代码。


3
投票
我在使用 Terraform 在 Azure 上设置资源时遇到了类似的问题。

当我运行

terraform plan

时,我收到错误:

│ Error: building AzureRM Client: Authenticating using the Azure CLI is only supported as a User (not a Service Principal). │ │ To authenticate to Azure using a Service Principal, you can use the separate 'Authenticate using a Service Principal' │ auth method - instructions for which can be found here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret │ │ Alternatively you can authenticate using the Azure CLI by using a User Account. │ │ with provider["registry.terraform.io/hashicorp/azurerm"], │ on main.tf line 18, in provider "azurerm": │ 18: provider "azurerm" {
我是这样解决的。

问题是我使用 Terraform 验证 Azure CLI 的方式错误。我使用下面的命令通过服务主体对其进行身份验证:

az login --service-principal --username $SERVICE_PRINCIPAL_APP_ID --password $SERVICE_PRINCIPAL_PASSWORD --tenant $SERVICE_PRINCIPAL_TENANT_ID
问题在于,上面的命令不会将您作为用户进行身份验证,而是作为服务主体进行身份验证,这不是 Terraform 支持的使用服务主体进行身份验证的方式。

[ { "cloudName": "AzureCloud", "homeTenantId": "f8256ac9-e164-4ac6-a487-0f6e3dc17532", "id": "bec123cd-bead-43ba-90c6-5235cririe903", "isDefault": true, "managedByTenants": [], "name": "my-subscription-1", "state": "Enabled", "tenantId": "f8556ac9-e159-4ac6-a487-8r9erhwjw", "user": { "name": "r673reb62-bbf7-40e1-ab10-ry45640484", "type": "servicePrincipal" } } ]
执行此操作的正确方法是简单地运行以下命令:

az login
然后 Azure CLI 将打开一个浏览器窗口,我将在其中登录到门户上的 Azure 帐户并获得用户身份验证。如果您有多个订阅,它会选择您当前登录的订阅作为默认订阅。

[ { "cloudName": "AzureCloud", "homeTenantId": "f8256ac9-e164-4ac6-a487-0f6e3dc17532", "id": "bec123cd-bead-43ba-90c6-5235cririe903", "isDefault": true, "managedByTenants": [], "name": "my-subscription-1", "state": "Enabled", "tenantId": "f8556ac9-e159-4ac6-a487-8r9erhwjw", "user": { "name": "[email protected]", "type": "user" } }, { "cloudName": "AzureCloud", "homeTenantId": "ghfjg6ac9-e164-7466-a487-0f6e3dc17hjr", "id": "rtkrt7f3d-51b2-7587-88b7-d29ftheruofw", "isDefault": false, "managedByTenants": [], "name": "my-subscription-2", "state": "Enabled", "tenantId": "f8556ac9-e159-4ac6-a487-8r9erhwjw", "user": { "name": "[email protected]", "type": "user" } } ]

或者如果您希望作为服务主体进行身份验证,那么您将使用提供的变量名称导出以下变量:

export ARM_CLIENT_ID="your-service-principal-appid" export ARM_CLIENT_SECRET="your-service-principal-password" export ARM_SUBSCRIPTION_ID="your-current-subscription-id" export ARM_TENANT_ID="your-tenant-id"
现在,您可以运行您的

terraform plan

,一切都会正常工作。

资源在 Terraform 中配置服务主体


0
投票
2023 年 11 月更新

我通过使用 ARM 前缀并将我的 azurerm 提供程序更改为 3.0 来使其工作


0
投票
@quadroid 接受的答案是完美的,这非常有帮助并且节省了我很多时间。设置

addSpnToEnvironment

 并使用 
export commands
 设置 Azure 环境变量是解决问题的关键。

但它不支持

管理组(如果你了解AWS,它类似于AWS跨账户承担角色),仅适用于当前订阅。

了解 Azure RBAC 的范围

    管理组
  • 订阅
  • 资源组
  • 资源

所以我得到的错误是

Error: building account: unable to configure ResourceManagerAccount: subscription ID could not be determined and was not specified
我终于与管理组解决了这个问题,我可以对该管理组下的任何订阅运行 terraform/terragrunt 命令。

    使用
  • addSpnToEnvironment
     并将其设置为 
    true
    (它将服务提供商凭据添加到环境中,如
    文档中所述)
  • 按照 terraform
  • 的描述设置 Azure 环境变量。
  • # these variables are automatically generated by `addSpnToEnvironment` set to `true` export ARM_CLIENT_ID=$servicePrincipalId export ARM_CLIENT_SECRET=$servicePrincipalKey export ARM_TENANT_ID=$tenantId # this variable need be input by pipeline's parameters or hardcode if you know its subscription id export ARM_SUBSCRIPTION_ID="20000000-0000-0000-0000-000000000000" or export ARM_SUBSCRIPTION_ID="$(subscription_id)"
最终的管道供大家参考

parameters: - name: subscription_id displayName: 'Azure Subscription ID' type: string stages: - stage: TerraformDeployment jobs: - job: TerraformDeployment displayName: TerraformDeployment steps: - task: AzureCLI@2 displayName: "Terraform" inputs: azureSubscription: <replace_with_service_account_with_management_group_permission> scriptType: bash addSpnToEnvironment: true scriptLocation: inlineScript inlineScript: | export ARM_CLIENT_ID=$servicePrincipalId export ARM_CLIENT_SECRET=$servicePrincipalKey export ARM_TENANT_ID=$tenantId # it need be set via Environment variable, or get from parameters export ARM_SUBSCRIPTION_ID="$(subscription_id)" terraform init .....

© www.soinside.com 2019 - 2024. All rights reserved.