Quick Start

Prepare the required environment variables environment variables for the Terraform Providers. Also, fill in the default values for the Terraform variables in the the variables.tf file, or declare Terraform variables. Here are examples of the values expressed on a Bash shell:

Environment Variables

# Environment variables required for the Terraform provider for 
# Azure Resource Manager requirements. These reflect the credentials
# for an account principal, not your own Azure AD credentials.
# 
export ARM_CLIENT_ID="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_CLIENT_SECRET="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_SUBSCRIPTION_ID="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_TENANT_ID="1234abcd-56ef-12ab-34cd-567890efabcd"

# Environment variables required for the Terraform provider for Azure 
# DevOps, and the Terraform provider for Terraform Cloud or Enteprise.
# Note that the values are exclusive to your Azure DevOps organization
# and your Terraform Cloud organization.
#
export AZDO_ORG_SERVICE_URL=https://dev.azure.com/hashicat-azdo
export AZDO_PERSONAL_ACCESS_TOKEN="REPLACE-ME-WITH-YOUR-AZDO-PAT"
export TFE_TOKEN="REPLACE-ME-WITH-YOUR-TFE-TOKEN"

Terraform Variables

# Terraform variables required to bootstrap the demo.
# Please note that that the AZDO project name and the
# AZDO repo name are arbitrary and must not already exist
# in Azure DevOps. If either exist, the deployment fails.
#
# Also, the values TFC org name and TFC token are exclusive
# to your Terraform Cloud organization.
#
export TF_VAR_azure_devops_project_name="azdo-primer-101"
export TF_VAR_azure_devops_repo_name="pipeline-starter"
export TF_VAR_azure_devops_org_name="hashicat-azdo"
export TF_VAR_arm_client_secret=$ARM_CLIENT_SECRET
export TF_VAR_tfc_org_name="interrupt-software"
export TF_VAR_tfc_token=$TFE_TOKEN

Deployment

Use the following to stage the working environment.

terraform init

Use terraform apply to build the entire environment. This will deploy all resources included in the source repositories.

terraform apply -auto-approve

With a successful run, you should be be able to navigate to the your Azure DevOps organization and see the project instantiated. It should look somewhat like this:


Alternatively, you have the option to walk through each module to create an additive rhythm to the demonstration of these assets. With this approach, create the Azure DevOps Project first.

terraform apply -target module.project

Once you are familiar with the pipelines, you can decide which example to run. For instance, if you are comfortable with the "Hello World, Let's Terraform" example, you can pick that directly as follows:

terraform apply -target module.pipeline1

The code in pipeline1/main.tf creates an Azure DevOps Pipeline that references the pipelines1/azdo-pipeline-01.yml resouce in this repo.

Potential errors

There is a potential error during the creation of the pipelines that may occur sporadically. AzureDevOps Guide writes that the error TF400898: An Internal Error Occurred mostly occurs when you are trying to access information from Azure DevOps via some REST API calls. According to Microsoft this is mostly a timeout issue from Azure DevOps. If you try it again after sometime this error seems to goes away.

