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
# ^^^ 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
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
# 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"
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
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.
1 comment:
Thanks for your interesting article.
I had to use "Cloud Application Administrator" instead of "Application Administrator".
Post a Comment