Automatically Logging PowerShell in to Azure

I've been working with Azure Resource Manager templates a lot lately, as an easy, repeatable way to create deployment environments for my code.  ARM templates are a JSON description of a resource or grouping of resources and can be applied to create or update an environment.  This means you can roll out a new environment quickly and easily - perfect for quickly setting up a Dev or Test system, and you know that if you use the same templates to configure Production you won't have any surprises, or "Well, it worked in Dev..." conversations.
The best thing about ARM templates for me is how easy it is to generate them.  If you have a resource group, you can create a template by clicking on the Automation Script button:

This will create a show you a JSON template and supporting files that can be downloaded as a Zip.  It contains all the information needed to reproduce your resource group's infrastructure.  It isn't a backup though - it doesn't have the website code or the rows from your database or anything.  My automation script view looks like this:

The template is a little rough around the edges - the parameter names are very tightly tied to the original resource group ("databaseAccounts_arm_template_demo_name" for example) but will work almost straight away.  The zip file contains the following files:

The template and parameters files go together - the parameter file contains the various settings that can be changed for each deployment or environment.  You can copy this file for different deploys, changing the web server to a more powerful type in Production or whatever.  Out of the box all values are set to null, though - you need to change this before the template will work.  Alternatively, delete the parameters file as the template has defaults that will be used instead.

My parameters file is above - replace all the nulls with the appropriate values (use the template's default values as guides), and you can try a deploy.  Open PowerShell and run deploy.ps1:

The script asks for your subscription ID, and the resource group name you want to deploy to, then it opens an Azure login dialogue.  This is OK at first, but gets really tiresome after a while, especially if you're trying out different parameters and settings like I was.  Fortunately it's easy to fix.
All of the parameters for the PowerShell script are described at the beginning of the file - you can set these on the command line so you don't have to type them in again and again:

This is much easier to run and re-run but it still makes you log in every time.  The answer to this is using a Service Principal to connect and run the deploy, rather than logging in yourself.  The Service Principal can be set up to use a certificate to authenticate, meaning you don't need to supply a key or password each time.  Service Principals are explained here, and if you're from a Unix background like me you can think of them as the user that an application runs as.  When you run Apache or PostgreSQL on a server, for example, they don't run as root but as some other user so that if they're breached, the hacker does not have root access.  Instead they'll get "apache" or "postgres" user permissions which are usually very limited.
In practice I have found adding Service Principals via the Azure Portal quite tricky.  Part of this is working out where to grant access, and another part is the various IDs that Microsoft make you use (ObjectId, ApplicationId, ClientId...) and trying to work out whether the ApplicationId or the ObjectId is ClientId (no seriously, Microsoft!  What are you thinking!?)  Fortunately I found some PowerShell to create a Service Principal and configure it:

This script makes you log in to the Azure account, and creates a Service Principal for you.  It does get Contributor access to your subscription, so this may not be for you - I will look at limiting its access to a single resource group in future.  Contributors have the ability to alter any resource in their scope, but can't assign other people this right - so if someone cracks your Contributor access they can delete all your resources!  Be careful, this may not be right for you.
Once you've run this script, check in your Active Directory for the new Application Registration (related to the Service Principal):

You're ready to test out the easy login now.  Take note of the ApplicationID of the Service Principal, and the TenantId (the ID of your Azure Active Directory) then run this PowerShell:

$Thumbprint =  (Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -match "NewServicePrincipal" }).Thumbprint
Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $Thumbprint -ApplicationId <App ID> -TenantId <Tenant ID>

This will look up the "NewServicePrincipal" certificate in your keychain, and use this to authenticate to Azure.  It will log in and has Contributor rights, so can alter resources for you.  Perfect!
All that's left to do now is to modify the deploy.ps1 script so that it uses this login:

I added 3 parameters to the beginning (applicationId, tenantId and certificateSubject) and modified the lines around the login.

The deploy script will now log in automatically and not prompt for any parameters - the final PowerShell command looks like this:

deploy.ps1 -subscriptionId <Subscription ID> -resourceGroupName new-rg -resourceGroupLocation "Australia East" -deploymentName Demo -applicationId <App ID> -tenantId <Tenant ID> -certificateSubject NewServicePrincipal

Hope this helps speed up your ARM template development!


Popular posts from this blog

Feature Toggles on a .Net Core API

Feature Toggles for Angular UIs