Alternative to Azure AD Premium’s Azure AD Privileged Identity Management (PIM)

Hi,

Azure AD Priviledged Identity Management aka PIM is a great set of features to control who can access what in an organization but this is part of Azure Active Directory Premium P2, which costs about 7 euros/month/user at the time of writing.

In a nutshell, PIM helps you setting up an on-demand higher privilege request. While this is from far the recommended way to control users with higher privileges, if you can’t make it for licensing reasons, there are other ways to achieve similar results. So, here is an alternative that works with every plan but requires a little bit of effort. As I did it as a kind of POC, this is of course much lighter than PIM but draws the basics of the underlying architecture you’d have to setup in order to control Global Admin access, just to take a very sensitive role.

So, here are the steps required to reach this objective (controlling access to Global Admin role):

  • Create an MFA AzureAD app, with user access enabled
  • Create a native App that will be used to leverage the Password Credentials Flow
  • Create a web app protected by that Azure AD App, this Web App hosts the request form
  • In the web app, use the OAuth2’s Password Credentials Flow with a service account to leverage the Graph API and promote the connected user as a Global Admin. This operation cannot be done “as an app” as you’d receive the following exception Insufficient privileges to complete the operation. Therefore, a Service Account that is Global Admin has to be used.
  • Log the demand either in the database, either in a queue for tracking purposes but also in order to remove the temporary permission after a certain duration
  • Develop a Web Job that removes the temporary access
  • Optionally, use the Office 365 Management API and try to filter the actions of this user while he was Global Admin.

I will cover steps 1, 2, 3 and 4 as they are the most complex ones. The tracking system is secondary and I’m not going to elaborate nor will I explain how to make a Web Job. I think that the AAD bits represent the important part of this scenario.

Create an MFA AzureAD app with user access enabled

Using the old portal (read this to see why it might be wiser today to use the old portal), select the target AAD and proceed to the following steps:

  • Add an App, give it the name you want. As Sign-on URL, use the url of the webapp you’ll create in step 3. Say https://globaladminrequest.azurewebsites.net/. This will define the same URL as redirect URL.
  • Enable MFA for all users and User Assignment (two switches in the Configure tab)
  • Go to the Users tab of this app and assign either groups, either users. It’s of course always better to work with groups.

The MFA setting will ensure that the user who requests the Global Admin role is indeed well the person he pretends to be. MFA will enforce to login with user/password but also to provide additional login information such as a 6 digits code sent to the user’s mobile phone.

The User Assignment will restrict the access to this Web App only to users who are part of the groups you have assigned. Therefore, they are somehow similar to the Eligible Users PIM provides.

Create a native AzureAD app for the Password Credentials flow

As stated earlier, with the Azure AD Graph API, it is not possible to promote users as Global Admins even if you grant all the permissions to the App. Therefore, it is required to consume the resource as a user who has already the Global Admin role. In order to do so, you can create a native App that will be used in our Azure Web App. So, our Azure Web App will be protected by our MFA Azure AD App to make sure that only allowed users may access the web site but the promotion itself will be performed thanks to the native App. Here are the steps to create the native App:

  • Add an App, give it the name you want. Sign-on URL as well as Redirect URLs are not important as the Password Credentials Flow doesn’t use them.
  • Grant this App all the Delegate Permissions over the Azure Active Directory

Create the Azure Web App

  • In Visual Studio, create a new project of type ASP.NET Web Application. Choose either MVC, either Web Forms. As it doesn’t matter for this demonstration, I’ve taken the Web Forms one. Make sure to enable Organizational Authentication so that the boiler plate code will be present when the project is created.
  • Make sure to replace ida:ClientId in the web.config with the ID of your MFA App. Note that if you deploy everything with VS, it will create the App for your in AzureAD but then, you’ll have to configure the App as discussed earlier (MFA, User Access…).
  • When you’ll deploy this Web App, make sure to click on the cancel button when you see the popup Enabling Organizational Authentication as this would create a new AD App unnecessarily (provided you followed the previous steps). Again, here if you know what you’re doing, chose your prefered method. I personally don’t like to let Visual Studio push things for me in Azure AD.

The default plumbing will be enough to protect the default page. The below piece of code will only promote the currently logged in user to Global Admin role. I leave the rest to your imagination.

protected void Page_Load(object sender, EventArgs e)
{
    AssignRole(ClaimsPrincipal.Current.Identity.Name).Wait();
}

public Task AssignRole(string identity)
{
    return Task.Run(async () =>
    {
        ActiveDirectoryClient ac = new ActiveDirectoryClient(
        new Uri("https://graph.windows.net/{tenantid}"), async () =>
        {
            UserPasswordCredential uc = new UserPasswordCredential("{user}", "{password}");
            AuthenticationContext ctx =
             new AuthenticationContext("https://login.windows.net/{tenant}");
            AuthenticationResult res = await ctx.AcquireTokenAsync("https://graph.windows.net/", "{nativeappid}", uc);
            return res.AccessToken;
        });

            DirectoryRole TargetRole = null;
            IDirectoryRole role = ac.DirectoryRoles.Where(r => r.ObjectId.Equals("9a693df2-8ae7-4b35-bf57-5623a2787486")).ExecuteSingleAsync().Result;
            if (role != null)
                TargetRole = role as DirectoryRole;

            if (TargetRole != null)
            {
                IUser u = ac.Users.Where(uu => uu.UserPrincipalName.Equals(identity)).ExecuteSingleAsync().Result;
                TargetRole.Members.Add(u as User);
                TargetRole.UpdateAsync().Wait();
            }
   });
}
 

The above code requires some NuGet packages :

<package id="Microsoft.Azure.ActiveDirectory.GraphClient" version="2.1.1" targetFramework="net452" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.5" targetFramework="net452" />

Of course, when assigning the role to the user, you can log that to a database or a Storage Queue and have the Web Job checking either of these every 5 minutes and revoke the permission of the promoted user, based on the time it was promoted.

This alone is of course not as sophisticated as PIM. Again, PIM is clearly the best choice but as you can see here, with a very low amount of efforts, it is possible to easily grant the Global Admin role (could be other roles of course) to some key people of your organization.

Happy Coding!

Advertisements

About Stephane Eyskens

Office 365, Azure PaaS and SharePoint platform expert
This entry was posted in Azure Active Directory and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s