Previously we detailed the process of creating our service principal and using that to deliver an azure subscription - so here we will map the process from az cli to terraform

  • map all of the required variables into one variables.tf
  • create the data lookups and service principal resource
  • assign roles and permissions to the SP
  • create an Azure Subscription using defined parameters
  • bundle the process steps into a terraform module
Unable to render {children}. Page not found: Azure Automation: automation by first principles.

Here we will identify all the inputs and requirements for each stage of facilitating and creating a subscription via cli - this will remind us of the stages and steps needed for full automation

Azure Subscriptions

  • Service Principal
    • Name
    • Billing Account
    • Enrollment Account
  • Role Assignment
    • Service Principal assignment to enrollment account

  • Azure Subscription
    • Name
    • User
    • Offer

:sp: :terraform:

  • Insert the required terraform azurerm features block
Provider "azurerm" {
  features {} 
}
  • Set variables for the Service Principal name so that we can re-use the code
variable "application_name" {}
variable "management_group" {}
  • lookup the root management group so that we can assign scope
data "azurerm_management_group" "primary" {
  name = var.management_group
}
  • Create the App Registration or Service Principal
resource "azuread_application" "auth" {
 display_name = "${var.application_name}"
 }
  • Obtain the AppId so we can assign a role to the SP
resource "azuread_service_principal" "auth" {
 application_id = "${azuread_application.auth.application_id}"
}
  • Assign a role definition and scope to the Service Principal
resource "azurerm_role_assignment" "auth" {
 scope                = "${data.azurerm_management_group.primary.id}"
 role_definition_name = "Owner"
 principal_id         = "${azuread_service_principal.auth.id}"
}

so now - with some basic inputs for app name and management group we should be anle to validate the process with terraform plan

terraform init
terraform plan
Terraform init && terraform plan
Plan
  # azuread_application.auth will be created
  + resource "azuread_application" "auth" {
      + app_role_ids                = (known after apply)
      + application_id              = (known after apply)
      + disabled_by_microsoft       = (known after apply)
      + display_name                = "testapp"
      + id                          = (known after apply)
      + logo_url                    = (known after apply)
      + oauth2_permission_scope_ids = (known after apply)
      + object_id                   = (known after apply)
      + prevent_duplicate_names     = false
      + publisher_domain            = (known after apply)
      + sign_in_audience            = "AzureADMyOrg"
      + tags                        = (known after apply)
      + template_id                 = (known after apply)

      + feature_tags {
          + custom_single_sign_on = (known after apply)
          + enterprise            = (known after apply)
          + gallery               = (known after apply)
          + hide                  = (known after apply)
        }
    }

  # azuread_service_principal.auth will be created
  + resource "azuread_service_principal" "auth" {
      + account_enabled             = true
      + app_role_ids                = (known after apply)
      + app_roles                   = (known after apply)
      + application_id              = (known after apply)
      + application_tenant_id       = (known after apply)
      + display_name                = (known after apply)
      + homepage_url                = (known after apply)
      + id                          = (known after apply)
      + logout_url                  = (known after apply)
      + oauth2_permission_scope_ids = (known after apply)
      + oauth2_permission_scopes    = (known after apply)
      + object_id                   = (known after apply)
      + redirect_uris               = (known after apply)
      + saml_metadata_url           = (known after apply)
      + service_principal_names     = (known after apply)
      + sign_in_audience            = (known after apply)
      + tags                        = (known after apply)
      + type                        = (known after apply)

      + feature_tags {
          + custom_single_sign_on = (known after apply)
          + enterprise            = (known after apply)
          + gallery               = (known after apply)
          + hide                  = (known after apply)
        }

      + features {
          + custom_single_sign_on_app = (known after apply)
          + enterprise_application    = (known after apply)
          + gallery_application       = (known after apply)
          + visible_to_users          = (known after apply)
        }
    }

  # azurerm_role_assignment.auth will be created
  + resource "azurerm_role_assignment" "auth" {
      + id                               = (known after apply)
      + name                             = (known after apply)
      + principal_id                     = (known after apply)
      + principal_type                   = (known after apply)
      + role_definition_id               = (known after apply)
      + role_definition_name             = "Owner"
      + scope                            = "/providers/Microsoft.Management/managementGroups/UK"
      + skip_service_principal_aad_check = (known after apply)
    }

Plan: 3 to add, 0 to change, 0 to destroy.


(blue star) Checkpoint

To recap what we have - and where we are in the process of Automating Azure Subscriptions we have

  • Created a Service Principal
  • Assigned Permissions or Enrolment Account to allow subscription creation
  • Have accessed the Service Principal credentials we will need when automating
  • logged into az cli with our Service Principal
  • created a new subscription using the az cli command

(blue star) Checkpoint

(blue star) Checkpoint

:subscription: :terraform:

  • set variables for the subscription name and the billing details we discovered previously
variable "subscription_display_name" { default = "test"}
variable "billing_account_name" { default = "187561154"}    
variable "enrollment_account_name" { default = "311200"}                           
  • lookup the scope associated with our billing details - so we can assign the subscription there
data "azurerm_billing_enrollment_account_scope" "current" {
  billing_account_name    = var.billing_account_name
  enrollment_account_name = var.enrollment_account_name
  }            
  • create the subscription resource under the billing id
resource "azurerm_subscription" "create" {
  subscription_name = var.subscription_display_name
  billing_scope_id  =  data.azurerm_billing_enrollment_account_scope.current.id
}                           

if we add this as a new set of terraform files, we can use the SP details crested earlier to run the deployment

terraform init
terraform plan

terraform init && terraform plan
terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_subscription.create will be created
  + resource "azurerm_subscription" "create" {
      + alias             = (known after apply)
      + billing_scope_id  = "/providers/Microsoft.Billing/billingAccounts/187561154/enrollmentAccounts/311200"
      + id                = (known after apply)
      + subscription_id   = (known after apply)
      + subscription_name = "test"
      + tenant_id         = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

We now have 2 sets of terraform code

  1. code to create and assign the SP that we would expect to only run when setting up the instance

  2. code to use the SP details and create a subscription under the assigned billing account

Next we’ll take the process and variables we discovered here and mimic the steps in terraform… first locally and then in a GitHub Workflow

Next we’ll take the process and variables we discovered here and mimic the steps in terraform… first locally and then in a GitHub Workflow