Thursday, March 02, 2017

PowerShell + AzureRM : Using Certificate based automated login

This is a long overdue post (previous one here) on how to use certificates to do an automated login to Azure Resource Manager. Not rocket science but easy to setup, so that you use a cert to authenticate to Azure RM automatically.

It seems the Azure docs are already up to date on how to do few bits involved in this, please read the section 'Create service principal with a certificate' in the docs.

The process is almost the same as mentioned in the docs, except the fact that when we do the role assignment, we instead assign the contributor role definition to the service principal, since we want the ability to manage the resources in Azure RM.
Also, we will author a function add it to our profile so that PowerShell authenticates automatically to Azure RM each time it opens. 
So let's begin with it:
  1. Create the self-signed certificate.

    If you are running this on Windows 8.1, then you have to use the script by MVP Vadims Podans from the gallery.

    # For OS below Windows 10, download the script and use that to generate the self-signed cert.
    Import-Module .\New-SelfSignedCertificateEx.ps1
    New-SelfSignedCertificateEx -StoreLocation CurrentUser -StoreName My -Subject "CN=AutomateLogin" -KeySpec Exchange
    $cert = Get-ChildItem -path Cert:\CurrentUser\my | where {$PSitem.Subject -eq 'CN=AutomateLogin' }

    Otherwise, if you are running Windows 10 then the builtin PKI module would suffice. Note - The cert created below has marked private key to be not exportable.

    Run below:

    $cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" -Subject "CN=AutomateLogin" -KeySpec KeyExchange -KeyExportPolicy NonExportable

  2. Create the AD app and service principal

    In order to create the Azure AD application, we first need to read the raw certificate data as base64 encoded string (help for the New-AzureRMADApplication clearly states this fact).

    # Get the certificate data as base64 encoded string
    $keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

    # Create a new Azure AD application with the associated certificate
    $app = New-AzureRmADApplication -DisplayName "AutomatedCertLoginApp" -HomePage "" `
            -IdentifierUris "" `
            -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore

    Once the Azure AD Application is created, it is time to add a corresponding AD service principal. Make a note of this application ID (echoed on the host for reference), since it will be passed as a value to our function later.

    # Also create a corresponding service principal for the Azure AD application
    New-AzureRmADServicePrincipal -ApplicationId $app.ApplicationId
    Write-Host -ForeGround Cyan -Object $app.ApplicationId
    Start-Sleep -Seconds 15
  3. Role assignment to the service principalNow the time has come to deviate from the original article being referenced in for this post, it is time to grant the contributor access to the AD service principal created above.

    # Assign the Contributor role definition to the service prinicipal
    New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $app.ApplicationId

  4. Author the automated login function

    Now, I am calling this function Connect-ToAzureRM, in order for us to author this function we would need the current subscription id, which can be fetched using the Get-AzureRMSubscription cmdlet (note the tenantID field).

    Below is how the function is added to my $PROFILE and invoked at the end, you will have to place your subscription tenant id and application id along with the certificate subject name (created above).

    Now, this function is very crude and runs each time PowerShell opens, you might want to customize this by setting the default value of parameters and then invoking the function on demand. You can also get more creative with this concept.

    # Author a new function, add it to $PROFILE and call it everytime PS opens
    Function Connect-ToAzureRM {


        # first fetch the certificate from the Cert store
        $cert = Get-ChildItem -path Cert:\CurrentUser\my | where {$PSitem.Subject -eq $CertificateSubjectName }

        # now use the above cert to authenticate to Azure
        Add-AzureRmAccount -ServicePrincipal -CertificateThumbprint $cert.Thumbprint -ApplicationId $ApplicationId -TenantId $TenantId
     Connect-ToAzureRM -TenantId "place ur Tenant ID" -ApplicationId "place ur app id" -CertificateSubjectName CN=AutomateLogin
References :