Saturday, May 07, 2016

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

3 comments:

  1. You wrote, that there will be a post on

    " Using Certificate based automated login (another post)."

    Where is the post?

    ReplyDelete
    Replies
    1. True, I haven't gotten around to it. Let me give it a shot this week.
      Thanks for the reminder ;)

      Delete
    2. Hey there,
      Thanks for pushing me to complete this one.
      The post is live now here -> http://www.dexterposh.com/2017/03/powershell-azurerm-using-certificate.html

      Delete