Pages

Tuesday, February 8, 2022

Creating a Service Principal to connect to Azure AD using a Certificate to authenticate

As a follow up to one of my previous posts:

PowerShell script to assign users in an on-premise AD group to an Azure Enterprise Application's Users and Groups
http://terenceluk.blogspot.com/2022/02/powershell-script-to-assign-users-in-on.html

A PowerShell script can be used to manually add user accounts to an Azure Enterprise Application’s User and Groups, and to take it one step further, it can be automated with Azure Automation Runbooks or Azure Functions. This post serves as a continuation of how to automate PowerShell scripts.

One of the first and most important task to do when automating a PowerShell script is to handle how authentication happens. Interactive logon with modern or legacy basic authentication is not and never really an option. The recommended method for scripts is to create a service principal and either use a secret (see my previous post: http://terenceluk.blogspot.com/2022/02/using-azure-service-principal-to.html or certificate (as shown in this post) to authenticate.

Microsoft has documentation (https://docs.microsoft.com/en-us/powershell/azure/active-directory/signing-in-service-principal?view=azureadps-2.0) for how to configure a Service Principal with a certificate to authenticate but I feel the process can be elaborated it a bit so below is a detailed walkthrough of what happens.

Before I begin, the PowerShell script can be found here at my Github repo: https://github.com/terenceluk/Azure/blob/main/PowerShell/ServicePrincipalCertificateAuthentication.ps1

Step #1 – Connect to Azure AD and define the variables:

Start by importing the AzureAD module and authenticating with your Global Admin account, then define the variables with values that we’ll be using later on to create the certificate.

# Import AzureAD module with -UseWindowsPowerShell switch for PowerShell 7

Import-Module AzureAD -UseWindowsPowerShell

# Login to Azure AD PowerShell With Admin Account

Connect-AzureAD

# Define variables that will be used to create the certificate and export it

$password = "YourPassword123$" # certificate password

$certDNSname = "EnterpriseApps.contoso.com" # the CN (common name) of the certificate

$certificateLifeInYears = 3

$certificateExportPath = "c:\temp\"

$certificateExportName = "enterpriseAppsCert.pfx"

$certificatePathandName = $certificateExportPath + $certificateExportName

$enterpriseAppName = "Enterprise-Apps-Permissions-PS" # This is the App Registration object that the Enterprise Application created from

Step #2 – Create a self-signed certificate on the local Windows desktop and export it to PFX with the private key

Create a self-signed certificate on the local Windows desktop these cmdlets are executed and then export it to the computer’s local C:\temp as a PFX:

# Create the self signed cert on the local Windows machine's Computer Store (Not User Store)

$currentDate = Get-Date

$notAfter = $currentDate.AddYears($certificateLifeInYears)

$thumb = (New-SelfSignedCertificate -CertStoreLocation cert:\localmachine\my -DnsName $certDNSname -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $notAfter).Thumbprint

### Certificate is now created in the computer's local store

image

# ^^^ Convert the password to a secure string and export the newly created certificate on the computer's Computer Store to a PFX file

$password = ConvertTo-SecureString -String $password -Force -AsPlainText

Export-PfxCertificate -cert "cert:\localmachine\my\$thumb" -FilePath $certificatePathandName -Password $password

### ^^^ Certificate now exported to the local computer

image

Step #3 – Create the App Registration and Enterprise Application (Service Principal) objects

Begin by creating the certificate as an object, create the App Registration, upload the certificate, create the service principal that is linked to the app registration:

# Create and load the certificate into variables

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate($certificatePathandName, $password)

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

# Create the Azure Active Directory Application (Azure Active Directory > App Registrations) and upload certificate during creation

$application = New-AzureADApplication -DisplayName $enterpriseAppName # include URL if there is one or omit it -IdentifierUris "https://TestApp"

New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier $enterpriseAppName -StartDate $currentDate -EndDate $notAfter -Type AsymmetricX509Cert -Usage Verify -Value $keyValue

### ^^^ App registrations should now show the newly created application with the certificate uploaded to "Certificates and secrets" so it would allow a client with the

### certificate and its private key to authenticate

image

# Create the Service Principal (Enterprise Application) and linked to the Application (App Registration)

$sp=New-AzureADServicePrincipal -AppId $application.AppId

### ^^^ Enterprise Applications should now show the newly created application with filter set to "All Applications"

image

Step #4 – Assign Roles to the Service Principal

The service principal will not have any permissions to the directory so grant the required permissions:

# Give the Service Principal Reader access to the current tenant (Use Get-AzureADDirectoryRole to list the roles - Azure Active Directory > Roles and Administration > Directory readers)

Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Directory Readers"}).Objectid -RefObjectId $sp.ObjectId

# Give the Service Principal Reader access to the current tenant (Use Get-AzureADDirectoryRole to list the roles - Azure Active Directory > Roles and Administration > Application administrator)

Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Application administrator"}).Objectid -RefObjectId $sp.ObjectId

### ^^^ The Enterprise App (Service Principal) should now be added to the "Application administrator" and "Directory Readers" roles

image

Step #5 – Test authentication with Service Principal

With the service principal configured, test logging in as it with the same computer that has the certificate used for authentication:

<#

We can now test authentication with the Service Principal and the certificate stored on the local computer we have just created

#>

# Get Tenant Detail

$tenant=Get-AzureADTenantDetail

# Now you can login to Azure PowerShell with your Service Principal and Certificate

Connect-AzureAD -TenantId $tenant.ObjectId -ApplicationId $sp.AppId -CertificateThumbprint $thumb

Please see my next post for how to create an Azure Function App where it will use this service principal authenticate and run a PowerShell script on a timer trigger.