Ошибка выдачи конвейера Azure DevOps с Terraform при развертывании в Azure

Я пытаюсь развернуть виртуальную машину в существующей группе доступности и VNET/SNET в определенной существующей группе ресурсов. Я использую Terraform с открытым исходным кодом, и мой файл состояния хранится в контейнере для хранения.

Это мой файл конвейера ниже

variables:
  - group: infra-variables
  
trigger:
  branches:
    include:
    - master
  paths:
    include:
    - Terraform-Test 
    exclude:
    - README.md
  
stages:
- stage: Validate
  displayName: Validate
  jobs:
  - job: validate
    pool:
      vmImage: ubuntu-latest
    steps:
    - checkout : self 
    # - task: AzureCLI@2
    #   displayName : 
    #   inputs:
    #     azureSubscription: 'PalTest'
    #     scriptType: 'bash'
    #     scriptLocation: 'inlineScript'
    #     inlineScript: |
    #       az account set --subscription $AZURE_SUBSCRIPTION_ID
    #       az login --service-principal -u $AZURE_CLIENT_ID -p $AZURE_CLIENT_SECRET --tenant $AZURE_TENANT_ID 
    #       STORAGE_ACCOUNT_KEY=$(az storage account keys list -g $(Terraform_Backend_RG) -n $(TF_STATE_BLOB_ACCOUNT_NAME) | jq ".[0].value" -r)
    #       echo "setting storage account key variable"
    #       echo "##vso[task.setvariable variable=ARM_ACCESS_KEY;issecret=true]$ARM_ACCESS_KEY"

    - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
      displayName: Install Terraform
      inputs:
        terraformVersion: 'latest'


  # Init
    - task: TerraformCLI@0
      displayName: Terraform Init
      inputs:
        backendType : 'azurerm'
        command: 'init'
        workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
        backendServiceArm: 'Pallab-ADO-Setup'
        backendAzureRmResourceGroupName: $(Terraform_Backend_RG)
        backendAzureRmStorageAccountName: $(TF_STATE_BLOB_ACCOUNT_NAME)
        backendAzureRmContainerName: $(TF_STATE_BLOB_CONTAINER_NAME)
        backendAzureRmKey: 'infrastructure/terraform.ntfstate'
        

  # Validate
    - task: TerraformCLI@0
      displayName: Validate Config
      inputs:
        command: 'validate'
        workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'

- stage: Plan
  displayName: Plan
  jobs:
  - job: plan
    pool:
      vmImage: ubuntu-latest
    steps:
    - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
      displayName: Install Terraform
      inputs:
        terraformVersion: 'latest'

  # Init
    - task: TerraformCLI@0
      displayName: Terraform Init
      inputs:
        backendType : 'azurerm'
        command: 'init'
        workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
        backendServiceArm: 'Pallab-ADO-Setup'
        backendAzureRmResourceGroupName: $(Terraform_Backend_RG)
        backendAzureRmStorageAccountName: $(TF_STATE_BLOB_ACCOUNT_NAME)
        backendAzureRmContainerName: $(TF_STATE_BLOB_CONTAINER_NAME)
        backendAzureRmKey: 'infrastructure/terraform.ntfstate'

  # Plan
    - task: TerraformCLI@0
      displayName: Plan Terraform Deployment
      inputs:
        backendType : 'azurerm'
        command: 'plan'
        commandOptions: '-input=false'
        environmentServiceName : 'Pallab-ADO-Setup'
        workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
        # backendServiceArm: 'PalTest'
        # backendAzureRmResourceGroupName: $(Terraform_Backend_RG)
        # backendAzureRmStorageAccountName: $(TF_STATE_BLOB_ACCOUNT_NAME)
        # backendAzureRmContainerName: $(TF_STATE_BLOB_CONTAINER_NAME)
        # backendAzureRmKey: 'infrastructure/terraform.tfstate'

# Approve
- stage: Approve
  displayName: Approve
  jobs:
  - job: approve
    displayName: Wait for approval
    pool: server
    steps: 
    - task: ManualValidation@0
      timeoutInMinutes: 60
      inputs:
        notifyUsers: '[email protected]'
        instructions: 'Review the plan in the next hour'

- stage: Apply
  displayName: Apply
  jobs:
  - job: apply
    pool:
      vmImage: ubuntu-latest
    steps:
      - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
        displayName: Install Terraform
        inputs:
          terraformVersion: 'latest'
      
      # Init
      - task: TerraformCLI@0
        displayName: TF Init 
        inputs:
          command: 'init'
          workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
          commandOptions: '-backend-config=storage_account_name=$(TF_STATE_BLOB_ACCOUNT_NAME) -backend-config=container_name=$(TF_STATE_BLOB_CONTAINER_NAME) -backend-config=key=$(ARM_ACCESS_KEY)'
          backendType: 'selfConfigured'


      # Apply
      - task: TerraformCLI@0
        displayName: TF Apply 
        env:
          ARM_SAS_TOKEN: $(ARM_ACCESS_KEY)
          ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
          ARM_CLIENT_SECRET: $(AZURE_CLIENT_SECRET)
          ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
          ARM_TENANT_ID: $(AZURE_TENANT_ID)
        inputs:
          command: 'apply'
          workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
          commandOptions: '-auto-approve'

Это мой код Terraform:

terraform {
  required_version = "~> 1.0"

  backend "azurerm" {
  key = "terraform.ntfstate"
}
  
  required_providers {
    azuread = "~> 2.0"  
    azurerm = "~> 2.0"
  }
}


provider "azurerm" {
  tenant_id       = var.tenant_id
  client_id       = var.client_id
  client_secret   = var.client_secret
  subscription_id = var.subscription_id
  features {}
}

