I am trying to deploy a VM in an existing availability set and VNET/SNET in a particular existing Resource Group I am using open source Terraform and my state file is stored in a storage container
This is my pipeline file below
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: 'pallabcd@hotmail.com'
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'
This is my Terraform Code :
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"
}
I am getting this error in the plan stage
Planning failed. Terraform encountered an error while generating this plan.
╷
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
If i comment out the below lines, i don't get the above error and my plan goes successfully
provider "azurerm" {
# tenant_id = var.tenant_id
# client_id = var.client_id
# client_secret = var.client_secret
# subscription_id = var.subscription_id
features {}
}
But then at the Apply Stage i encounter the below error at the 'tf init' stage :
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.
Based on your description, you can bypass the first error by commenting the service principal block in the .tf
file.
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.
For the error in the Apply stage, the cause of the issue can be that you haven't pass the service connection credentials to the terraform init step.
Code block:
- 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'
To solve this issue, you need to change the selfConfigured
type to azurerm
type in Terraform init step. And you also need to define the service connection in terraform apply step to make sure that it can use the correct service principal.
For example:
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'
If you need to keep using the selfConfigured
type in terraform init step, you can add additional tasks before terraform init step to execute the az login command with the correct service connection.
For example:
- 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