Terraform and Azure Resource Manager

This was originally going to be a post on deploying infrastructure using Terraform and Azure Resource Manager. Didn’t quite pan out. Here are the notes.

originally, this was going to be a few sections

  • Creating and configuring Azure to work with Terraform.
  • Terraforming a Azure resource group using Azure Resource Manager (ARM).
  • Configuring a base image.
  • Using Terraform and Ansible to deploy an infrastructure.

This first section is about configuring Azure to work with Terraform. There are a few guides out there that document the process of configuring Azure Terraform credentials and Azure AD applications, but there were aspects of it that are a bit confusing, so these blog posts are a collection of notes and discoveries about that process. Hopefully it can help others.

creating and automating the creation of custom Azure virtual machine image part 1

The first step in deploying infrastructure to Azure, is ensuring that you have proper access to various resource groups (or all resource groups). This is a quick walkthrough on configuring credentials so that terraform can configure Azure Resource Manager (ARM).

This post attempts to do the following:

  • Take a quick look at Azure and it’s two sided life (Azure classic and Azure Resource Manager).
  • Establish an Azure account.
  • Create an application.
  • Assign appropriate access rights in anticipation of using Terraform.

quick Azure overview

Currently, Azure is in a bit of a reorganization. There are effectively two Azure’s; Azure classic (found at https://manage.windowsazure.com/) and Azure Resource Manager (ARM). ARM is their newer model. It’s nice, resources are organized as a part of a resource group.

So, Microsoft has two portals, and has had them for a while. The old portal, Azure classic, is based around a service management model (service APIs). The new portal, Azure Resource Manager is based around a logical group model. ARM is focused on treating all resources (compute, storage, networking, etc) as a group. Some points about ARM:

  • Using ARM, you can deploy a selection of resources together (resource group), such as storage, DNS, load balancer, computing resources (VMs), network infrastructure, and security groups.
  • Deploy them as a template.
  • Configure dependencies and determine order.
  • Use role-based access to control who can access what resource group.
  • Tag resources (cue snarky AWS comment here… :wink:).

But to touch upon the AWS comparions, in Azure rights and access are controlled and allocated per resource group. It’s actually really slick. Having a newly created test resource group isolated and controlled, with the ability to tear it down as quickly is impressive. It makes the AWS model look very disorganized.

But in order to access these resource groups, Azure AD and the classic portal are required.

insert Azure Active Directory

Ah, Active Directory. What an adventure we’ve been through in our lives. One of my first jobs was to migrate an NT Domain to Active Directory. Azure AD is the heart of the user access control of Azure itself. In order to do anything with ARM (Azure 2.0), you’ll need to configure Azure AD, which can only be found in the classic portal (Azure 1.0). It’s as close as it gets to AWS IAM. Users added to Azure AD can either be native to that Azure AD domain, or Microsoft Live accounts.

Azure AD is an odd one. It is fairly critical to managing roles and access for Azure Resource Manager, but it’s still locked away in the classic portal. It will be interesting to see how Microsoft moves this forward.

first steps - create an Azure account

If you haven’t already create an Azure account, here’s a quick overview of establishing an Azure account (that comes with a free $200 worth of credit):

Pretty straightfoward.

subscription administrator accounts

The initial account (email address) used to create the Azure environment. This account is an external account to the Azure AD default domain, which is fine, just something to take note of. You can manage Azure Resource Manager using non-Azure AD accounts just as you can if they were accounts created within Azure AD.

After the initial account, feel free to create a new domain, create users within that domain, and add them as subscription administrators if necessary. In the end, all that is needed is a valid Azure AD domain to create the application in.

configure Azure AD Application - overview

In order to use Terraform with ARM, Terraform will need:

  • the subscription ID
  • the client ID
  • the client secret
  • and the tenant ID

These values will be stored in the ~/.azure/credentials file. The subscription ID and the tenant ID we can look up. The Azure AD application will allow us to generate the client ID and client secret.

subscription ID

Great reference right here.. In short:

  • Log into the classic portal - https://manage.windowsazure.com.
  • Scroll down and click “Settings”. You will see the subscription ID.
  • After getting the subscription ID, create a ~/.azure/credentials file:
[SUBSCRIPTION_ID_CAPTURED_ABOVE]
client_id = "TBD"
client_secret = "TBD"
tenant_id = "TBD"

This is the credentials file that Terraform will use.

create the Azure Application - client ID and client secret

  • Go to Azure Active Directory in the classic portal.
  • Click “Applications”.
  • Click “ADD” at the bottom.
  • Select “Add an application my organization is developing”.
  • Name it something, in this case, “terraform_application”. Leave the “WEB APPLICATION AND/OR WEB API” selected.
  • For the next window, the “SIGN-ON URL” and “APP ID URI” don’t matter. Enter in something like “https://terraform_application.lan".
  • With the Azure AD application created, click “CONFIGURE”. Scroll down to “CLIENT ID”. Add this to the ~/.azure/credentials file.
  • After documenting the client ID, scroll down to the “Keys” section. Select “2 years”.
  • At the bottom, click “Save”. At this point, the key will be available. Document this in a safe password repository and in the ~/.azure/credentials file. Once you leave the page, it will no longer be available.

tenant ID

OK, this is goofy and it’s not obvious to get. After you have created your application, you should see in the address bar, a unique ID, something like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. That is the tenant ID. copy it from the address bar.

configure Azure Resource Manager rights

Now that the Azure application has been configured, it needs privileges in Azure Resource Manager.

verify and Terraform smoke test

With the exploration and configuration of Azure now complete, time for the smoke test. This test will create a very simple Azure resource group

  • Clone the repository:
git clone git@github.com:bonovoxly/terraforms.git
  • Step into the ./terraforms/ARM/smoketest directory:
cd terraforms/ARM/smoketest
  • Source the azure_credentials.sh file (loads Azure variables as environment variables from ~/.azure/credentials).
source ./azure_credentials.sh
  • Run Terraform plan:
% terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.


The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

+ azurerm_resource_group.resource_group
   location:       "eastus"
   name:           "arm_smoketest"
   tags.%:         "1"
   tags.terraform: "yes"


Plan: 1 to add, 0 to change, 0 to destroy.
  • Apply the plan:
% terraform apply
azurerm_resource_group.resource_group: Creating...
 location:       "" => "eastus"
 name:           "" => "arm_smoketest"
 tags.%:         "" => "1"
 tags.terraform: "" => "yes"
azurerm_resource_group.resource_group: Creation complete

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the complete state
use the `terraform show` command.

State path: terraform.tfstate
  • Go to https://portal.azure.com and verfiy the Resource Group has been created. If necessary delete the group using terraform destroy.

That’s it. Azure ready to be used with Terraform.

links