Tag Archives: Security

Security at large ; Azure Security Center, Log Analytics, Key Vault

Automating Azure AD

https://pixabay.com/en/machine-factory-automation-1651014/

In the previous article, we explored how to interact (read / write) to an Azure AD tenant using Microsoft Graph API.

In the article before that, we looked at how to authenticate a user without using Azure AD web flow.

Those were motivated by a specific scenario:  replacing a LDAP server by Azure AD while migrating a SaaS application to Azure.

Now a SaaS application will typically have multiple tenants or instances.  Configuring Azure AD by hand, like any other Azure service, can be tedious and error prone.  Furthermore, once we’ve onboarded say 20 tenants, making a configuration change will be even more tedious and error prone.

This is why we’ll look at automation in this article.

We’ll look at how to automate the creation of Azure AD applications we used in the last two articles.  From there it’s pretty easy to generalize (aka exercise to the reader!).

Azure AD Tenant creation

From the get go, bad news, we can’t create the tenant by automation.

No API is exposed for that, we need to go through the portal.

Sorry.

Which PowerShell commands to use?

Automating Azure AD is a little confusing.  Too many options is like not enough.

The first approach should probably be to use the Azure PowerShell package like the rest of Azure services.  For instance, to create an application, we would use New-AzureRmADApplication.

The problem with that package for our scenario is that the Azure AD tenant isn’t attached to a subscription. This is typical for a SaaS model:  we have an Azure AD tenant to manage internal users on all subscriptions and then different tenants to manage external users.  Unfortunately, at the time of this writing, the Azure PowerShell package is tied around the Add-AzureRmAccount command to authenticate the user ; that command binds a subscription (or via the Select-AzureRmSubscription).  But in our case we do not have a subscription:  our Azure AD tenant isn’t managing a subscription.

The second approach would then be to use the MSOnline Module.  That’s centered around Azure AD, but it is slowly being deprecated for…

The third approach, Azure Active Directory V2 PowerShell module.  This is what we’re going to use.

I want to give a big shout to Chris Dituri for tapping the trail here.  His article Azure Active Directory: Creating Applications and SPNs with Powershell was instrumental to write this article.  As we’ll see, there are bunch of intricacies about the application permissions that aren’t documented and that Chris unraveled.

The first thing we’ll need to do is to install the PowerShell package.  Easy:

Install-Module AzureADPreview

If you read this from the future, this might have changed, so check out the documentation page for install instructions.

Connect-AzureAD

We need to connect to our tenant:

connect-azuread -TenantId bc7d0032…

You can see the documentation on the Connect-AzureAD command here.

Where do we take our tenant ID?

image

Now we can go and create applications.

Service-Client

Here we’ll replicate the applications we built by hand in the Authenticating to Azure AD non-interactively article.

Remember, those are two applications, a service and a client one.  The client one has permission to access the service one & let users sign in to it.  As we’ll see, giving those permissions are a little tricky.

Let’s start by the final PowerShell code:

#  Grab the Azure AD Service principal
$aad = (Get-AzureADServicePrincipal | `
    where {$_.ServicePrincipalNames.Contains("https://graph.windows.net")})[0]
#  Grab the User.Read permission
$userRead = $aad.Oauth2Permissions | ? {$_.Value -eq "User.Read"}

#  Resource Access User.Read + Sign in
$readUserAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$aad.AppId ;
  ResourceAccess=[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
    Id = $userRead.Id ;
    Type = "Scope"}}

#  Create Service App
$svc = New-AzureADApplication -DisplayName "MyLegacyService" `
    -IdentifierUris "uri://mylegacyservice.com"
# Associate a Service Principal to the service Application 
$spSvc = New-AzureADServicePrincipal -AppId $svc.AppId
#  Grab the user-impersonation permission
$svcUserImpersonation = $spSvc.Oauth2Permissions | `
    ?{$_.Value -eq "user_impersonation"}
 
#  Resource Access 'Access' a service
$accessAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$svc.AppId ;
  ResourceAccess=[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
    Id = $svcUserImpersonation.Id ;
    Type = "Scope"}}
#  Create Required Access 
$client = New-AzureADApplication -DisplayName "MyLegacyClient" `
  -PublicClient $true `
  -RequiredResourceAccess $readUserAccess, $accessAccess

As promised, there is ample amount of ceremony.  Let’s go through it.

  • Line 1:  we grab the service principal that has a https://graph.windows.net for a name ; you can check all the service principals living in your tenant with Get-AzureADServicePrincipal ; I have 15 with a clean tenant.  We’ll need the Graph one since we need to give access to it.
  • Line 5:  we grab the specific user read permission inside that service principal’s Oauth2Permissions collection.  Basically, service principals expose the permission that other apps can get with them.  We’re going to need the ID.  Lots of GUIDs in Azure AD.
  • Line 8:  we then construct a user-read RequiredResourceAccess object with that permission
  • Line 15:  we create our Legacy service app
  • Line 16:  we associate a service principal to that app
  • Line 20:  we grab the user impersonation permission of that service principal.  Same mechanism we used for the Graph API, just a different permission.
  • Line 24:  we build another RequiredResourceAccess object around that user impersonation permission.
  • Line 30:  we create our Legacy client app ; we attach both the user-read & user impersonation permission to it.

Grant Permissions

If we try to run the authentication piece of code we had in the article, we’ll first need to change the “clientID” value for $client.AppId (and make sure serviceUri has the value of “uri://mylegacyservice.com”).

Now if we run that, we’ll get an error along the line of

The user or administrator has not consented to use the application with ID ‘…’. Send an interactive authorization request for this user and resource.

What is that?

There is one manual step we have to take, that is to grant the permissions to the application.  In Azure AD, this must be performed by an admin and there are no API exposed for it.

We could sort of automate it with code via an authentication workflow (which is what the error message is suggesting to do), which I won’t do here.

Basically, an administrator (of the Azure AD tenant) needs to approve the use of the app.

We can also do it, still manually, via the portal as we did in the article.  But first, let’s throw the following command:

Get-AzureADOAuth2PermissionGrant

On an empty tenant, there should be nothing returned.  Unfortunately, there are no Add/New-AzureADOAuth2PermissionGrant at the time of this writing (this might have changed if you are from the future so make sure you check out the available commands).

So the manual step is, in the portal, to go in the MyLegacyClient App, select Required Permissions then click the Grant Permissions button.

image

Once we’ve done this we can run the same PowerShell command, i.e.

Get-AzureADOAuth2PermissionGrant

and have two entries now.

image

We see the two permissions we attached to MyLegacyClient.

We should now be able to run the authentication code.

Graph API App

Here we’ll replicate the application we created by hand in the Using Microsoft Graph API to interact with Azure AD article.

This is going to be quite similar, except we’re going to attach a client secret on the application so that we can authenticate against it.

#  Grab the Azure AD Service principal
$aad = (Get-AzureADServicePrincipal | `
    where {$_.ServicePrincipalNames.Contains("https://graph.windows.net")})[0]
