Did you ever wanted to automate everything in Azure? Using Azure Automation or using Remote PowerShell – pretty much anything automated in Azure, you should NOT be using a stock standard user account. Why? Because you can have all sorts of problems, for instance the password can expire and then it breaks everything and everything stops working. It’s a bit like on-prem days where you would use specific service accounts, each service account setup for a specific purpose, much easier to manage and it’s best practice.
In Azure it’s no difference, you use a service principal and grant this service principal access to where ever in Azure with contributor or owner privileges.
The below script (run as admin) walks you through setting up an AAD application, creating the service principal, creating a self signed certificate then uploading the certificate to Azure.
There’s a section further below in the script to create all the Azure automation variables and sets up the certificate so you can use the Service Principal with Azure Automation. Remember, you need the certificate installed on the machine in which you want to connect automatically to Azure with using certificate based authentication.
Then further below is an example Azure Automation block of code clearly labled “Azure Automation PowerShell Workflow Runbook example” which you add to your own Azure Automation account as a starting point.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Written with Azure PowerShell module v6.1.0 available from https://github.com/Azure/azure-powershell/releases/tag/v6.1.0-May2018 | |
# Recently tested fully with a later version of the Azure PowerShell module – Install-Module AzureRM -RequiredVersion 6.1.0 | |
###################### | |
############## Step 0: Change Variables, and logon | |
###################### | |
# Define Azure Automation Assets | |
$AutomationAppIDName = 'AutomationAppId' # Feel free to change to suit you | |
$AutomationTenantIDName = 'AutomationTenantId' # Feel free to change to suit you | |
$AutomationCertificateName = 'AutomationCertificate' # Feel free to change to suit you | |
$AutomationSubscriptionIDName = 'AutomationSubscriptionId' # Feel free to change to suit you | |
# Login to Azure manually | |
Login–AzureRmAccount | |
### Choose Subscription | |
$subscription = Get-AzureRmSubscription | Out-GridView –Title "Select the Azure subscription that you want to use …" –PassThru | |
Select-AzureRmSubscription –SubscriptionId $subscription.id | |
###################### | |
############## Step 1: Create certificate for Azure AD Service Principal | |
###################### | |
# 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 = "$($env:TEMP)\$(Get-Date –Format yyyyMMdd)pfxfile.json" | |
Export-PfxCertificate –Cert "$($certStore)\$($certThumbprint)" –FilePath $pfxFilepath –Password $pfxPassword | |
###################### | |
############## Step 3: Create Key Credential Object | |
###################### | |
# 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() | |
Get-Module AzureRM.Resources | |
Import-Module –Name AzureRM.Resources | |
# $keyCredential = New-Object -TypeName Microsoft.Azure.Commands.Resources.Models.ActiveDirectory.PSADKeyCredential | |
$keyCredential = New-Object –TypeName Microsoft.Azure.Graph.RBAC.Version1_6.ActiveDirectory.PSADKeyCredential | |
<# | |
If you get an error: | |
New-Object : Cannot find type [Microsoft.Azure.Commands.Resources.Models.ActiveDirectory.PSADKeyCredential]: verify that the assembly containing this type is loaded. | |
Install this module version v4.2.1 specifically, run this: – Install-Module AzureRM -RequiredVersion 4.2.1 | |
#> | |
# Define properties of Key Credential object | |
$keyCredential.StartDate = $currentDate | |
$keyCredential.EndDate = $endDate | |
$keyCredential.KeyId = $keyId | |
$keyCredential.CertValue = $keyValue | |
#$keyCredential | fl * | |
###################### | |
############## 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" # Any URL, http://microsoft.com if you like :) | |
$adAppIdentifierUri = Read-Host –Prompt "Enter unique Azure AD App Identifier URI" # Can be the same as the first URI | |
# Remove Azure AD Application | |
#Remove-AzureRmADApplication -DisplayName $adAppName -Force | |
# 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 | |
###################### | |
# Sleep and wait for the new service principal to propergate through AAD | |
Start-Sleep –Seconds 30 | |
# Assign Owner permissions to the Service Principal for the selected subscription | |
New-AzureRmRoleAssignment –RoleDefinitionName Owner –ServicePrincipalName $adApp.ApplicationId.Guid | |
###################### | |
############## Step 6: Test authenticating as Service Principal | |
###################### | |
# Set Azure AD Tenant ID | |
$tenantId = (Get-AzureRmContext).Tenant.Id | |
# Test authenticating as Service Principal to Azure | |
Login–AzureRmAccount –ServicePrincipal –TenantId $tenantId –ApplicationId $adApp.ApplicationId –CertificateThumbprint $certThumbprint | |
### Choose Subscription | |
$subscription = Get-AzureRmSubscription | Out-GridView –Title "Select the Azure subscription that you want to use …" –PassThru | |
Select-AzureRmSubscription –SubscriptionId $subscription.id | |
###################### | |
############## Step 7: Define Azure Automation Assets | |
###################### | |
# 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 $AutomationAppIDName –Value $adApp.ApplicationId –AutomationAccountName $automationAccount.AutomationAccountName ` | |
–ResourceGroupName $automationAccount.ResourceGroupName –Encrypted:$false | |
# Create Azure Automation Asset for Azure AD Tenant ID | |
New-AzureRmAutomationVariable –Name $AutomationTenantIDName –Value $tenantId –AutomationAccountName $automationAccount.AutomationAccountName ` | |
–ResourceGroupName $automationAccount.ResourceGroupName –Encrypted:$false | |
# Create Azure Automation Asset for Certificate | |
New-AzureRmAutomationCertificate –Name $AutomationCertificateName –Path $pfxFilepath –Password $pfxPassword ` | |
–AutomationAccountName $automationAccount.AutomationAccountName –ResourceGroupName $automationAccount.ResourceGroupName | |
# Create Azure Automation Asset for Azure Subscription ID | |
New-AzureRmAutomationVariable –Name $AutomationSubscriptionIDName –Value $subscription.Id –AutomationAccountName $automationAccount.AutomationAccountName ` | |
–ResourceGroupName $automationAccount.ResourceGroupName –Encrypted:$false | |
########################################################################################## | |
########################################################################################## | |
############## ###################### | |
############## Azure Automation PowerShell Workflow Runbook example ###################### | |
############## ###################### | |
########################################################################################## | |
########################################################################################## | |
workflow StartAzurePlaylistVMs | |
{ | |
# Get Azure Automation Assets | |
$adAppId = Get-AutomationVariable –Name 'AutomationAppId' | |
Write-Output "Azure AD Tenant 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 | |
$VMs = Get-AzureRmVM | where {$_.Name -match 'playlist'} | |
ForEach –Parallel ($VM in $VMs) | |
{ | |
Start-AzureRmVM –Name $VM.Name –ResourceGroupName $VM.ResourceGroupName | |
} | |
} |
Below is how you would logon to Azure using PowerShell and certificate based authentication – as long as you have the certificate installed locally on the machine in which you are connection from, so you can successfully find the correct thumbprint.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Log into Azure using certificate authentication | |
$AzureADAppID = '49fy7934-dc71-4bdd-8804-h9742fyh93y' | |
$certThumbprint = (Get-ChildItem Cert:\LocalMachine\My | where {$_.Subject -match 'PowerShell_SP'}).ThumbPrint | |
$TenantId = '3494h480-6a11-78k0-a439-49hh8f49d0' | |
Login–AzureRmAccount –ServicePrincipal –TenantId $tenantId –ApplicationId $AzureADAppId –CertificateThumbprint $certThumbprint | |
$Subscription = (Get-AzureRmSubscription | Out-GridView –Title "Choose a Source & Target Subscription …" –PassThru) | |
Select-AzureRmSubscription –SubscriptionId $Subscription.Id |
See my other post to see how to setup an AAD Service Principal using password authentication instead.