Skip to content

Instantly share code, notes, and snippets.

@JustinGrote
Last active April 15, 2021 11:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save JustinGrote/832cc64cb22f062f4ee2663bd7427515 to your computer and use it in GitHub Desktop.
Save JustinGrote/832cc64cb22f062f4ee2663bd7427515 to your computer and use it in GitHub Desktop.
App-Only Authentication with Exchange in Azure Automation

App-Only Exchange Online Authentication with Azure Automation

Introduction

Basic Authentication is deprecated and will not be available to new tenants starting October 2020 and will be removed from existing tenants in 2H 2021.

What does this mean for your Azure Automation Scripts that connect to Exchange Online? It means they'll stop working! How about you get on the ball now and get it working.

Did you know the Azure Automation RunAs account is a service principal? This means that it can do everything a service principal can do, including authentiate to Exchange Online using the certificate it autogenerates.

Notice: This article is intended for legacy scripts that must run on Azure Automation. You really should consider moving to Azure Functions Powershell if you are doing things net-new, and yes, you can call Powershell 5.1 from the Powershell 7 runtime in Azure Functions so there's no reason you should need to stick with Azure Automation for compatibility.

If you want to set up something similar for applications other than Azure AD, check out the PSServicePrincipal module and its README

Exchange Online Management 2.0.3-Preview

You will need the ExchangeOnlineManagement 2.0.3 or greater imported into your Azure Automation environment. As of this writing it was still a prerelease. This command will install the module directly from the Powershell Gallery to your Azure Automation Account

#Requires -Module Az.Automation
New-AzAutomationModule -ResourceGroupName 'MyAAResourceGroupName'  -AutomationAccountName 'MyAutomationAccountName' -Name 'ExchangeOnlineManagement' -ContentLinkUri 'https://www.powershellgallery.com/api/v2/package/ExchangeOnlineManagement/2.0.3-Preview'

image

Configure Azure Automation RunAs Account for Exchange Access

The Azure Automation RunAs account (aka an Azure AD Service Principal) can behave the same as any user in Azure AD, including managing Exchange, Sharepoint, etc. as long as permissions are assigned. For the scope of this article we will grant the Exchange Administrator role to the runas account. In a real production environment, you should instead use role assignment policies to limit the scope of your runas account to only what it needs to do.

Run this command from a system with AzureAD, Az.Account, and Az.Automation Modules installed

**NOTE: Due to an api limitation this script assumes you are using the default RunAs Account. **

#requires -module AzureAD,Az.Automation,Az.Resources
$aaInfo = @{
    ResourceGroup = 'MyAAResourceGroup'
    AutomationAccountName = 'MyAutomationAccountName'
}

$aaConnection = Get-AzAutomationConnection @aaInfo -Name 'AzureRunAsConnection'
$aaRunAsServicePrincipal = Get-AzAdServicePrincipal -DisplayNameBeginsWith $aaConnection.AutomationAccountName
$ESARole = Get-AzureADDirectoryRole | where displayname -eq 'Exchange Service Administrator'
Add-AzureAdDirectoryRoleMember -ObjectId $ESARole.objectid -RefObjectId $aaRunAsServicePrincipal.Id

You can also do this via the Azure Portal:

image

Connect to Exchange in Runbook

Add this to your runbook. The automation account automatically puts the runas certificate in the CurrentUser certificatestore, so no need to do any fancy retrieval via Get-AutomationCertificate. Once connected you can run exchange commands and the new "EXO" commands as normal

#requires -module ExchangeOnlineManagement
$runAsConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
$ConnectParams = @{
    #We don't have an easy way to retrieve this, and it doesn't take the tenant ID. You have to manually specify it for now
    Organization = 'myorganization.com'
    AppId = $runAsConnection.ApplicationId
    CertificateThumbprint = $runAsConnection.CertificateThumbprint
    ShowBanner = $false
}
Connect-ExchangeOnline @ConnectParams

SET A REMINDER TO RENEW YOUR CERT

The automation runas account certificate expires by default in a year. The good news is that it automatically syncs it with the service account, so you just need to click the renew certificate button and everything else will be taken care of.

image

@JBines
Copy link

JBines commented Aug 13, 2020

Thanks for the info! Wondering if you have done any testing around using the cred manager in azure automation?

https://docs.microsoft.com/en-us/azure/automation/shared-resources/certificates

@JustinGrote
Copy link
Author

@JBines If you mean windows credential manager, it's not a good choice because the instances are ephemeral. You can keep certificates in either the Azure Automation secrets, or keep them in Azure Key Vault and use the automation key vault integration.

@JBines
Copy link

JBines commented Aug 13, 2020

Yep that's what I was thinking to store it as a secure asset in azure automation but I was hoping I could call the cert by using the Get-AzAutomationCertificate instead but I'm guessing that's not going to make it to the certificatestore. It would be nice to have a longer life cert or maybe we can just automate the cert update on the app.

@JustinGrote
Copy link
Author

If you're referring to the RunAs cert, Azure Automation handles all of the renewal by just clicking the renew cert button, you don't have to do all of this setup again.

@AndersRask
Copy link

@JustinGrote thanx for the write up.
Did you miss a step though? For my test setup, it worked only if I granted Exchange.ManageAsApp API permissions to the App Registration for the Enterprise Application.
I added this to the manifest and then granted permission:

"requiredResourceAccess": [
		{
			"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
			"resourceAccess": [
				{
					"id": "dc50a0fb-09a3-484d-be87-e023b12c6440",
					"type": "Role"
				}
			]
		}
	]

@JBines
Copy link

JBines commented Apr 12, 2021

I wouldn't do it this way as you need to renew the cert every year. Instead use a self signed cert for 50 years and then you can set and forget.

Br.
J

@AndersRask
Copy link

I wouldn't do it this way as you need to renew the cert every year. Instead use a self signed cert for 50 years and then you can set and forget.

Br.
J

You could just renew the certificate for the Run As account using PowerShell. A RunAs account is an Enterprise Application and the certificate is available on the App Registration instance just like any other.
You just create a self signed x509 and upload it replacing existing

regards
Anders

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment