December 7, 2016 Leave a comment
You know those annoying “back in my day” stories your crazy uncle would tell at the holidays? Well I have one of those. Fortunately for all of us, I’m also here to tell you how to accomplish this using today’s tech. But before we get to the cool stuff, I want to hop into the wayback machine for a few. So come along Sherman. BTW, that’s an old cartoon joke for you “yung’uns”.
Once upon a time, we had the Azure Management Service
Before the world of the Azure Resource Manager (ARM), there was ASM, the “Service Management” interface. Much like ARM, it was a REST based API for interacting with Azure’s resources. But this predated Azure Active Directory, so the only way to interact with it outside of a username/password was via “management certificates”. These were just any old certificate that you happened to have around, but what made them special is that when you uploaded them to the Azure portal, you could then use them to interact with the management API via the command line. And best yet, these certificates gave you co-administrator authority. Essentially allowing you to do almost anything with the subscription that you wanted.
By the time ARM showed up about 2 years ago, we had Azure AD. And folks were starting to look at Role Based Access Control (RBAC) and the notion of “just enough security”. Basically they didn’t want to give a certificate that could be passed around between developers. So Azure stepped up its RBAC implementation, and more and more services started supporting role-based security.
Adding a new user to Azure AD and granting it permissions is easy enough. But what if you need to have a process execute something against the ARM api? You’d have to set up a user identity, complete with password for the process. Then store the username/password somewhere secure. This is where the management certificates had a nice advantage. A certificate can be installed on a server and flagged as “not exportable”. So the certificate becomes a credential that a process can use. But how do we do this in the new Azure AD world?
Azure AD has the concept of Applications. And these applications could be associated with a certificate. And together, they form a service principle. A principle that gives us the best of both worlds.
Creating your certificate
The first step in setting this up is to create a certificate we can use. And not any old certificate will do, there’s a couple gotcha’s here. First off, to use a certificate as a service principle in Azure, it needs to have a common name. I don’t know why, but this seems to be something that’s enforced by Azure AD. The second is (and I hope this is considered a no-brainer), don’t generate a certificate using a SHA1 hash algorithm. If you missed the news, SHA1 is no longer considered secure enough and is being deprecated across the industry.
With these requirements in hand, the next step is to set about creating the certificate. On Windows, you may be tempted to reach for that old stand-by, MakeCert. Please don’t. Instead, open up PowerShell and find the New-SelfSignedCertificate cmdlet.
Using this cmdlet, we can use this snippet of PowerShell to generate a self-signed certificate
$certSubject = Read-Host -Prompt “Issue By/To for the certificate” $cert = New-SelfSignedCertificate ` -CertStoreLocation Cert:\CurrentUser\My ` -Subject "CN=$($certSubject)" ` -KeySpec KeyExchange ` -HashAlgorithm SHA256
This creates the certificate using the SHA256 hash, the common name we specified, and places it into the current user’s Personal/Certificate store. You can then use the MMC (Microsoft Management Console, windows key + R, then MMC) to locate the certificate and export it using the “save as file” option.
Creating the Application and Principle
The PowerShell above doesn’t just create the certificate, it also returns some of its attributes so we can continue to use them. So the next step is to start constructing our service principle. We’ll continue using PowerShell and start by capturing the details of the certificate that we’ll need later.
# Get certificate thumbprint $certThumbprint = $cert.Thumbprint # Get public key and properties from selected cert $keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData()) $keyId = [guid]::NewGuid() $startDate = $cert.NotBefore $endDate = $cert.NotAfter
These lines capture the certificate thumbprint and other data such as the certificate start/end dates. We also create a GUID that will uniquely identify the credential. Then, we use these values to create a PowerShell credential, a PSAADKeyCredential object.
Import-Module ` -Name AzureRM.Resources $keyCredential = New-Object -TypeName Microsoft.Azure.Commands.Resources.Models.ActiveDirectory.PSADKeyCredential $keyCredential.StartDate = $startDate $keyCredential.EndDate = $endDate $keyCredential.KeyId = $keyId $keyCredential.CertValue = $keyValue
We start by importing the Azure Resource Manager module that contains what we need to create the Azure AD application/principle. We then create a blank credential object and populate it with the values we saved off earlier.
With this done, we need to log into Azure (when run, you’ll need to enter your Azure username/password credentials), and create the Azure AD Application using the PowerShell credential object that’s based on our newly created certificate.
Login-AzureRmAccount # Define Azure AD App values for new Service Principal $adAppName = Read-Host -Prompt “Enter unique Azure AD App name” #these aren't needed for our uses, but need to be completed anyways $adAppHomePage = "<a href="http://$(">http://$(</a>$adAppName)" $adAppIdentifierUri = "<a href="http://$(">http://$(</a>$adAppName)" # Create Azure AD App object for new Service Principal $adApp = New-AzureRmADApplication ` -DisplayName $adAppName ` -HomePage $adAppHomePage ` -IdentifierUris $adAppIdentifierUri ` -KeyCredentials $keyCredential Write-Output “New Azure AD App Id: $($adApp.ApplicationId)”
Its important to keep in mind, that the New-AzureRMADApplication cmd requires you to have permissions in the subscription’s Azure AD tenant to create the application. If your Azure AD tenant is tightly managed, or perhaps even bound to an on-prem Active Directory or Office365 tenant, this isn’t likely going to be the case. So this step may need to be executed by someone with the proper Azure AD administrative permissions.
With the application created, we save the Application ID (save this for later, we’ll need it) and we’re then ready to create its associated service principle.
$principleID = New-AzureRmADServicePrincipal ` -ApplicationId $adApp.ApplicationId
Granting Permissions and Using the Credential
With the application and service principle created, we can now grant it permissions like we would a user. But instead of specifying the user, we specify the Service Principle via the Application ID that we saved earlier. . You should only give the principle the minimum permissions, but since I’m only doing an example here, I’ll give you full access as an owner of the subscription.
New-AzureRmRoleAssignment ` -RoleDefinitionName Owner ` -ServicePrincipalName $adApp.ApplicationId
Now a special note if you’re scripting all this. Between adding the principle and assigning it to a role, there’s some lag. This is because in the cloud the service that’s doing the add and the one that’s granting permissions may not be the same. So there’s some latency regarding the data between the two services. So you may see a few seconds (generally less than 10-15) before the addition of the principle and being able to add the permission succeeds. Not a big deal if you’re doing these commands by hand, but if you’re scripting the process, you’ll need to address this.
With the principle created and given permission to access the subscription, we can then use it to log into Azure.
Login-AzureRmAccount ` -ServicePrincipal ` -TenantId $tenantId ` -ApplicationId $appId ` -CertificateThumbprint $certThumbprint
The tenantId is the Azure AD tenant we’re logging in to, the $appId is the application we created (I told you to save that), and the $certThumbprint is the thumbprint of the certificate that’s installed on the machine that will be used to log in. Under the covers the certificate is retrieved and then presented to Azure AD to authenticate our login request.
With this done, you’re now able to continue on, doing whatever other PowerShell commands you need.
So that’s about it. Hopefully my explanation is straight forward enough. I’ve put two scripts up on github that show what we’ve just covered end to end. But before I end this completely I need to give some credit where its due. This post is based on the great work of Keith Mayer. You can even find his original version on github as well. What he pulled together is SOOO much more elegant than anything I could have done. So major kudos to him.
Until next time!