data "azurerm_resource_group" "az-rg-wu" {
  name = "Great-Learning"
}

Я получаю эту ошибку на этапе планирования

Планирование провалилось. Terraform обнаружил ошибку при создании этого плана.

     building account: getting authenticated object ID: listing Service Principals: autorest.DetailedError{Original:adal.tokenRefreshError{message:"adal: Failed to unmarshal the service principal token during refresh. Error = 'invalid character '<' looking for beginning of value' JSON = '\r\n\r\n<!-- Copyright (C) Microsoft Corporation. All rights reserv


rror]Terraform command 'plan' failed with exit code '1'.
##[error]╷
│ Error: building account: getting authenticated object ID: listing Service Principals: autorest.DetailedError{Original:adal.tokenRefreshError{message:"adal: Failed to unmarshal the service principal token during refresh. Error = 'invalid character '<' looking for beginning of value' JSON = '\r\n\r\n<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->\r\n<!DOCTYPE html>\r\n<html dir=\"ltr\" class=\"\" lang=\"en\">\r\n<head>\r\n    <title>Sign in to your account</title>\r\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n   

Если я закомментирую приведенные ниже строки, я не получу указанную выше ошибку, и мой план будет успешным.

provider "azurerm" {
  # tenant_id       = var.tenant_id
  # client_id       = var.client_id
  # client_secret   = var.client_secret
  # subscription_id = var.subscription_id
  features {}
}

Но затем на этапе применения я столкнулся с ошибкой ниже на этапе «tf init»:

Initializing the backend...
╷
│ Error: Error building ARM Config: obtain subscription() from Azure CLI: parsing json result from the Azure CLI: waiting for the Azure CLI: exit status 1: ERROR: Please run 'az login' to setup account.
│ 
│ 
╵
##[error]Terraform command 'init' failed with exit code '1'.
##[error]╷
│ Error: Error building ARM Config: obtain subscription() from Azure CLI: parsing json result from the Azure CLI: waiting for the Azure CLI: exit status 1: ERROR: Please run 'az login' to setup account.

1
96
1

Ответ:

Решено

Судя по вашему описанию, вы можете обойти первую ошибку, прокомментировав блок субъекта-службы в файле .tf.

Ошибка: ошибка построения конфигурации ARM: получение подписки() из Azure CLI: анализ результата json из Azure CLI: ожидание Azure CLI: статус выхода 1: ОШИБКА: запустите «az login», чтобы настроить учетную запись.

Причина ошибки на этапе применения может заключаться в том, что вы не передали учетные данные подключения к службе на этапе инициализации terraform.

Блок кода:

  - task: TerraformCLI@0
    displayName: TF Init 
    inputs:
      command: 'init'
      workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
      commandOptions: '-backend-config=storage_account_name=$(TF_STATE_BLOB_ACCOUNT_NAME) -backend-config=container_name=$(TF_STATE_BLOB_CONTAINER_NAME) -backend-config=key=$(ARM_ACCESS_KEY)'
      backendType: 'selfConfigured'

Чтобы решить эту проблему, вам нужно изменить тип selfConfigured на тип azurerm на этапе инициализации Terraform. Вам также необходимо определить соединение службы на этапе применения terraform, чтобы убедиться, что оно может использовать правильный субъект службы.

Например:

stages:
- stage: Apply
  displayName: Apply
  jobs:
  - job: apply
    pool:
      vmImage: ubuntu-latest
    steps:
      - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
        displayName: Install Terraform
        inputs:
          terraformVersion: 'latest'
      
      # Init
      - task: TerraformCLI@0
        displayName: TF Init 
        inputs:
          command: 'init'
          workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
          backendType: 'azurerm'
          backendServiceArm: 'Pallab-ADO-Setup'
          backendAzureRmStorageAccountName: '$(TF_STATE_BLOB_ACCOUNT_NAME)'
          backendAzureRmContainerName: '$(TF_STATE_BLOB_CONTAINER_NAME)'
          backendAzureRmKey: '$(ARM_ACCESS_KEY)'


      # Apply
      - task: TerraformCLI@0
        displayName: TF Apply 
        env:
          ARM_SAS_TOKEN: $(ARM_ACCESS_KEY)
          ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
          ARM_CLIENT_SECRET: $(AZURE_CLIENT_SECRET)
          ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
          ARM_TENANT_ID: $(AZURE_TENANT_ID)
        inputs:
          command: 'apply'
          workingDirectory: '$(System.DefaultWorkingDirectory)/Terraform-Test'
          environmentServiceName: 'Pallab-ADO-Setup' #Add Correct Service Connection
          runAzLogin: true
          commandOptions: '-auto-approve'
  

Если вам нужно продолжать использовать тип selfConfigured на этапе инициализации terraform, вы можете добавить дополнительные задачи перед этапом инициализации terraform, чтобы выполнить команду az login с правильным подключением к службе.

Например:

- task: AzureCLI@2
  displayName: 'Azure CLI '
  inputs:
    azureSubscription: Pallab-ADO-Setup
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
     echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$servicePrincipalId" 
     
     echo "##vso[task.setvariable variable=ARM_CLIENT_SECRET]$servicePrincipalKey"
    
     echo "##vso[task.setvariable variable=ARM_TENANT_ID]$tenantId"
    addSpnToEnvironment: true

- bash: |
   az login --service-principal --username $(ARM_CLIENT_ID) --password $(ARM_CLIENT_SECRET)  --tenant $(ARM_TENANT_ID)

  displayName: 'Az login to set account'

- task: TerraformCLI@0
  displayName: TF Init