Error: error creating resource Build Definition: TF400898: An Internal Error Occurred.
Activity Id: 51d6419d-e7be-41a4-be56-1ba41886d8d5.

  on pipeline3/main.tf line 24, in resource "azuredevops_build_definition" "build3":
  24: resource "azuredevops_build_definition" "build3" {

The solution is to issue another terraform apply command.


From Pipeline #4 and above, we assigning Collaborator priviliges to the default service account in the pipeline. The privilege allows the pipeline service account to automatically commit changes to the repository's master branch. To look up the principal name for that account and apply the permissions, we use a complicated sammich with hard-coded values. When we modify the Azure DevOps organization, you may find an error:

Error: Error in function call

  on pipeline4/main.tf line 107, in data "azuredevops_users" "user":
 107:   principal_name = element(data.azuredevops_users.all_users.users[*], 
        index(data.azuredevops_users.all_users.users[*].display_name, 
        "azdo-starter-99 Build Service (hashicat-ado)")).principal_name
    |----------------
    | data.azuredevops_users.all_users.users is set of object with 3 elements

Call to function "index" failed: item not found.

The reason for that error is that the call is unable to find the appropriate organization. From the environment variable $AZDO_ORG_SERVICE_URL above, note that the organization was exposed as hashicat-azdo and the code references hashicat-ado.

🗹 TO-DO: Code more better.

Update (09/08/21) - This is fixed. We added variables to handle the dependency.

data "azuredevops_users" "user" {
  principal_name = element(data.azuredevops_users.all_users.users[*], 
      index(data.azuredevops_users.all_users.users[*].display_name, 
      "${var.project_name} Build Service (${var.org_name})")).principal_name
}

We're leaving this here in case we run into similar issues. If so, please report them.

About the Providers

Each provider has various prerequesite data points that need to be expressed as enviroment variables as part of the initial deployment.

Provider Description Environment variables
Azure Resource Manager Provisions Azure Cloud resources through build pipelines. Also provides authentication for Azure subscription services for Azure DevOps tasks. ARM_CLIENT_ID
ARM_CLIENT_SECRET
ARM_SUBSCRIPTION_ID
ARM_TENANT_ID
Azure DevOps Create master project, respostories and build pipelines. We also use it update account permissions for pipeline users AZDO_ORG_SERVICE_URL
AZDO_PERSONAL_ACCESS_TOKEN
Terraform Sets up and configures Terraform Cloud workspaces, and links pipeline deployments to the appropriate workspaces. TFE_TOKEN
Random Creates random pet names. none

In addition, the IaC deployments require the pass-thru of two specific variables that support the pipeline tasks. These are required by the work carried during the execution of terraform plan and terraform apply steps but are not strictly required to build the demo environment.

  • TF_VAR_arm_client_secret is used during the terraform plan and terraform apply steps within a pipeline. While the credentials can be inhereted from the triggering account (human/you) with az login, the instrospection of data source data azurerm_client_config current {} does not expose the client secret.

Azure Resource Manager

It is true that we can avoid exposing these variables with az login to authenticate with your Azure Active Directory account instead of an Account Principal. Please note, however, that we are not using these credentials for this demo environment at all. Instead, we are publishing these to the pipelines as local secrets. The pipelines use these credentials to procure Azure services. We want the flexibility to depecreate these credentials once the demonstration exercise is completed.

In addition, we also plant the credentials in Terraform Cloud workspaces as environment secrets. The Azure authentication process from a Terraform Cloud workspace requires account principal credentials. Please note the the requirement for TF_VAR_arm_client_secret below.

export ARM_CLIENT_ID="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_CLIENT_SECRET="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_SUBSCRIPTION_ID="1234abcd-56ef-12ab-34cd-567890efabcd"
export ARM_TENANT_ID="1234abcd-56ef-12ab-34cd-567890efabcd"

Azure DevOps

Create an Azure DevOps personal access token (PAT) to support remote operations with the Terraform Azure DevOps provider. There is a handy guide on how to create personal access tokens in the Azure DevOps Documentation.

Expose your Azure DevOps PAT and organization URL as follows:

export AZDO_PERSONAL_ACCESS_TOKEN="##########"
export AZDO_ORG_SERVICE_URL=https://dev.azure.com/hashicat-azdo

Terraform Cloud

This is not strictly required to build the demo environment. We are using it in this manner to maintain the recommended convention for exposure. Some people like little tomatoes and some tomatillos.

export TFE_TOKEN="##########"

The following variables are required for the Terraform and environment that run in various Azure DevOps pipeline tasks. Please note that TF_VAR_azure_devops_org_name is here to solve the dependency names on the pipeline service account.

Pipeline inheritance

export TF_VAR_arm_client_secret=$ARM_CLIENT_SECRET
export TF_VAR_tfc_token=$TFE_TOKEN
export TF_VAR_azure_devops_org_name="hashicat-azdo"