So yes, It has been 2 years since I posted <sigh> You would think with Covid I would have been all over this, but well .. we all agree that time of our lives sucked and here we are.
As we have all had, I recently had the requirement to create a PowerShell Script that ran daily to do a task. Since we did not want to have to manually run this we needed a secure way to run this to pull information out of Azure for other tasks on prem. Now the worst way to do this is to put a username and password in the script for a user or service account that would login to Azure AD to complete the task. With the implementation of MFA this makes it a little more difficult but you could (wrongfully) bypass MFA for that account in the Conditional Access Policy to get the PowerShell ran. Now I will not now nor ever admit that this has been done in the past, but please consider a different way.
SPN or Service Principal Name / Azure Applications. We can create one of these and give it just the permissions needed to run the script tasks with its certificate or secret tied to a specific location.
Steps to Setup Azure Application
Let’s walk through the steps for Creating an Azure Application.
- Login to Azure Portal as Global Admin https://portal.azure.com
- Navigate to Azure Active Directory
- Select Enterprise Applications
- Select New Application
- Select Create your own application
- Enter a Name
- Select Register an application to integrate with Azure AD (app you’re developing)
- Leave the Supported account type as it which should default to Accounts in this organizational directory only (<TenantName> only – Single tenant)
- Select Register – This will create the App, and list it in Enterprise Apps. Continue to next steps
Secrets and Certificates – Access needs to be setup to allow this application to be signed in.
- From the Azure Active Directory Console Select App Registrations
- Select the App you created
- Select Add Certificate or Secret
- NOTE: In this example I will use Secret, which generates a secret to be used (like a password) Ideally Certificate is the better solution but this requires creating a certificate from the machine that the PowerShell will be ran from.
- Under Client Secrets, select + New Client Secret
- Enter Description
- Select Expires timeframe. 6 Months is default and recommended
- Select Add button
- Note the Value of the Secret just created. This is the value you will use for the Secret.
- No need to copy now as you can retrieve this at any time by going back to this app registration page
Grant Permissions that will be needed for the PowerShell Script – In my script we required just read access to some of the user permissions so we granted the follow as an example: Group.Read.All, GroupMember.Read.All, User.Read, User.Read.All. But assign the least privileged needed for your script.
- From the App Registrations Blade select your App
- Select API Permissions
- Select Add a Permission to add the designed permissions
- After adding Permissions you will also need to “Grant admin consent for <Tenant>” by selecting this option
Testing Access – For our script we are going to get user information, which is out of scope for this blog post, but here is the connection that will need to be made from the script to run those commandlets.
Pre-req:
- TENANT ID for the tenantID variable – This can be found from several places but in the GUI go to the Overview Page of Azure Active Directory
- The appID variable – This can be found from the App registration page for the app created above
- The appsecret variable (Client Secret) – This can also be found under the App Registration Page
As Noted below in the comments – Putting the Client Secret in the PowerShell Script itself is not secure, and you should follow the steps outlined to secure that in a text file on the computer you are running the script from. Again – This is not the most secure solution, using a certificate would be better, but this was done in our case for ease of use, as a starting point .. And well .. We didn’t have access to the server that was going to run the script yet so creating a certificate was not an option.
# Variables for Authentication of SPN
$appID ="<APPID>"
$tenantId = "<TENANTID>"
$appsecret = ConvertTo-SecureString "<CLIENT_SECRET>" -AsPlainText -Force # Remove from Script after running below to Secure Secret
$AzureADCred = New-Object System.Management.Automation.PSCredential($appID, $appsecret)
##################################################################################
# If we want to do this securly, Must setup password.txt on the computer that this will run from
# $appsecret = | ConvertFrom-SecureString | set-content "C:\Passwords\password.txt"
# $EncryptedSecret = Get-Content "C:\Passwords\password.txt" | ConvertTo-SecureString
# $AzureADCred = New-Object System.Management.Automation.PSCredential($appID, $EncryptedSecret)
###################################################################################
# Making Connection
try {
$Context = Get-AzContext
if ($Context){
Write-Host "[>] Connected to $($Context.Name)" -ForegroundColor Magenta
} else {
Connect-AzAccount -ServicePrincipal -TenantId $tenantId -Credential $AzureADCred
}
} catch {
Write-Error "Failed to connect to Azure! Please retry."
exit
}
Disclaimer – I did this from memory, so if I am missing something PLEASE let me know, I can fix it. This is meant as a starting point blog post – “Continuous improvement is better than delayed perfection” – Mark Twain