#  Grab the User.Read permission
$userRead = $aad.Oauth2Permissions | ? {$_.Value -eq "User.Read"}
#  Grab the Directory.ReadWrite.All permission
$directoryWrite = $aad.Oauth2Permissions | `
  ? {$_.Value -eq "Directory.ReadWrite.All"}


#  Resource Access User.Read + Sign in & Directory.ReadWrite.All
$readWriteAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$aad.AppId ;
  ResourceAccess=[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
    Id = $userRead.Id ;
    Type = "Scope"}, [Microsoft.Open.AzureAD.Model.ResourceAccess]@{
    Id = $directoryWrite.Id ;
    Type = "Role"}}

#  Create querying App
$queryApp = New-AzureADApplication -DisplayName "QueryingApp" `
    -IdentifierUris "uri://myqueryingapp.com" `
    -RequiredResourceAccess $readWriteAccess

#  Associate a Service Principal so it can login
$spQuery = New-AzureADServicePrincipal -AppId $queryApp.AppId

#  Create a key credential for the app valid from now
#  (-1 day, to accomodate client / service time difference)
#  till three months from now
$startDate = (Get-Date).AddDays(-1)
$endDate = $startDate.AddMonths(3)

$pwd = New-AzureADApplicationPasswordCredential -ObjectId $queryApp.ObjectId `
  -StartDate $startDate -EndDate $endDate `
  -CustomKeyIdentifier "MyCredentials"

You need to “grant permissions” for the new application before trying to authenticate against it.

Two big remarks on tiny bugs ; they might be fixed by the time you read this and they aren’t critical as they both have easy work around:

  1. The last command in the script, i.e. the password section, will fail with a “stream property was found in a JSON Light request payload. Stream properties are only supported in responses” if you execute the entire script in one go.  If you execute it separately, it doesn’t.  Beat me.
  2. This one took me 3 hours to realize, so use my wisdom:  DO NOT TRY TO AUTHENTICATE THE APP BEFORE GRANTING PERMISSIONS.  There seems to be some caching on the authentication service so if you do try to authenticate when you don’t have the permissions, you’ll keep receiving the same claims after even if you did grant the permissions.  Annoying, but easy to avoid once you know it.

An interesting aspect of the automation is that we have a much more fine grained control on the duration of the password than in the Portal (1 year, 2 years, infinite).  That allows us to implement a more aggressive rotation of secrets.

Summary

Automation with Azure AD, as with other services, helps reduce the effort to provision and the human errors.

There are two big manual steps that can’t be automated in Azure AD:

  • Azure AD tenant creation
  • Granting permissions on an application

That might change in the future, but for now, that limits the amount of automation you can do with human interactions.

Using Microsoft Graph API to interact with Azure AD

In my last article, I showed how to authenticate on Azure AD using a user name / password without using the native web flow.

The underlying scenario was to migrate an application using an LDAP server by leveraging an Azure AD tenant.

The logical continuation of that scenario is to use the Microsoft Graph API to interact with the tenant the same way we would use LDAP queries to interact with the LDAP server.

Microsoft Graph API is a generalization of the Azure AD Graph API and should be used instead.  It consists of simple REST queries which are all documented.

In this scenario, I’ll consider three simple interactions:

  • Testing if a user exists
  • Returning the groups a user belong to
  • Creating a new user

But first we need to setup the Azure AD tenant.

Azure AD setup

We’re going to rely on the last article to do the heavy lifting.

We are going to create a new application (here we’re going to use the name “QueryingApp”) of type Web App / API (although native should probably work).

The important part is to grab its Application-ID & also to give it enough permission to create users.

image

In this scenario, the application is going to authenticate itself (as opposed to a user) so we need to define a secret.

image

We’ll need to add a key, save & copy the key value.

Authenticating with ADAL

This sample is in C# / .NET but since the Active Directory Authentication Library (ADAL) is available on multiple platform (e.g. Java), this should be easy to port.

We need to install the NuGet package Microsoft.IdentityModel.Clients.ActiveDirectory in our project.

        private static async Task<string> AppAuthenticationAsync()
        {
            //  Constants
            var tenant = "LdapVplDemo.onmicrosoft.com";
            var resource = "https://graph.microsoft.com/";
            var clientID = "9a9f5e70-5501-4e9c-bd00-d4114ebeb419";
            var secret = "Ou+KN1DYv8337hG8o8+qRZ1EPqBMWwER/zvgqvmEe74=";

            //  Ceremony
            var authority = $"https://login.microsoftonline.com/{tenant}";
            var authContext = new AuthenticationContext(authority);
            var credentials = new ClientCredential(clientID, secret);
            var authResult = await authContext.AcquireTokenAsync(resource, credentials);

            return authResult.AccessToken;
        }

Here the clientID is the application ID of the application we created at secret is the secret key we created for it.

Here we return the access token as we’re going to use them.

Authenticating with HTTP POST

If we do not want to integrate with the ADAL, here’s the bare bone HTTP post version:

        private static async Task<string> HttpAppAuthenticationAsync()
        {
            //  Constants
            var tenant = "LdapVplDemo.onmicrosoft.com";
            var clientID = "9a9f5e70-5501-4e9c-bd00-d4114ebeb419";
            var resource = "https://graph.microsoft.com/";
            var secret = "Ou+KN1DYv8337hG8o8+qRZ1EPqBMWwER/zvgqvmEe74=";

            using (var webClient = new WebClient())
            {
                var requestParameters = new NameValueCollection();

                requestParameters.Add("resource", resource);
                requestParameters.Add("client_id", clientID);
                requestParameters.Add("grant_type", "client_credentials");
                requestParameters.Add("client_secret", secret);

                var url = $"https://login.microsoftonline.com/{tenant}/oauth2/token";
                var responsebytes = await webClient.UploadValuesTaskAsync(url, "POST", requestParameters);
                var responsebody = Encoding.UTF8.GetString(responsebytes);
                var obj = JsonConvert.DeserializeObject<JObject>(responsebody);
                var token = obj["access_token"].Value<string>();

                return token;
            }
        }

Here I use the popular Newtonsoft Json Nuget Package to handle JSON.

By no mean is the code here a master piece of robustness and style.  It is meant to be straightforward and easy to understand.  By all means, improve it %500 before calling it production ready!

Testing if a user exists

Here we’re going to use the User Get of Microsoft Graph API.

There is actually a NuGet package for Microsoft Graph API and, in general SDKs (at the time of this writing) for 9 platforms.

        private static async Task<bool> DoesUserExistsAsync(HttpClient client, string user)
        {
            try
            {
                var payload = await client.GetStringAsync($"https://graph.microsoft.com/v1.0/users/{user}");

                return true;
            }
            catch (HttpRequestException)
            {
                return false;
            }
        }

Again, the code is minimalist here.  The HTTP GET actually returns user information that could be used.

Returning the groups a user belong to

Here we’re going to use the memberof method of Microsoft Graph API.

        private static async Task<string[]> GetUserGroupsAsync(HttpClient client, string user)
        {
            var payload = await client.GetStringAsync(
                $"https://graph.microsoft.com/v1.0/users/{user}/memberOf");
            var obj = JsonConvert.DeserializeObject<JObject>(payload);
            var groupDescription = from g in obj["value"]
                                   select g["displayName"].Value<string>();

            return groupDescription.ToArray();
        }

Here, we deserialize the returned payload to extract the group display names.  The information returned is richer and could be used.

Creating a new user

Finally we’re going to use the Create User method of Microsoft Graph API.

This is slightly more complicated as it is an HTTP POST with a JSON payload in input.

        private static async Task CreateUserAsync(HttpClient client, string user, string domain)
        {
            using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            {
                var payload = new
                {
                    accountEnabled = true,
                    displayName = user,
                    mailNickname = user,
                    userPrincipalName = $"{user}@{domain}",
                    passwordProfile = new
                    {
                        forceChangePasswordNextSignIn = true,
                        password = "tempPa$$w0rd"
                    }
                };
                var payloadText = JsonConvert.SerializeObject(payload);

                writer.Write(payloadText);
                writer.Flush();
                stream.Flush();
                stream.Position = 0;

                using (var content = new StreamContent(stream))
                {
                    content.Headers.Add("Content-Type", "application/json");

                    var response = await client.PostAsync("https://graph.microsoft.com/v1.0/users/", content);

                    if (!response.IsSuccessStatusCode)
                    {
                        throw new InvalidOperationException(response.ReasonPhrase);
                    }
                }
            }
        }

Calling Code

The calling code looks like this:


        private static async Task Test()
        {
            //var token = await AppAuthenticationAsync();
            var token = await HttpAppAuthenticationAsync();

            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

                var user = "test@LdapVplDemo.onmicrosoft.com";
                var userExist = await DoesUserExistsAsync(client, user);

                Console.WriteLine($"Does user exists?  {userExist}");

                if (userExist)
                {
                    var groups = await GetUserGroupsAsync(client, user);

                    foreach (var g in groups)
                    {
                        Console.WriteLine($"Group:  {g}");
                    }

                    await CreateUserAsync(client, "newuser", "LdapVplDemo.onmicrosoft.com");
                }
            }
        }

Summary

We can see that using the Microsoft Graph API, most if not all LDAP query can easily be converted.

Microsoft Graph API is aligned with OData v3 which makes it a great REST API where filtering queries are standardized.

Authenticating to Azure AD non-interactively

fingerprint-1382652_640I want to use Azure AD as a user directory but I do not want to use its native web authentication mechanism which requires users to go via an Active Directory page to login (which can be branded and customized to look like my own).

I just want to give a user name & password to an authentication API.

The reason is I want to migrate an existing application currently using an LDAP server and want to change the code as little as possible.

You might have other reasons why you want to do that.

Let’s just say that the online literature HEAVILY leans towards using the web workflow.  Even the documentation on native apps recommends that your native app pops the Azure AD web page to authenticate the user.  There are good reasons for that as this way your app never touches user credentials and is therefore more secure and your app more trustworthy.  So in general, I totally agree with those recommendations.

But in my case, my legacy app is touching the user credentials all over the place.  Also this approach is a stepping stone before considering moving to the web workflow.

After a weekend spent scanning the entire web (as a side note I’ve learned there was little Scandinavian men living inside the Earth, which is flat by the way), I finally found Danny Strockis’ article about Authenticating to Azure AD non-interactively using a username & password.

That is it basically.  Except the article is a little quick on setup, so I’m gona elaborate here.

I’m going to give a sample in C# using ADAL, but since at the end of the day, the authentication is one HTTP POST, I’ll also give a more bare bone sample using HTTP post if you don’t want or cannot to integrate with ADAL.  The samples are quite trivial so you should be able to convert them in the language / platform of your choice.

Conceptually

We basically want our users to interact with our application only, punch in their credentials and have the application check with Azure AD if the credentials are good.

image

Here the application is represented as a Web app here but it could also be a native application.

In order to do this in the world of Azure AD is to use two Azure AD apps:

  1. A client app, representing the agent authenticating the user
  2. A service app, representing the actual application the user is authenticating against

I know it looks weird, it makes your brain hurts and is in great part the reason I’m writing this article, because it isn’t straightforward.

image

In the authentication parlance, the client App is the client (so far so good) while the service app is the resource, i.e. the thing the user is trying to access:  the client is accessing the resource on the user’s behalf.

Setting up Azure AD

Yes, there will be some steps to setup Azure AD.

First we need a tenant.  We can use the tenant used by our subscription but typically for those types of scenario we’ll want to have a separate tenant for our end users.  This article shows how to create an Azure AD tenant.

We then need a user to test.  We can create a user like this:

image

where, of course, ldapvpldemo is my Azure AD tenant.

We’ll also need to give that user a “permanent” password, so let’s show the password on creation (or reset it afterwards) then let’s go to an InPrivate browsing window and navigate to https://login.microsoftonline.com/.  We can then login as the user (e.g. test@ldapvpldemo.onmicrosoft.com) with the said password.  We’ll be prompted to change it (e.g. My$uperComplexPassw0rd).

Let’s create the client app.  In App Registrations, let’s add an app with:

image

It would probably work as a Web app / API but a Native App seems more fitting.

We’ll need the Application ID of that application which we can find by looking at the properties of the application.

image

We then need to create the service app:

image

We’ll need the App ID URI of the service:

image

That URI can be changed, either way we need the final value.

We will need to give permission to the client app to access the service app.  For that we need to go back to the client app, go to the Required Permissions menu and add a permission.  From there, in the search box we can just start to write the name of the service app (e.g. MyLegacyService) and it should appear where we can select it.  We then click the Access MyLegacyService box.

Finally, we need to grant the permissions to users.

image

With all that, we’re ready to authenticate.

ADAL

This sample is in C# / .NET but since ADAL is available on multiple platform (e.g. Java), this should be easy to port.

We’ll create a Console Application project.  We need the full .NET Framework as the .NET core version of ADAL doesn’t have the UserPasswordCredential class we’re gona be using.

We need to install the NuGet package Microsoft.IdentityModel.Clients.ActiveDirectory in the project.

        private static async Task AdalAuthenticationAsync()
        {
            //  Constants
            var tenant = "LdapVplDemo.onmicrosoft.com";
            var serviceUri = "https://LdapVplDemo.onmicrosoft.com/d0f883f6-1c32-4a14-a436-0a995a19c39b";
            var clientID = "b9faf13d-9258-4142-9a5a-bb9f2f335c2d";
            var userName = $"test@{tenant}";
            var password = "My$uperComplexPassw0rd1";

            //  Ceremony
            var authority = "https://login.microsoftonline.com/" + tenant;
            var authContext = new AuthenticationContext(authority);
            var credentials = new UserPasswordCredential(userName, password);
            var authResult = await authContext.AcquireTokenAsync(serviceUri, clientID, credentials);
        }

We have to make sure we’ve copied the constants in the constant section.

This should work and authResult should contain a valid access token that we could use as a bearer token in different scenarios.

If we pass a wrong password or wrong user name, we should obtain an error as expected.

HTTP POST

We can use Fiddler or other HTTP sniffing tool to see what ADAL did for us.  It is easy enough to replicate.

        private static async Task HttpAuthenticationAsync()
        {
            //  Constants
            var tenant = "LdapVplDemo.onmicrosoft.com";
            var serviceUri = "https://LdapVplDemo.onmicrosoft.com/d0f883f6-1c32-4a14-a436-0a995a19c39b";
            var clientID = "b9faf13d-9258-4142-9a5a-bb9f2f335c2d";
            var userName = $"test@{tenant}";
            var password = "My$uperComplexPassw0rd";

            using (var webClient = new WebClient())
            {
                var requestParameters = new NameValueCollection();

                requestParameters.Add("resource", serviceUri);
                requestParameters.Add("client_id", clientID);
                requestParameters.Add("grant_type", "password");
                requestParameters.Add("username", userName);
                requestParameters.Add("password", password);
                requestParameters.Add("scope", "openid");

                var url = $"https://login.microsoftonline.com/{tenant}/oauth2/token";
                var responsebytes = await webClient.UploadValuesTaskAsync(url, "POST", requestParameters);
                var responsebody = Encoding.UTF8.GetString(responsebytes);
            }
        }

Basically, we have an HTTP post where all the previous argument are passed in the POST body.

If we pass a wrong password or wrong user name, we should obtain an error as expected.  Interestingly, the HTTP code is 400 (i.e. bad request) instead of some unauthorized variant.

Summary

Authenticating on an Azure AD tenant isn’t the most recommended method as it means your application is handling credentials whereas the preferred method delegate to an Azure AD hosted page the handling of those credential so your application only see an access token.

But for a legacy migration for instance, it makes sense.  Azure AD definitely is more secure than an LDAP server sitting on a VM.

We’ve seen two ways to perform the authentication.  Under the hood they end up being the same.  One is using the ADAL library while the other uses bare bone HTTP POST.

Keep in mind, ADAL does perform token caching.  If you plan to use it in production, you’ll want to configure the cache properly not to get strange behaviours.

Primer on Azure Monitor

pexels-photo-42384[1]

Azure Monitor is the latest evolution of a set of technologies allowing Azure resources monitoring.

I’ve written about going the extra mile to be able to analyze logs in the past.

The thing is that once our stuff is in production with tons of users hitting it, it might very well start behaving in unpredictable ways.  If we do not have a monitoring strategy, we’re going to be blind to problems and only see unrelated symptoms.

Azure Monitor is a great set of tools.  It doesn’t try to be the end all solution.  On the contrary, although it offers analytics out of the box, it let us export the logs wherever we want to go further.

I found the documentation of Azure Monitor (as of November 2016) a tad confusing, so I thought I would give a summary overview here.  Hopefully it will get you started.

Three types of sources

First thing we come across in Azure Monitor’s literature is the three types of sources:  Activity Logs, Diagnostic Logs & Metrics.

There is a bit of confusion between Diagnostic Logs & Metrics, some references hinting towards the fact that metrics are generated by Azure while diagnostics are generated by the resource itself.  That is confusing & beside the point.  Let’s review those sources here.

Activity logs capture all operations performed on Azure resources.  They used to be called Audit Logs & Operational Logs.  Those comes directly from Azure APIs.  Any operations done on an Azure API (except HTTP-GET operations) traces an activity log.  Activity log are in JSON and contain the following information:  action, caller, status & time stamp.  We’ll want to keep track of those to understand changes done in our Azure environments.

Metrics are emitted by most Azure resources.  They are akin to performance counter, something that has a value (e.g. % CPU, IOPS, # messages in a queue, etc.) over time ; hence Azure Monitor, in the portal, allows us to plot those against time.  Metrics typically comes in JSON and tend to be emitted at regular interval (e.g. every minute) ; see this articles for available metrics.  We’ll want to check those to make sure our resources operate within expected bounds.

Diagnostic logs are logs emitted by a resource that provide detailed data about the operation of that particular resource.  That one is specific to the resource in terms of content:  each resource will have different logs.  Format will also vary (e.g. JSON, CSV, etc.), see this article for different schemas.  They also tend to be much more voluminous for an active resource.

That’s it.  That’s all there is to it.  Avoid the confusion and re-read the last three paragraphs.  It’s a time saver.  Promised.

We’ll discuss the export mechanisms & alerts below, but for now, here’s a summary of the capacity (as of November 2016) of each source:

Source Export to Supports Alerts
Activity Logs Storage Account & Event Hub Yes
Metrics Storage Account, Event Hub & Log Analytics Yes
Diagnostics Logs Storage Account, Event Hub & Log Analytics No

Activity Log example

We can see the activity log of our favorite subscription by opening the monitor blade, which should be on the left hand side, in the https://portal.azure.com.

image

If you do not find it there, hit the More Services and search for Monitor.

Selecting the Activity Logs, we should have a search form and some results.

image

ListKeys is a popular one.  Despite being conceptually a read operation, the List Key action, on a storage account, is done through a POST in the Azure REST API, specifically to trigger an audit trail.

We can select one of those ListKeys and, in the tray below, select the JSON format:


{
"relatedEvents": [],
"authorization": {
"action": "Microsoft.Storage/storageAccounts/listKeys/action",
"condition": null,
"role": null,
"scope": "/subscriptions/<MY SUB GUID>/resourceGroups/securitydata/providers/Microsoft.Storage/storageAccounts/a92430canadaeast"
},
"caller": null,
"category": {
"localizedValue": "Administrative",
"value": "Administrative"
},
"claims": {},
"correlationId": "6c619af4-453e-4b24-8a4c-508af47f2b26",
"description": "",
"eventChannels": 2,
"eventDataId": "09d35196-1cae-4eca-903d-6e9b1fc71a78",
"eventName": {
"localizedValue": "End request",
"value": "EndRequest"
},
"eventTimestamp": "2016-11-26T21:07:41.5355248Z",
"httpRequest": {
"clientIpAddress": "104.208.33.166",
"clientRequestId": "ba51469e-9339-4329-b957-de5d3071d719",
"method": "POST",
"uri": null
},

I truncated the JSON here.  Basically, it is an activity event with all the details.

Metrics example

Metrics can be accessed from the “global” Monitor blade or from any Azure resource’s monitor blade.

Here I look at the CPU usage of an Azure Data Warehouse resource (which hasn’t run for months, hence flat lining).

image

Diagnostic Logs example

For diagnostics, let’s create a storage account and activate diagnostics on it.  For this, under the Monitoring section, let’s select Diagnostics, make sure the status is On and then select Blob logs.

image

We’ll notice that all metrics were already selected.  We also noticed that the retention is controlled there, in this case 7 days.

Let’s create a blob container, copy a file into it and try to access it via its URL.  Then let’s wait a few minutes for the diagnostics to be published.

We should see a special $logs container in the storage account.  This container will contain log files, stored by date & time.  For instance for the first file, just taking the first couple of lines:


1.0;2016-11-26T20:48:00.5433672Z;<strong>GetContainerACL</strong>;Success;200;3;3;authenticated;monitorvpl;monitorvpl;blob;"https://monitorvpl.blob.core.windows.net:443/$logs?restype=container&amp;comp=acl";"/monitorvpl/$logs";295a75a6-0001-0021-7b26-48c117000000;0;184.161.153.48:51484;2015-12-11;537;0;217;62;0;;;"&quot;0x8D4163D73154695&quot;";Saturday, 26-Nov-16 20:47:34 GMT;;"Microsoft Azure Storage Explorer, 0.8.5, win32, Azure-Storage/1.2.0 (NODE-VERSION v4.1.1; Windows_NT 10.0.14393)";;"9e78fc90-b419-11e6-a392-8b41713d952c"
1.0;2016-11-26T20:48:01.0383516Z;<strong>GetContainerACL</strong>;Success;200;3;3;authenticated;monitorvpl;monitorvpl;blob;"https://monitorvpl.blob.core.windows.net:443/$logs?restype=container&amp;comp=acl";"/monitorvpl/$logs";06be52d9-0001-0093-7426-483a6d000000;0;184.161.153.48:51488;2015-12-11;537;0;217;62;0;;;"&quot;0x8D4163D73154695&quot;";Saturday, 26-Nov-16 20:47:34 GMT;;"Microsoft Azure Storage Explorer, 0.8.5, win32, Azure-Storage/1.2.0 (NODE-VERSION v4.1.1; Windows_NT 10.0.14393)";;"9e9c6311-b419-11e6-a392-8b41713d952c"
1.0;2016-11-26T20:48:33.4973667Z;<strong>PutBlob</strong>;Success;201;6;6;authenticated;monitorvpl;monitorvpl;blob;"https://monitorvpl.blob.core.windows.net:443/sample/A.txt";"/monitorvpl/sample/A.txt";965cb819-0001-0000-2a26-48ac26000000;0;184.161.153.48:51622;2015-12-11;655;7;258;0;7;"Tj4nPz2/Vt7I1KEM2G8o4A==";"Tj4nPz2/Vt7I1KEM2G8o4A==";"&quot;0x8D4163D961A76BE&quot;";Saturday, 26-Nov-16 20:48:33 GMT;;"Microsoft Azure Storage Explorer, 0.8.5, win32, Azure-Storage/1.2.0 (NODE-VERSION v4.1.1; Windows_NT 10.0.14393)";;"b2006050-b419-11e6-a392-8b41713d952c"

Storage Account diagnostics obviously log in semicolon delimited values (variant of CSV), which isn’t trivial to read the way I pasted it here.  But basically we can see the logs contain details:  each operation done around the blobs are logged with lots of details.

Querying

As seen in the examples, Azure Monitor allows us to query the logs.  This can be done in the portal but also using Azure Monitor REST API, cross platform Command-Line Interface (CLI) commands, PowerShell cmdlets or the .NET SDK.

Export

We can export the sources to a Storage Account and specify a retention period in days.  We can also export them to Azure Event Hubs & Azure Log Analytics.  As specified in the table above, Activity logs can’t be sent to Log Analytics.  Also, Activity logs can be analyzed using Power BI.

There are a few reasons why we would export the logs:

  • Archiving scenario:  Azure Monitor keeps content for 30 days.  If we need more retention, we need to archive it ourselves.  We can do that by exporting the content to a storage account ; this also enables big data scenario where we keep the logs for future data mining.
  • Analytics:  Log Analytics offers more capacity for analyzing content.  It also offers 30 days of retention by default but can be extended to one year.  Basically, this would upgrade us to Log Analytics.
  • Alternatively, we could export the logs to a storage account where they could be ingested by another SIEM (e.g. HP Arcsight).  See this article for details about SIEM integration.
  • Near real time analysis:  Azure Event Hubs allow us to send the content to many different places, but also we could analyze it on the fly using Azure Stream Analytics.

Alerts (Notifications)

Both Activity Logs & Metrics can trigger alerts.  Currently (as of November 2016), only Metrics alert can be set in the portal ; Activity Logs alerts must be set by PowerShell, CLI or REST API.

Alerts are a powerful way to automatically react to our Azure resource behaviors ; when certain conditions are met (e.g. for a metric, when a value exceeds a threshold for a given period of time), the alert can send an email to a specified list of email addresses but also, it can invoke a Web Hook.

Again, the ability to invoke a web hook opens up the platform.  We could, for instance, expose an Azure Automation runbook as a Web Hook ; it therefore means an alert could trigger whatever a runbook is able to do.

Security

There are two RBAC roles around monitoring:  Reader & Contributor.

There are also some security considerations around monitoring:

  • Use a dedicated storage account (or multiple dedicated storage accounts) for monitoring data.  Basically, avoid mixing monitoring and “other” data, so that people do not gain access to monitoring data inadvertently and, vis versa, that people needing access to monitoring data do not gain access to “other” data (e.g. sensitive business data).
  • For the same reasons, use a dedicated namespace with Event Hubs
  • Limit access to monitoring data by using RBAC, e.g. by putting them in a separate resource group
  • Never grant ListKeys permission across a subscription as users could then gain access to reading monitoring data
  • If you need to give access to monitoring data, consider using a SAS token (for either Storage Account or Event Hubs)

Summary

Azure Monitor brings together a suite of tools to monitor our Azure resources.  It is an open platform in the sense it integrates easily with solutions that can complement it.

Securing REST API using Azure Active Directory

Scenario:  you have a web & mobile front-end, both using a REST API as a back-end.  You want to secure that back-end with authentication / authorization.  How do you do that in Azure?

image

There are obviously a bunch of ways to do that.  In this post, I’ll discuss the recommended approach:  using Azure Active Directory.  We’ll build an Hello World solution in .NET implementing it.

This is actually quite well documented in the Azure documentation so in this post I’ll just try to complete the documentation with practical points.

You can read about Azure API apps here and follow a good Getting started tutorial here.  This walks you through building a three tier app, exposes you to the powerful Swagger integration (you can read about Swagger in this post) and the configurations around Cross-Origin Resource Sharing (CORS).

You can then go about and read authentication / authorization of API apps here.

I will not cover API Management in this post but once you expose your API publically, i.e. not just to your own services, it’s a good idea to consider Azure API Management to manage it, if only to throttle usage to guarantee a good quality of service to everyone.

Overview of the solution

So we’re going to use Azure Active Directory (or Azure AD or AAD) as the identity provider for our solution.

image

Now keep in mind there are many variations on this architecture.  There could be a “Web API” within the Web app for AJAX calls.  There could be an Azure Mobile App API (used by the mobile device only), itself using the API app.  Many other variations.

Here we’ll focus on the architecture pictured in the diagram above.

Notice that the API app is accessed by two classes of identities:

  • Service Principal:  the Web app accesses the API as itself, not as the end-user
  • End-User Principal:  the mobile app accesses the API as the end-user

This creates an asymmetry within the API app.  For instance, authorization might be a bit funky since the API would trust the service principal to implement authorization rules on its end while it would need to implement it for the end-user.

This is one of the reason why some people might put another API between the mobile app & the back-end API.

In this post, I’ll focus on a Service Principal accessing an API app.

If you are unfamiliar with AAD applications, have a look at Azure Active Directory Application and if you’re unfamiliar with AAD Service Principals, read Using Azure Active Directory Service Principal.

Let’s build it!

Ok, let’s go and create a solution.  Let’s call it ApiAuthDemo.

Under that solution, let’s create a ASP.NET application.  I’m using VS 2015 so it might look a little different on other versions of the project.  I choose the ASP.NET Web Application template under the Cloud template folder.

image

I call the project AboutMeApi.  I then choose Azure API App sub-template.

image

I then create a straight Console App.  This will be the client accessing the API for the demo.

image

I call it AboutMeConsole.

So in the end, you should have the following structure in Visual Studio:

image

About Me API

Let’s flesh out the API.  And when I say flesh out, I mean let’s change 500 bytes of code.  This is a demo after all!

Under Models folder, create a class PersonaModel with the following code:


namespace AboutMeApi.Models
{
    public class PersonaModel
    {
        public string Description { get; internal set; }
        public string Name { get; set; }
        public string[] Claims { get; internal set; }
    }
}

Under the Controllers folder rename ValuesController by PersonaController.  This should hopefully rename the underlying class.  Let’s keep the following code:

using AboutMeApi.Models;
using System.Linq;
using System.Security.Claims;
using System.Web.Http;

namespace AboutMeApi.Controllers
{
    public class PersonaController : ApiController
    {
        // GET api/values
        public PersonaModel Get()
        {
            var identity = (ClaimsIdentity)User.Identity;
            var claims = from i in identity.Claims
                         select i.Type + " | " + i.Value;

            return new PersonaModel
            {
                Description = "Description of the invoking user",
                Name = identity.Name,
                Claims = claims.ToArray()
            };
        }
    }
}

As you can see, what this API does is take the current user information and return it to the caller.

Then under App_Start folder, in SwaggerConfig, uncomment the following:

// ***** Uncomment the following to enable the swagger UI *****
})
.EnableSwaggerUi(c =&gt;
{

Now we can start the web app to check out our API.  Start it with F5.  You should land on the root of your web site and get a Forbidden 403 error.  That’s because there is no content in the web site, it’s an API.

Go to the Swagger path:  http://localhost:18008/swagger/.  Actually, my web app is installed on port 18008, yours will be different as it is randomly assigned.

This gives you the beautiful Swagger UI.  You see the Persona API, expend it.  You’ll see the GET operation ; click it.  Then Try it out.  No parameters are required and you should have the following in return payload:

{ "Description": "Description of the invoking user", "Name": "", "Claims": [] }

That is because you aren’t authenticated so the current user is empty.  No problem, we’ll get there.

Configuring Service Principal in AAD

Before we build the client test console, we’ll need to be able to authenticate.

For that, we’ll create a Service Principal in AAD.  This will be the identity of the service calling our API ; in our case, the Console Application.

As explained in Azure Active Directory Application, an AAD application is a Service Principal which is the equivalent of a “Service User” in on premise AD, except it is a first class citizen.

Here I will refer you to the excellent article of Tom FitzMacken:  Create Active Directory application and service principal using portal to create your Service Principal in your AAD with the following properties:

Name Value
Name AboutMeConsoleClient
Sign-on URL https://console.Aboutme.com
App ID URI https://console.Aboutme.com

You’ll need to create a key and remember its value.  You should also copy the client ID of your Service principal.

Create API Application in AAD

This step could be done automatically when deploying your API app in Azure, but I like to see what’s going under the cover…  a little.

So let’s create another app with the following properties:

Name Value
Name AboutMeApi
Sign-on URL https://api.Aboutme.com
App ID URI https://api.Aboutme.com

We will change some of those properties when we deploy the API to Azure but it’s ok for now.

You do not need to create a key for that application as we will not login to AAD with it but use it only as an application for our Service Principal to log against.  You need to capture the client-ID of the app though.

Console App

Now we can build our console app.

First, let’s add a REST API client of the API we just created in the Console app.

Right-click on the Console project, select Add, follow the sub-menu to REST API Client…

You should see the following dialog.

image

Since Swagger defines the meta data of your API, it is possible to construct a client for it from that meta data.  This is what this tool does.

Select an existing swagger metadata file & click Browse.  Now you need to tell the system where the swagger file is.  If you go back to the Swagger web page, at the top of the screen you’ll see

image

So http://localhost:18008/swagger/docs/v1 is where your swagger metadata file is.  Again, the port number will likely be different on your PC.

Change the namespace for AboutMeConsole.AboutMeApi before hitting OK.

Now you can go in the Program file and paste the following code:

using AboutMeConsole.AboutMeApi;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace AboutMeConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            DoJobAsync().Wait();
        }

        private async static Task DoJobAsync()
        {
            var authenticationResult = await AuthenticateAsync();
            var client = new AboutMeApiClient
            {
            };

            client.HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
                "Bearer",
                authenticationResult.AccessToken);

            var persona = await client.Persona.GetAsync();
        }

        private async static Task<AuthenticationResult> AuthenticateAsync()
        {
            var authority = "https://login.microsoftonline.com/<your AAD name here>.onmicrosoft.com";
            //  Invoked App ID
            var resource = "<The client ID of AboutMeApi app>";
            var clientID = "<The client ID of AboutMeConsoleClient app>";
            var clientSecret = "<The secret key of AboutMeConsoleClient app>";
            var clientCredential = new ClientCredential(clientID, clientSecret);
            var context = new AuthenticationContext(authority, false);
            var authenticationResult = await context.AcquireTokenAsync(
                resource,
                clientCredential);

            return authenticationResult;
        }
    }
}

You should have a few classes your system doesn’t recognize.  You need to import the NuGet package Microsoft.IdentityModel.Clients.ActiveDirectory to get those classes.

You can then go to the AuthenticateAsync method and replace the placeholder, e.g. <your AAD name here>, by the values you’ve collected.

Now let me explain a bit what the code does here.

First the style:  async.  This is a console app, so async is pretty useless since the main thread is always running, but I like to get everyone in the habit of using await / async for all their code.  So in the main, I do a call to an async method (DoJobAsync) and I wait (block) on it.  This is the only non-async code.  The rest you could copy paste in service code.

So, in DoJobAsync we first fetch a token from AAD, then we create an API client.  On that client we add the access token in the request headers.

image

We have the flow described above where the console app goes to AAD, authenticates itself as the console app, in the context of the API app (remember, authentication in AAD always is in the context of a target app).  It receives a bearer token that it passes to the API when invoking it.

Now if you try the console app, you’ll see that the persona object returned by the API is basically empty.  Why is that?

That’s because there is no code in the API app to crack open the token and find the identity of the caller.  We could add ADAL code there and that might be a sensible thing to do in a development environment, but I won’t cover this in this post.

Instead, I’ll leverage the authentication / authorization feature of Azure App Service.

Deploying the API in Azure

Let’s publish the API in Azure.  Put it under your favorite App Service Plan & Resource Group.

Try to call the API App name itself AboutMeApi.  But since it needs to be globally unique (being mapped to a DNS), you’ll likely need to append some numbers at the end.  I called mine AboutMeApi2016.

You can then go in the API app in the portal and select the Authentication / Authorization feature.

image

This feature is pretty handy.  It basically runs the authentication code outside of your app.  A gateway, in front of your app, intercept the bearer token cracks it open, does the cryptography to check out everything is valid and reemit http-headers your app can readily consume.  Isn’t that fantastic?  If not, what is, I’m asking you.

I definitely suggest you read the documentation around service authentication to understand the different options you have.

For us, let’s just switch the authentication to ON, leave the default to “Log in with Azure Active Directory”, then configure the AAD.  For that, select the Express Management mode and then select your app.  If you’re like me and have multiple AAD in your subscription and the AAD you’re using isn’t the default one, select Advanced.

In client ID, paste the client ID of the API app we created earlier.  In Issuer URL, you need to paste https://sts.windows.net/ and append the tenant id of your AAD.  To find that out, go to your AAD configuration, select “View Endpoints”

image

Then you should see the ID where I’ve put the orange box.

image

You can save your API App configuration in the portal.

Console App pointing to Azure App

Now let’s go back to our Console app and change the following code in DoJobAsync:

            var client = new AboutMeApiClient
            {
                BaseUri = new Uri("https://aboutmeapi2016.azurewebsites.net")
            };

Of course, you need to put your own unique URL there but…  and I can’t stress that enough, you need to put HTTPS in your url there.  If you don’t, the authorization feature is going to give you an unauthorized and if you’re lucky like me, you’ll need 3 hours to find out why.  Hint:  it is the letter ‘s’ missing at the end of ‘http’

Now, let’s run the console app.  You’ll see the persona object gets filled with information, including the list of claims given by AAD.

An interesting fact is that your Service Principal doesn’t have a name and this is why the name property is still blank.  Your application is identified by an app-id.

Token Cache

I went extremely quickly through the code but an interesting fact is that the object AuthenticationContext contains a property TokenCache which is a global cache in your app-domain.  This means that the next time you call it for an authentication, it won’t go to AAD to fetch a token.

This is gold for performance and scalability of course.

It is clever enough to figure out when the cached token are expiring and will then go again to AAD.

Conclusion

Ok, this wasn’t trivial I know.  Lots of GUIDs and configuration right-left & center.

But the important items are:

  • You can access an API App using a Service Principal ; this is what you’ll typically do for an API accessed as a “back-end” from another service
  • You can have different Service Principal accessing the same API and you could give different authorization to different ones ; authorization would be done in the code, either declaratively (Authorize attribute) or imperatively
  • Azure App Service can take care of the Authentication / Authorization for you

An issue you’ll have in your dev setup, i.e. your own PC while you develop your solution, is that you won’t have the App Service Authentication gateway in front of your service.

You could fix that in different ways.  You could ignore the authentication in dev, knowing it’s taken care of in production.  A bit risky, but you know you could have a flag making sure it’s there in production.  You could put ADAL code in your app and take care of the authentication yourself.  Or you could have a gateway in dev that essentially does the same thing than the one in Azure.  You simply don’t deploy it when you go to Azure.

Multi-Tenant SaaS with Azure Active Directory B2B & B2C

Scenario:  I’m creating a Software as a Service (SaaS).  I’m having multiple customers & I want to manage their identity.  For some of my customers the users won’t have corporate identity ; I would like to offer them to login using their social identity (e.g. Facebook) if they want to or create an account on my site otherwise.  For other customers, they’ll come in with a corporate AAD (likely synchronized with on premise AD) and I would like to integrate with that.  How do I do that in Azure?

Azure Active Directory (AAD) is an Identity & Access Management (IAM) service in Azure.

AAD can be used in multiple numbers of ways.  You can use it as a simple identity store where you store user accounts with a given password.  You can then use it to authenticate those users against a web site or a web API.  You can have it synchronize with an on premise Active Directory, using Azure Active Directory Connect.  You can enable multi-factor authentication with it.  You can use it as an identity provider for third party SaaS applications (e.g. SalesForce.com), enabling SSO.  You can also use it for on premise web applications, projecting them in the cloud, with Application Proxy.  You can enable conditional access on those application proxies.

Lots of ways to use it.

Two new ways to use it, still in preview, are AAD B2C & AAD B2B.  Both services are in preview at this time (mid-March 2016).

Business 2 Consumer

AAD B2C allows AAD to integrate with social networks:

This means your AAD won’t be authenticating the users, those social networks will.  But, AAD will still be logging in the users.  This means your application integrates with only one identity provider, which in turns integrates with many.  It therefore federates identities from different sources.

image

You stay in control of the entire onboarding, login & other User Experience (UX) integration with social network by customizing those UX.

AAD B2C still allows you to create “local users”, i.e. users existing solely in your AAD tenant.  This supports the scenario of “falling back” to creating accounts for your site only.  Those users can have access to a self-service password reset.

On top of that AAD B2C allows you to customize the user schema, i.e. adding custom attributes on top of the standard ones (e.g. Given Name, Surname, City, etc.).

Since user accounts are imported in your tenant, you can put different users coming from different social networks within AAD groups, to manage application roles for instance.

You can see an introduction video here, see the pricing here (based on number of users & number of authentications).  You should also consult the up-to-date list of known limitations here.

AAD B2C is actually a special type of AAD.  You have to decide at creation if you want an AAD B2C or not.

image

Business 2 Business

AAD B2B allows you to bring identities from other AADs into your tenant and give them access to your applications.

This feature is free.

Currently (mid March 2016), the only to import user accounts is by using CSV files.  This is done via the “Add User” window:  simply select Users in partner companies in the as the type of user.

image

You need to supply a CSV file with a given format, i.e. with the following column names:

  • Email
  • DisplayName
  • InviteAppID
  • InviteReplyUrl
  • InviteAppResources
  • InviteGroupResources
  • InviteContactUsUrl

The way it works is that the email you give is basically the key to find the user in the right tenant.  For instance, vince@contoso.com will use contoso.com as identity provider.  The user is then imported in your directory and its attributes are copied into it.  The only thing that remains in the foreign AAD is the authentication.

Only non-Microsoft accounts are accepted in those.

Optionally you can specify the “InviteAppID” column.  This will add the user in the given App within your tenant.

image

One of the advantage of importing the user account within your tenant is that you can assign it to groups within your tenant.

There is excellent documentation on this feature.  You can find a detailed walkthrough and learn about the up-to-date current limitations.

Multi tenant SaaS strategy

The strategy I’m giving here leverages Azure Active Directory and isolates each of the SaaS tenant in a different tenant.

You could use one AAD tenant and throw the user accounts of all your tenants in it ; you would then solely use applications within your AAD to segregate between your SaaS tenants.  Although this would work, it would be much harder to manage users this way.

Having separate AAD segregates your SaaS tenants more strongly.  For instance, you could wipeout an entire SaaS tenant by deleting the corresponding AAD.

Here is how it could look like.

image

Cust-X & Cust-Y are the same scenario:  the customers do not have a corporate AAD, hence you rely on AAD B2C to store and federate identities.  You can then use AAD groups within the AAD B2C to control user membership and implement some application roles.

Cust-Z is a scenario where the customer do have a corporate AAD and you leverage AAD B2B to import the users that will use your application.  The Cust-Z AAD tenant becomes a proxy for the corporate AAD.

A variant on this scenario is with Cust-W, where there is no proxy AAD and the AAD application used to authenticate your application’s users is within the corporate AAD of your customer.

So when would you choose Cust-Z over Cust-W scenario?

Cust-Z allows the owner of the application (you) to create groups within the AAD proxy and include different users into it.  With Cust-W you can’t do that since you do not control the AAD.  The advantage of Cust-W scenario is that your customer can more easily control which users should access your application since that one lives within his / her AAD.

Conclusion

So there you have it, a strategy to manage identities within a multi tenant SaaS solution.

As usual with architecture, there are more than one possible ways to solve the problem, so your mileage will vary as you’ll perform different compromises.

Nevertheless, the combination of AAD B2C & AAD B2B adds a lot of flexibility on how AAD can manage external identities.

Azure Active Directory Application

This is a quick post to talk about what an Application is for Azure Active Directory (or Azure AD or AAD).

If you come from the on premise world and are used to Active Directory on Windows Server, the concept of an application within Active Directory probably is a bit foreign.

Think about how authentication works in the cloud and how it would be without the concept of application.

image

The flow would be that (1) the user authenticates against the identity provider (AAD) and receives an authentication token related only to the user, not the application and (2) the user presents the token to the app.

So that would work.  Except that if the application is an application you don’t fully thrust, for instance a SaaS third party, nothing would stop that app to (3) pass your token to another application, an Enterprise application with sensitive information for instance, and impersonate you.

Clearly, that wouldn’t mean security in the cloud!

Here comes the Application

An AAD application fulfills the concept of Relying Party in the claims based model and serves many purposes.

It limits the context of an authentication to one application.  It forbids the scenario we just talked about since the token is application-specific.

It specializes the authentication.  It allows AAD to emit a different set of claims per application.  AAD standard doesn’t support that yet, but AAD B2C does.

It makes application (or services) a first class citizen.  An application isn’t only a relying party which you can, as an end-user, authenticate against ; it is also a Service Principal that can authenticate itself.  In AD on premise, this is usually done using “Service Account”.  AAD made that concept a first class citizen.  You can read Using Azure Active Directory Service Principal to learn more.

With this concept, the authentication flow is augmented as follow.

image

Now the user authenticates (1) in the context of a specific application (App X).  It presents the token (2) to App X.  If App X tries to use the token on App Y (3), it gets an unauthorized access since the token isn’t signed for App Y.

So this is what application do in AAD!

 

PS:  When I say “the user presents the token”, this is typically done by the browser itself via an HTTP-post on the application.