Skip to main content

PowerShell + AzureRM : Automated login using Service Principal

Do you remember ?
In the older Azure Service Management model, we had an option to import the publish settings file and use the certificate for authenticating. It saved a lot of hassle.


That method is deprecating now but we have something better which we can use in the newer ARM model.

BTW for record I find it really annoying to enter credentials each time when I want to quickly try something out on Azure. So I have been using two techniques for automated login to the AzureRM portal.





This post is about the easier and a crude way (less secure) to setup the automated login using the Service Principal, in this way we store the service principal credentials (encrypted) in an XML file.
You would need the AzureRM PowerShell module installed. The whole code snippet is placed at the end of the post.

Below are the steps on creating an AzureAD App, tying it with a Service principal and using the service principal creds to do an automated login :

  1. Login to the Azure RM using the Login-AzureRMAccount cmdlet.


    # Login to the Azure Account first                                                            
    Login-AzureRMAccount



    Once done, the current context is displayed i.e. Account, TenantID, SubscriptionID etc.

  2. If you have multiple subscriptions then you need to select the Azure Subscription you want to create the Service principal account and automated login for. If you only have one subscription then, you can skip this step.


    # Select the right Subscription in which the Azure AD application and Service Principal are to be created
    Get-AzureRmSubscription | Out-GridView -OutputMode Single -Title 'Select the Azure Subscription!' | Set-AzureRmContext

  3. Now we need to create an Azure AD Application, this will create a directory services record that identifies an application to Azure AD.

    The homepage & identifier uri can be any valid url. 
    Note identifier uri or application id are used as a username while building credentials for the automated login later along with the password specified in this step.


    # Create the Azure AD App now, this is the directory services record which identifies an application to AAD
    $CMDistrictAADApp = New-AzureRmADApplication -DisplayName "AppForCMDistrict" `
                            -HomePage "http://www.dexterposh.com" `
                            -IdentifierUris "http://www.dexterposh.com/p/about-me.html" `
                            -Password "P@ssW0rd#1234"
  4. Create a Service Principal in Azure AD, this is an instance of an application in Azure AD which needs access to other resources. In plain words application manifests itself as a service principal in directory services in order to gain access to other resources.


    # Create a Service Principal in Azure AD                                                          
    New-AzureRmADServicePrincipal -ApplicationId $CMDistrictAADApp.ApplicationID
  5. Using RBAC grant access to Resource group (CMDistrict_RG in this case), you have to the above service principal.

    Note that since this is a less secured way, so you can be extra careful and give limited access to a Resource Group rather than the entire subscription for this.


    # Grant access to Service Prinicpal for accessing resources in my CMDistrict RG                   
    New-AzureRmRoleAssignment -RoleDefinitionName Contributor `
        -ServicePrincipalName $CMDistrictAADApp.ApplicationId `
        -ResourceGroupName CMDistrict_RG
  6. Now it is time to save the Service Principal credentials locally, easiest way to do is use Get-Credential and then pipe the object to Export-CliXML to save those locally.


    # Export creds to disk (encrypted using DAPI)
    Get-Credential -UserName $CMDistrictAADApp.ApplicationId -Message 'Enter App password' | 
        Export-CLixml -Path "$(Split-Path -path $profile -Parent)\CMDistrictAADApp.xml"

  7. Use the exported credentials next time you want to quickly do something on the resource group. For example - I use a function to on demand start/stop the VMs, so before I run the function I import the creds and authenticate.
    Check below that I create the creds using Import-Clixml and then use those with Add-AzureRMAccount , -ServicePrincipal switch marks that this is a service prinicipal account authenticating.
    Note - You can take the below lines and hard code your tenant-id (get it using Get-AzureRMContext or Get-AzureRMSubscription) below and put this in your profile or wrap it in a function.


    # Authenticate now using the new Service Principal
    $cred = Import-Clixml -Path "$(Split-Path -path $profile -Parent)\CMDistrictAADApp.xml"  

    # Authenticate using the Service Principal now
    Add-AzureRmAccount -ServicePrincipal -Credential $cred -TenantId '<Place your tenant id here>'


BTW if you are wondering why can't we simply create a credential object and pass it to Add-AzureRMAccount ( Login-AzureRMAccount is an alias for it) then read below from MSFT documentation that only organization accounts support that. 

Now one has to go and create a user in your AzureAD and use that account here (another way of doing this), but in the next post you will see that with service principals we can have certificate based logins too (more secure). 

Watch out upcoming article on that subject.



Below is the entire PowerShell code snippet :

#region Automated login using the Service Principal
# Login to the Azure Account first
Login-AzureRMAccount

# Select the right Subscription in which the Azure AD application and Service Principal are to be created
Get-AzureRmSubscription | Out-GridView -OutputMode Single -Title 'Select the Azure Subscription!' | Set-AzureRmContext

# Create the Azure AD App now, this is the directory services record which identifies an application to AAD
$CMDistrictAADApp = New-AzureRmADApplication -DisplayName "AppForCMDistrict" `
                        -HomePage "http://www.dexterposh.com" `
                        -IdentifierUris "http://www.dexterposh.com/p/about-me.html" `
                        -Password "Passw0rd#1234"

