Azure Active Directory guest users really simplify the process to collaborate with external users. Although keeping a good governance on guest accounts can become quite a challenge. The two biggest challenges I often observe are: “Who invited that guest user?” and “Does this guest user still need access to our infrastructure?”. Inspired by a recent post of Thomas Kurth regarding Azure AD Guest Account - Governance and Cleanup I also developed a solution which comes quite close to an “Azure AD Access review” like user experience.

Notable features

  • The ‘Manager’ attribute of your guest users get’s automatically populated with the identity of the inviter
  • All Azure AD app registration information is stored in Azure Key Vault
  • Almost zero touch deployment with ARM templates
  • You can integrate existing guest users into this solution by populating the manager attribute in Azure AD
  • You can configure the approval frequency for guest accounts
  • Approval frequency respects last approval date for each guest account

Architecture

Azure AD Guest User Review

The solution leverages function of:

  • Azure Logic App

    • To process the guest user approval
    • Fetches guest users via Microsoft Graph
    • Retrieves information from the Azure Functions
    • Sends approval e-mails to the guest user’s manager
  • Azure AD

    • Manager attribute to referece the inviter of the guest user and account him as responsible for the guest
    • Open type extensions to store metadata of the guest review process
    1
    2
    3
    4
    5
    6
    7
    8
    
    {
        "@odata.type": "#microsoft.graph.openTypeExtension",
        "[email protected]": "#DateTimeOffset",
        "lastReview": "2020-07-11T11:22:23.8382113Z",
        "inviterUpn": "[email protected]",
        "inviterId": null,
        "id": "ch.nicolonsky.tech.guestManagement"
    }
    
  • Azure Key Vault

    • Securely stores app registration details and client secret
    • Grants access to the Function App and Logic Apps Managed identities
  • Azure Functions (comes with app service plan and storage account)

    • PopulateGuestInviterAsManager: Populates the manager and open openTypeExtension data
    • FetchLastSigninAndManager: Retrieves the manager, last sign-in details and lastReview time from the openTypeExtension
    • UpdateGuestManagementMeta: Updates last review date for the openTypeExtension
  • Azure Log Analytics alert rule

    • Triggers Azure Function which populates the inviter of the guest as the guet user’s manager

Prerequisites

In order to deploy this solution you need the following prerequisites:

  • Azure subscription
  • Azure AD Audit & Sign-In Log forwarding to a log analytics workspace
  • Azure AD app registration
    • Required Microsoft Graph permissions: Directory.ReadWrite.All, AuditLog.Read.All (Application Permissions)

Deployment

Ensure that you registered an app registration in Azure AD and consented to the application permissions. I named mine “Azure AD Guest User Review”. You will need the Directory (tenant) ID, Application (client) ID and Client secret for the deployment.

For an easy and automated onboarding this solution ships with ARM templates. The only mandatory input for the deployment are the details for the app registration.

Specify these values as ARM template deployment parameters as secretValue like: {"secretName":"ClientSecret","secretValue":"Paste Azure AD App Registration Detail"}.

The ARM template bundles multiple nested templates. You can have a closer look on them on this project’s GitHub repository.

  • The Azure resources will be named according to the recommended naming and tagging conventions provided by Microsoft

  • For the Function App, Storage Account and Key Vault resources which require an unique name the first part of the resource group id serves as suffix

  • Feel free to change the deployment parameters to reflect your Azure naming convention

Deployment via Azure portal:

Deploy to Azure Visualize

ARM Template Deployment

Deployment via Az PowerShell:

1
2
3
4
5
6
7
# Create new resource group
$rgName = "arg-guestreview-euw-tst-01"
$rgLocation = "West Europe"
New-AzResourceGroup -Name $rgName -Location $rgLocation

# Deploy ARM Template with app registration details in parameters.json file
New-AzResourceGroupDeployment -ResourceGroupName $rgName -TemplateFile "C:\Repos\GitHub\AzureADGuestReview\guestReview.json" -TemplateParameterFile "C:\Repos\GitHub\AzureADGuestReview\guestReview.parameters.json" -Verbose

Post deployment steps

  • Authorize ‘Office 365 Outlook’ API Connection in the Azure Portal with the Account you want to send your notification e-mails: Authorize Office 365 API Connection

  • Add the Azure functions from the PowerShell scripts Add azure function

    • Repeat the steps for all three functions
    • Grab & paste the function URL for the “fetchLastSigninAndManager” & “updateGuestManagementMeta” function in the logic app
  • Create an action group for your log analytics workspace to trigger the Azure Function: ‘PopulateGuestInviterAsManager’

    • Make sure to enable the common alert schema
    • Create Action Group
  • Add a new alert rule to your log analytics workspace which triggers the previously created action group

    • Create Alert Rule
    • Create Alert Rule
    • Choose severity level 4 (which refers to verbose) and not 0 like I did
    • Custom log search query:
    1
    2
    
    AuditLogs
    | where OperationName == 'Invite external user' and Result == 'success'
    

How it works

Populating the manager

  1. As soon as a new guest gets invited to the tenant the alert rule from the log analytics workspace triggers the function to populate the manager

The Logic App

The logic app performs the following steps in sequence:

  1. Fetch the ApplicationID, TenantID and ClientSecret from the Key Vault via Managed identity
  2. Get all guest users from Microsoft Graph API

For every guest user (iteration):

  • Call Azure Function to fetch manager (Azure AD attribute), lastReview (open type extension) and lastSignin (Azure AD sign-in logs)
    { “managerUpn”: “[email protected]”, “userId”: “29b956fe-6c3c-4135-9aa4-85853094d867”, “lastSignIn”: “2020-07-06T19:29:15.4651766Z”, “lastReview”: “2020-07-12T09:45:43.7814187Z”, “inviterId”: null, “inviterUpn”: “[email protected]” }
  • Check time difference between 'current timestamp' - lastReview
  • Check if a manager is assigned
  • If a new review is required send a confirmation mail to the manager Review Email
  • Based on the manager’s selected option:
    • Approve -> Update lastReview timestamp
    • Suspend -> Disable the account via Graph & Update lastReview timestamp
    • Delete -> Delete the account via Graph
  • The review for the specific guest is now completed

Note: The review email is an asynchronous action and the logic app will only change the state to completed if all managers submitted their input. You might want to adjust the default timeout for the approval / logic app runtime.

FAQ

  • What happens if a user doesn’t have a manager assigned

    • No reviews will occur
    • You could easily extend the logic app to gather all guest users without a manager and send a separate mail to the IT department
  • How can I add existing guests to this solution?

    • Simply populate the manager attribute of your guest accounts
    • Here’s a migration script which performs bulk population if you have a log analytics workspace with the Azure AD audit logs
  • What’s the default approval frequency

    • 30 days (adjustable via logic app variable)
  • How often will the managers receive an e-mail if they don’t respond

    • Every day (adjustable via logic app trigger)
  • How are the app registration details and credentials stored

    • They are stored in the Azure Key Vault
    • The access policy grants the managed identity of the function app and logic app access to retrieve the secrets
    • Output is hidden within the logic app to avoid sensitive information in the logic app run history
  • I only want to use the feature to automatically populate the inviter as the manager of the guest

    • You can either adjust the ARM template or deploy the full solution and then delete the Logic App & Office 365 API Connection

Final words

This solution will definitely boost your guest user governance as the inviters can directly manage the lifecycle of the guests. Additionally you can easily identify who’s responsible for a guest account.

Happy guest user reviewing.