Freigeben über


Unattended authentication to Azure Management APIs with Azure Active Directory

19/06/2015: See also this new post explaining how to authenticate using Certificates to call the Azure Resource Manager APIs from .NET.

Updated 29/11/2014 with info on authenticating to APIs from PowerShell

Microsoft Azure provides two management APIs, the older Service Management API and the new Azure Resource Manager API. Both are REST APIs (that also serve as the foundation for higher-level APIs such as PowerShell and .NET) that allow you to view and manipulate Azure resources such as websites, VMs and cloud services.

Careless or malicious access to these APIs has the potential to break your applications and cost you money, so obviously these API calls need to be authenticated. There are two ways of doing this: using Azure Active Directory, or using Management Certificates. Today, Management Certificates are probably the most common way of handling authentication, however certificates can be cumbersome to deal with, and more importantly this option is not supported with the new Azure Resource Manager API. Therefore it’s important to understand how to use Azure Active Directory to authenticate to the APIs.

Brady Gaster has an excellent post that provides step-by-step instructions on using AAD to authenticate calls to the Service Management API. However the approach he’s used results in a dialog box popping up asking for credentials. This is fine for certain operations tasks launched interactively by a human (or cyborg equivalent), but no good for any fully automated processes such as continuous deployment, scripted scaling or failover tasks. Fortunately, you can modify this approach to avoid the dialog box and authenticate your scripts without any user interaction.

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

 

Setting up your Unattended User Account

The first thing you’ll need is a service account whose credentials you’ll be using to authenticate against Azure Active Directory. A service account is important as you don’t to put your own credentials into your scripts, plus if you use a Microsoft Account to authenticate to the Azure Portal you couldn’t use this with the APIs even if you wanted to.

When you log into the Azure Management Portal and choose the Active Directory icon (it’s a pyramid shaped thing), you should see a default directory associated with your subscription. Confusingly, my directory has the exact same name as me (although I’m the better looking of the two). After selecting my directory, I can drill into Users and create a new user (I called mine “Service Account” or “service” for short). Azure Active Directory will assign a temporary password; you’ll need to log in as that user in another browser session to assign a permanent password. Note the user will be given a UPN with your directory’s domain name, which in my case is service@tomhollanderhotmail.onmicrosoft.com.

image

Now, you need to give this user access to your subscription. When using the Service Management API, the only option is to make this user a co-admin of your subscription, which gives them the keys to the castle – they can do whatever they want in your subscription. This is obviously risky, so you’ll need to be very careful to protect the credentials for your service account. To make the user a co-admin, choose Manage Administrators from the subscription menu at the top of the page, enter the user’s UPN and choose the subscription(s) you want them to have access to.

image

On the other hand, if you’re using the Azure Resource Manager API, you can use the awesome new Role-Based Access Control functionality to assign fine-grained permissions to different users. While you’ll still need to be careful with the service account credentials, this approach is much safer as you can limit the account’s rights to what they need to do. In my case I’ll use the new Azure Portal to add it to my subscription’s built-in Reader group, giving it read-only access to all of my resources, although I could have been much more fine-grained, for example by letting it create but not delete websites.

image

 

Accessing the APIs from .NET

Setting up your AAD Client Application

One final step before we start coding is to add a Client Application to our Azure Active Directory tenant. This is the exact same process described in the documentation. In a nutshell, you need to select your directory, choose Applications, add a new Native Client application, assign it access to the Service Management APIs, and note down the Client ID as you’ll need it in your code.

 

Getting an Authorisation Token

Finally, we’re ready to start coding! First, we’ll need to use Nuget to pull down the Active Directory Authentication Library (ADAL). ADAL is used to authenticate your user and generate an authorisation token which will be later sent to the Azure Management or Azure Resource Manager API via an HTTP header. Note the commented out code showing the “normal” way of using ADAL which results in an authentication dialog. However in this case we’re going to specify the credentials directly (loaded from a configuration file). Make sure to read this post from identity guru Vittorio Bertocci that provides more context around the capbilities, limitations and risks of this approach.

private const string _subscriptionId = "xxxxxxxxxxxxxxxxx"; private const string _aadTenantDomain = "tomhollanderhotmail.onmicrosoft.com"; private const string _aadClientId = "yyyyyyyyyyyyy"; private static string GetAuthorizationHeader() {     AuthenticationResult result = null;     var context = new AuthenticationContext("https://login.windows.net/" + _aadTenantDomain);

 

    // If you wanted to show a credential dialog, do this:
    //result = context.AcquireToken(
    //    "https://management.core.windows.net/",
    //    _aadClientId,
    //      new Uri("https://localhost"), PromptBehavior.Auto);

    // Directly specify the username and password.
    var credential = new UserCredential(
        ConfigurationManager.AppSettings["serviceAccountUserName"],
        ConfigurationManager.AppSettings["serviceAccountPassword"]);
    result = context.AcquireToken(
        "https://management.core.windows.net/",
        _aadClientId,
            credential);
    if (result == null)
    {
        throw new InvalidOperationException("Failed to obtain the JWT token");
    }

    string token = result.AccessToken;
    return token;
}

Calling the APIs

Now we have a token, let’s call some APIs! This post isn’t about the details of the specific APIs or what you can do with them, so here are some very simple, “Hello World”-esque calls. Note that while I’m calling two different APIs (Service Management API and Azure Resource Manager API), the same authorisation token is used for both.

private static async Task CallServiceManagementApi() {     var client = new HttpClient();     var header = GetAuthorizationHeader();     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", header);     client.DefaultRequestHeaders.Add("x-ms-version", "2009-10-01");

 

    try
    {
        var result = await
            client.GetStringAsync(
                String.Format(
                    "https://management.core.windows.net/{0}/services/hostedservices",
                    _subscriptionId));
        Console.WriteLine(result);

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

private static async Task CallAzureResourceManagerApi()
{
    var client = new HttpClient();
    var header = GetAuthorizationHeader();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", header);

    try
    {
        var result = await
        client.GetStringAsync(
            String.Format(
                "https://management.azure.com/subscriptions/{0}/resourcegroups?api-version=2014-04-01-preview",
                _subscriptionId));
        Console.WriteLine(result);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

 

Accessing the APIs from PowerShell

While it can be useful to call the Management APIs from .NET, many operations tasks are better accomplished through PowerShell. Fortunately you can also perform an unattended authentication to Azure Active Directory from PowerShell too.

First, we need to call Add-AzureAccount with the service account credentials:

$securepassword = ConvertTo-SecureString -string "<YourPasswordGoesHere>" -AsPlainText -Force

 

$cred = new-object System.Management.Automation.PSCredential ("service@tomhollanderhotmail.onmicrosoft.com", $securepassword)

Add-AzureAccount -Credential $cred

Now you can use either the Azure Service Management or Azure Resource Manager cmdlets to perform your desired operations:

Get-HostedService

Switch-AzureMode AzureResourceManager

Get-AzureResourceGroup

Conclusion

Using Azure Active Directory to authenticate your Azure management API calls allows you to avoid deploying management certificates, and is a requirement if you are using the new Azure Resource Manager API. When your scripts are run interactively the most secure way of authenticating is to obtain credentials from the user each time. However if your scripts are running without any human interaction, you can authenticate by specifying the username and password directly in your code. Whenever you do this, be sure to protect the credentials carefully and change the password regularly, particularly if your user account is a co-administrator of your subscription.