8 Steps for Using Azure AD Service Principal Certificate Authentication with Azure Automation PowerShell Workflow Runbooks

Lately, I’ve been working with several customers that are getting started with Azure Automation runbooks to help operationalize their Microsoft Azure subscriptions. As part of this process, runbooks need to securely authenticate to Azure with a minimum of administration overhead.  Typically, the authentication solution lands on using certificates to authenticate an Azure AD Service Principal that has been granted the relevant role-based access control permissions to manage the Azure subscription.

image

There’s lots of great technical articles that provide details on different pieces of this process, but we had a difficult time finding a good end-to-end tutorial that steps through the entire process.  In this article, I’m documenting the steps we used to configure certificate-based authentication with Azure AD service principals from within Azure Automation PowerShell Workflow runbooks.

Note: Azure Automation supports three different types of runbooks: Graphical Runbooks, PowerShell Workflow Runbooks and PowerShell Script Runbooks.  You can find more details on each type of runbook here. In our case, we chose to use PowerShell Workflow Runbooks, because of the native advantages around parallel processing and checkpoints. If you chose to leverage a different runbook type for your automation work, the runbook starter example in this article will need to be adjusted to accommodate the type of runbook you’ve selected.

We’ll be completing the following 8 steps as an end-to-end process for configuring certificate-based authentication for Azure AD service principals from within Azure Automation PowerShell Workflow runbooks:

  1. Create certificate for Azure AD Service Principal
  2. Export certificate to PFX file
  3. Create Key Credential Object
  4. Create Azure AD Service Principal
  5. Assign Role-Based Access Control (RBAC) permissions to Azure AD Service Principal
  6. Test authenticating as Azure AD Service Principal
  7. Define Azure Automation Assets
  8. Build a sample Azure Automation PowerShell Workflow Runbook

Before getting started …

Before getting started with this article, be sure that:

  • You’re running Windows 8 or later (I’m running on Windows 10) for your administration PC
  • You’ve downloaded and installed the latest Azure PowerShell modules (I’m currently using Azure PowerShell v1.2.2).

I’ve also included a sample of the code snippets from the article below in my GitHiub repo here.

Tip: To get started, launch Windows PowerShell ISE using the “Run as Administrator” option. If you don’t use this option to launch an Administrator: Windows PowerShell ISE session, you won’t be able to save your certificate to the LocalMachine certificate store in Step 1 below.

Step 1: Create certificate for Azure AD Service Principal

Before setting up an Azure AD Service Principal, we’ll first need to create a certificate.  In this walk-through, we’ll create a self-signed certificate.

# Define certificate start and end dates

$currentDate =
Get-Date

$endDate =
$currentDate.AddYears(1)

$notAfter =
$endDate.AddYears(1)

# Generate new self-signed certificate from "Run as Administrator" PowerShell session

$certName =
Read-Host `
-Prompt "Enter FQDN Subject Name for certificate"

$certStore =
"Cert:\LocalMachine\My"

$certThumbprint =
(New-SelfSignedCertificate `
-DnsName "$certName" `
-CertStoreLocation $CertStore `
-KeyExportPolicy Exportable `
-Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
-NotAfter $notAfter).Thumbprint

Step 2: Export Certificate to PFX file

# Export password-protected pfx file

$pfxPassword =
Read-Host `
-Prompt "Enter password to protect exported certificate:" `
-AsSecureString

$pfxFilepath =
Read-Host `
-Prompt "Enter full path to export certificate (ex C:\folder\filename.pfx)"

Export-PfxCertificate `
-Cert "$($certStore)\$($certThumbprint)" `
-FilePath $pfxFilepath `
-Password $pfxPassword

Step 3: Create Key Credential Object

Next, we’ll create a Key Credential object that will be referenced later in this article when assigning the certificate to the Azure AD Application used for our Service Principal.

# Create Key Credential Object

$cert =
New-Object `
-TypeName System.Security.Cryptography.X509Certificates.X509Certificate `
-ArgumentList @($pfxFilepath, $pfxPassword)

$keyValue =
[System.Convert]::ToBase64String($cert.GetRawCertData())

$keyId =
[guid]::NewGuid()

Import-Module `
-Name AzureRM.Resources

$keyCredential =
New-Object `
-TypeName Microsoft.Azure.Commands.Resources.Models.ActiveDirectory.PSADKeyCredential

# Define properties of Key Credential object

$keyCredential.StartDate = $currentDate

$keyCredential.EndDate = $endDate

$keyCredential.KeyId = $keyId

$keyCredential.Type = "AsymmetricX509Cert"

$keyCredential.Usage = "Verify"

$keyCredential.Value = $keyValue

Step 4: Create Azure AD Service Principal

# Define Azure AD Application Properties

$adAppName =
Read-Host `
-Prompt "Enter unique Azure AD App name"

$adAppHomePage =
Read-Host `
-Prompt "Enter unique Azure AD App Homepage URI"

$adAppIdentifierUri =
Read-Host `
-Prompt "Enter unique Azure AD App Identifier URI"

# Login to Azure Account

Login-AzureRmAccount

# Create new Azure AD Application

$adApp =
New-AzureRmADApplication `
-DisplayName $adAppName `
-HomePage $adAppHomePage `
-IdentifierUris $adAppIdentifierUri `
-KeyCredentials $keyCredential

Write-Output "New Azure AD App Id: $($adApp.ApplicationId)"

# Create Azure AD Service Principal

