Azure SPN from a workstation

To authenticate Terraform with Azure, you can use Azure Active Directory (Azure AD) to generate a service principal (SPN), and then use the workstation CLI to configure the necessary environment variables for Terraform to access and manage Azure resources.

A best practice is creating an SPN with a limited blast radius by limiting its access to certain working sections in Azure, such as a specific subscription or a resource group. You could grant it contributor rights to all your subscriptions, but this is > not advised. However, this means you need to manage multiple SPN accounts if you have multiple subscriptions. Using your own interactive Azure credential is not recommended, as it can often have additional access permissions and is a powerful tool for hackers.

When using Terraform from your workstation where you are running the Terraform commands as terraform apply yourself, it’s advised to use environment variables to store the credentials. It means the SPN credentials are not saved to a code repository and, at a minimum, only available from the workstation itself. You should never write credentials into your code as it makes it hard to limit exposure.

Set the SPN credentials as environment variables

This method stores the SPN credentials as environment variables on the workstation executing the Terraform code.

You load the authentication tokens into your workstation environment variables, and they’ll then will be called by Terraform when running terraform plan or terraform apply

Create the environment variables

This step will set the environment variables permanently which means they’ll be written to the system and always exist. Replace your_value with the output of the SPN creation command. Run this on a Terminal session on your Windows workstation.

Loading all the values is ideal if you have a single SPN to use. There are workarounds if you have multiple SPN, but it depends how fine grained you are with your access. For instance, if you have a single SPN for multiple subscriptions you could ommit loading the subscription value and code that in your Terraform providers file instead.

setx ARM_CLIENT_ID your_value
setx ARM_CLIENT_SECRET my_value
setx ARM_TENANT_ID my_value
setx ARM_SUBSCRIPTION_ID my_value

You can use this command to view the environment variables in the Terminal.

gci env:ARM_*

How Terraform uses the environment variables

By default, if you load all the SPN credentials into the environment variables, the Terraform configuration files do not need any specific configuration set to use the environment variables. When Terraform executes, it will look for and load the variables automatically so long as they start with ARM_. However, if you need to split your SPN values between environment variables and in-code you can do so, as demonstrated below.

Here are two examples of some simple Terraform code that creates an Azure resource group. The code can be copied into a single main.tf file and executed.

The single subscription code executes with zero edits, it relies on all four SPN values being loaded as environment variables.

The multi subscription code requires you to supply the azure subscription_id in the code but relies on the other three SPN values being loaded as environment variables. Doing it this way is useful if you have a single SPN but it has permission to multiple subscriptions in the same Azure tenant. It’s not ideal but also not too dangerous to have the subscription_id written to your VSC.


// This relies on all SPN values being set in 
// the environment variables

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0.2"
    }
  }

  required_version = ">= 1.1.0"
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "westus2"
}

// This relies on the SPN having access to all
// your subscriptions and you need to code the
// subscription ID only.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0.2"
    }
  }

  required_version = ">= 1.1.0"
}

provider "azurerm" {
  features {}

  subscription_id = "<your_subscription_id>"
}

resource "azurerm_resource_group" "rg" {
  name     = "myTFResourceGroup"
  location = "westus2"
}

The following image shows the basic layout of using an SPN in Azure when interacting with Azure from your workstation.

image

References

Authenticate Terraform to Azure

Last modified July 21, 2024: update (e2ae86c)