Authenticating to Azure Resource Manager using AAD and Certificates


In a previous post I described how to perform unattended authentication to Azure Active Directory using a username and password. This post takes this further by showing how to use certificates, rather than passwords, to authenticate. Using certificates for authentication is generally considered more secure, as there are no credentials in your code and it cannot run without an appropriate certificate installed on the machine executing the script. This approach can be used for anything that authenticates using AAD, but I’ll describe specially how to use this to call the Azure Resource Manager APIs from .NET, allowing your code to interrogate and/or manipulate Azure resources.

This post is basically combining ideas and code from the Daemon-CertificateCredential-DotNet AAD sample and Neil Mackenzie’s post on Using a Service Principal for Azure PowerShell Authentication.

Note: Azure’s capabilities and APIs change rapidly. This information is current as of June 2015. If you’re reading this in the distant future, you may want to check with other sources on current capabilities and best practices.

Create a new Application in your AAD tenant

Open up the Old Azure Management Portal, browse to the Azure Active Directory tenant associated with your description, click on the Applications tab and then click Add. Enter a nice name for your application and choose “Web Application and/or Web API” as the type. You’ll need to complete the Sign-on URL and the App ID URI but it doesn’t really matter what they are in this case. Once the application has been configured, click on the Configure tab and make a note of the Client ID.

Associate a Certificate with your AAD account

Next you’ll need to create/acquire a certificate to use for authentication. If you haven’t got one handy, you can create a self-signed one using the makecert tool which you should have access to from a Visual Studio developer command prompt:

makecert -r -pe -n "CN=MyAzureManagement" -ss My -len 2048 c:\temp\MyAzureManagement.cer

To associate the certificate with your AAD account you’ll need to install the Azure AD PowerShell module.

connect-msolservice
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate
$cer.Import("c:\temp\MyAzureManagement.cer")
$binCert = $cer.GetRawCertData()
$credValue = [System.Convert]::ToBase64String($binCert);
New-MsolServicePrincipalCredential -AppPrincipalId "<Client ID for your AAD app>" -Type asymmetric -Value $credValue -Usage verify

Assign your AAD application to an Azure Management Role

Even though we can now authenticate as your AAD application using a certificate, that account doesn’t yet have permissions to do anything to your Azure account. To enable this, we’ll need to add your AAD application to the appropriate Azure Resource Manager role. Remember that ARM has full role-based access control, so you can be quite fine-grained in what the application should be allowed to do.

The new Azure Portal currently lets you assign permissions to AAD Users, but not to AAD Applications. Since we want to do the latter, we’ll need to use the Azure PowerShell module. In this case I’m adding the application to the “Contributes” role for a specific resource group.

Switch-AzureMode AzureResourceManager
New-AzureRoleAssignment `
   -ServicePrincipalName "<Client ID for your AAD app>" `
   -RoleDefinitionName "Contributor" `
   -Scope "/subscriptions/<Your Azure SubscriptionId>/resourceGroups/Default-Web-WestUS"
 

Authenticate to AAD and call the Azure Resource Manager APIs

Finally we have everything we need to call the APIs. As far as I know it’s not possible to use certificates to authenticate to AAD from PowerShell, so we will be doing this from .NET.

The following sample code should run happily in a console app if you add the ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory) and ARM (Microsoft.Azure.Management.Resources) NuGet packages, and update the various constants for your subscription. All it does is list a couple of properties from the resource group but you whatever you want, provided your AAD app has the required roles.

string clientId = "<Client ID for your AAD app>";
var subscriptionId = "<Your Azure SubscriptionId>";
string tenant = "<AAD tenant name>>.onmicrosoft.com";

var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenant));

X509Certificate2 cert = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
string certName = "MyAzureManagement";
try
{
    store.Open(OpenFlags.ReadOnly);
    var certCollection = store.Certificates;
    var certs = certCollection.Find(X509FindType.FindBySubjectName, certName, false);
    cert = certs[0];
}
finally
{
    store.Close();
}

var certCred = new ClientAssertionCertificate(clientId, cert);
var token = authContext.AcquireToken("https://management.core.windows.net/", certCred);
var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
var client = new ResourceManagementClient(creds);
var rg = client.ResourceGroups.Get("Default-Web-WestUS");
Console.WriteLine(rg.ResourceGroup.Id);
Console.WriteLine(rg.ResourceGroup.Location);


Comments (1)
  1. Marc says:

    Hello,

    Thank you very much for this post, which addresses a major need I have.

    I successfully implemented the procedure you provided in your previous post (unattended authentication using hard-coded user name and password). Usage of certificates would consist of a much better way for me and I was happy to find this post. However, I get an error when using this command:

    New-MsolServicePrincipalCredential -AppPrincipalId “” -Type asymmetric -Value $credValue -Usage verif

    The error is the following:

    New-MsolServicePrincipalCredential : Access Denied. You do not have permissions to call this cmdlet.
    At line:1 char:1
    + New-MsolServicePrincipalCredential -AppPrincipalId “xxxxxx …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (:) [New-MsolServicePrincipalCredential], MicrosoftOnlineException
    + FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.AccessDeniedException,Microsoft.Online.Administration.Automation.NewServicePrincipalCredential

    I did the procedure outlined here twice, with the same result.

    I would greatly appreciate any suggestion you might have in order to work around this issue.

    Thanks and Regards,

    Marc

Comments are closed.

Skip to main content