New-AzureRmADServicePrincipal `
-ApplicationId $adApp.ApplicationId

Step 5: Assign Role-Based Access Control (RBAC) Permissions to the Service Principal

Now that our new service principal is created, we’ll need to assign it the necessary permissions to perform the automation tasks that our runbooks will be executing.  We can assign these permissions via Azure Role-Based Access Control. In this example, we’ll grant full Owner permissions for our entire Azure subscription to the Service Principal, but in other scenarios you can limit these permissions to just the access needed for particular Resource Groups or Resource Types that runbooks will be automating activities against.

# Select Azure subscription

$subscriptionId =
(Get-AzureRmSubscription |
Out-GridView `
-Title "Select an Azure Subscription ..." `
-PassThru).SubscriptionId

Select-AzureRmSubscription `
-SubscriptionId $subscriptionId

# Assign Owner permissions to the Service Principal for the selected subscription

New-AzureRmRoleAssignment `
-RoleDefinitionName Owner `
-ServicePrincipalName $adApp.ApplicationId

Step 6: Test authenticating as Service Principal

Before continuing further, it’s a good idea to test that you’re able to successfully authenticate using the new service principal.  If you’re unable to successfully authenticate, go back to Step 1 and confirm each of the previous steps again.

# Set Azure AD Tenant ID

$tenantId =
(Get-AzureRmContext).Tenant.TenantId

# Test authenticating as Service Principal to Azure

Login-AzureRmAccount `
-ServicePrincipal `
-TenantId $tenantId `
-ApplicationId $adApp.ApplicationId `
-CertificateThumbprint $certThumbprint

Step 7: Define Azure Automation Assets

After we begin using Azure Automation, we’ll likely have several runbooks for automating different activities. To be able to easily reuse the necessary information for authenticating to our Azure subscription from within each runbook, we’ll define a set of centralized Azure Automation Assets to store this information.

# Select existing Azure Automation account

$automationAccount =
Get-AzureRmAutomationAccount |
Out-GridView `
-Title "Select an existing Azure Automation account ..." `
-PassThru

# Create Azure Automation Asset for Azure AD App ID

New-AzureRmAutomationVariable `
-Name "AutomationAppId" `
-Value $adApp.ApplicationId `
-AutomationAccountName $automationAccount.AutomationAccountName `
-ResourceGroupName $automationAccount.ResourceGroupName `
-Encrypted:$false

# Create Azure Automation Asset for Azure AD Tenant ID

New-AzureRmAutomationVariable `
-Name "AutomationTenantId" `
-Value $tenantId `
-AutomationAccountName $automationAccount.AutomationAccountName `
-ResourceGroupName $automationAccount.ResourceGroupName `
-Encrypted:$false

# Create Azure Automation Asset for Certificate

New-AzureRmAutomationCertificate `
-Name "AutomationCertificate" `
-Path $pfxFilepath `
-Password $pfxPassword `
-AutomationAccountName $automationAccount.AutomationAccountName `
-ResourceGroupName $automationAccount.ResourceGroupName

# Create Azure Automation Asset for Azure Subscription ID

New-AzureRmAutomationVariable `
-Name "AutomationSubscriptionId" `
-Value $subscriptionId `
-AutomationAccountName $automationAccount.AutomationAccountName `
-ResourceGroupName $automationAccount.ResourceGroupName `
-Encrypted:$false

Step 8: Build Sample Azure Automation PowerShell Workflow Runbook

We’re ready to build our first PowerShell Workflow runbook to test the process of authenticating to our Azure subscription. Follow these steps to create your runbook, and then include the sample code I’ve provided below at the top of the PowerShell Workflow defined in your new runbook.

# Get Azure Automation Assets

$adAppId = Get-AutomationVariable -Name "AutomationAppId"

Write-Output "Azure AD Application Id: $($adAppId)"

$tenantId = Get-AutomationVariable -Name "AutomationTenantId"

Write-Output "Azure AD Tenant Id: $($tenantId)"

$subscriptionId = Get-AutomationVariable -Name AutomationSubscriptionId"

Write-Output "Azure Subscription Id: $($subscriptionId)"

$cert = Get-AutomationCertificate -Name "AutomationCertificate"

$certThumbprint = ($cert.Thumbprint).ToString()

Write-Output "Service Principal Certificate Thumbprint: $($certThumbprint)"

# Install Service Principal Certificate

Write-Output "Install Service Principal certificate..."

if ((Test-Path "Cert:\CurrentUser\My\$($certThumbprint)") -eq $false) {

    InlineScript {

        $certStore = new-object System.Security.Cryptography.X509Certificates.X509Store("My", "CurrentUser")

        $certStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)

        $certStore.Add($Using:cert)

        $certStore.Close()

    }

}

# Login to Azure

Write-Output "Login to Azure as Service Principal..."

Login-AzureRmAccount -ServicePrincipal -TenantId $tenantId -ApplicationId $adAppId -CertificateThumbprint $certThumbprint

# Select Azure Subscription

Write-Output "Select Azure subscription..."

Select-AzureRmSubscription -SubscriptionId $subscriptionId -TenantId $tenantId

# Insert your PowerShell Workflow code below this line for the automation activities you wish to perform

You’re now prepared to build Azure Automation PowerShell Workflow runbooks to automate and operationalize your cloud workloads!

Tip: For great examples of Azure Automation Runbooks that you can import at the end of your sample Runbook above, be sure to check out the Azure Automation Runbook Gallery.