# store the applicationID for the above AD App created
$Appid = $CMDistrictAADApp | Select -ExpandProperty ApplicationID

#- Service Prinicipal is an instance of an application in a directory that needs to access other resources.
# Create a Service Principal in Azure AD
New-AzureRmADServicePrincipal -ApplicationId $CMDistrictAADApp.ApplicationID

# Grant access to Service Prinicpal for accessing resources in my CMDistrict RG
New-AzureRmRoleAssignment -RoleDefinitionName Contributor `
    -ServicePrincipalName $CMDistrictAADApp.ApplicationId `
    -ResourceGroupName CMDistrict_RG

# Export creds to disk (encrypted using DAPI)
Get-Credential -UserName $CMDistrictAADApp.ApplicationId -Message 'Enter App password' |
    Export-CLixml -Path "$(Split-Path -path $profile -Parent)\CMDistrictAADApp.xml"

# Authenticate now using the new Service Principal
$cred = Import-Clixml -Path "$(Split-Path -path $profile -Parent)\CMDistrictAADApp.xml"

# Authenticate using the Service Principal now
Add-AzureRmAccount -ServicePrincipal -Credential $cred -TenantId '<Place your tenant Id here>'

#endregion

Popular posts from this blog

Test connectivity via a specific network interface

Recently while working on a Private cloud implementation, I came across a scenario where I needed to test connectivity of a node to the AD/DNS via multiple network adapters.  Many of us would know that having multiple network routes is usually done to take care of redundancy. So that if a network adapter goes down, one can use the other network interface to reach out to the node. In order to make it easy for everyone to follow along, below is an analogy for the above scenario: My laptop has multiple network adapters (say Wi-Fi and Ethernet) connected to the same network. Now how do I test connectivity to a Server on the network only over say Wi-Fi network adapter?

PowerShell + SCCM : Run CM cmdlets remotely

Today I saw a tweet about using implicit remoting to load the Configuration Manager on my machine by Justin Mathews . It caught my eye as I have never really tried it, but theoretically it can be done. Note - The second tweet says "Cannot find a provider with the name CMSite", resolution to which is in the Troubleshooting section at the end.

PowerShell : Trust network share to load modules & ps1

Problem Do you have a central network share, where you store all the scripts or PowerShell modules ? What happens if you try to run the script from a network share ? or if you have scripts (local) which invoke scripts or import PowerShell modules stored on this network share ? Well you would see a security warning like below (Note - I have set execution policy as 'Unrestricted' not 'bypass' here): Run a .ps1 from the network share Well this is a similar warning, which you get when you download scripts from Internet. As the message says run Unblock-File cmdlet to unblock the script and then run it, let's try it.