AzureAD Conditional Access ‘Block All except’ selected Apps and MyApps

Azure AD conditional access policies are a key part of O365 security. A common requirement is to be able to apply a policy to all applications, with exceptions for a few selected allocations. The most common use case is as a ‘block’ rule, with the exceptions used to whitelist applications. While you can do this already, by using ‘All’ in the list of applications the policy applies to, this has the side effect of blocking the MyApps portal. Microsoft have recently added MyApps as an application that can be added to CA policies, but it currently (June 2021) doesn’t work. This link is to the Microsoft feedback site where people are asking for this to be fixed :

https://feedback.azure.com/forums/169401-azure-active-directory/suggestions/19738183-support-conditional-access-for-myapps-microsoft-co

The only way to create a policy is to add all of the applications that should be blocked to the ‘includeApplications’ list of the policy manually. This quickly gets impossible to managed in a tenant with many applications. It also means that where there are several different policies, with exceptions for different groups or conditions, they must all be updated manually when a new Enterprise Application is added to the tenant.

This workaround uses Powershell to make calls to the Microsoft Graph REST API to maintain the list of applications in the CA Policies.

WARNING: It is possible to create a CA Policy that blocks ALL access to a Tenant, including Global Administrators. As this code manipulates CA policies it should be used with caution!

Setup

There are a few things that you need to setup in your AzureAD to get this to work:

  • Create an Application Registration, used to assign permissions for the Powershell script to access the Graph REST API
  • Note the Application ID
  • Create a Client secret and make a note of it. (AzureAD only displays this at creation)
  • Assign the following Application API Permissions, in the Graph section:
    • Application.Read.All
    • Policy.Read.All
    • Policy.ReadWrite.ConditionalAccess
  • Create an Enterprise Application. The name doesn’t actually matter, but I used ‘AAAL – Automated All Apps List’. Make a note of the Application ID
  • Create a Conditional Access policy for testing. I’d suggest creating it in Report only mode. Add the AAAL application to the Included applications and one or two applications to ‘Exclude’.
  • Edit the script and update the App Id (for the app registration), Client secret and the AAAL Application ID.

##############################################################################
# Variables
##############################################################################

$AppId = '< Application ID from Azure AD App Registration>'
$AppSecret = '< Application ID from Azure AD App Registration>'

# App ID of AAAL Enterprise App
$AAALiD = "< Application ID of AAAL Enterprise Application"

# Add System.Web for urlencode
Add-Type -AssemblyName System.Web

##############################################################################
# Garph REST API Token
##############################################################################
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
$Scope = "https://graph.microsoft.com/.default"

# Create body
$Body = @{
    client_id = $AppId
	client_secret = $AppSecret
	scope = $Scope
	grant_type = 'client_credentials'
}

# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
    ContentType = 'application/x-www-form-urlencoded'
    Method = 'POST'
    Body = $Body
    Uri = $Url
}

# Request the token
$Request = Invoke-RestMethod @PostSplat

# Create header
$Header = @{
    Authorization = "$($Request.token_type) $($Request.access_token)"
}

##########################################################################
# Applications
##########################################################################
# Fetch all Applications from AAD
$Uri = "https://graph.microsoft.com/v1.0/applications"
$Applications = $null
$Applications = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"

##########################################################################
# CA Policies
##########################################################################
# Fetch Guest CA Policies
$Uri = "https://graph.microsoft.com/V1.0/identity/conditionalAccess/policies"
$CAPolicies = $null
$CAPolicies = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"
foreach($CAPolicy in $CAPolicies.value){
# Search for AAAL and Expand
$Include = $null
$Include = $CAPolicy.conditions.applications.includeApplications
if($Include -contains $AAALiD){
    $Exclude = $null
    $Exclude = $CAPolicy.conditions.applications.excludeApplications
    # Comment out the following line Add to exiting list, Uncomment to replace
    # e.g. if you want O365 Apps in the list as well as Ent Aps 
    $Include = @($AAALiD)
    foreach($Application in $Applications.value){
        if($Exclude -notcontains $Application.appId){
            # Add if not on the include list already
            if($Include -notcontains $Application.appId){
                  $Include += $Application.appId
                  }
            }
        }
    write-output "Updating Policy " $CApolicy.displayName
    #Patch the CA Policy
    $Uri = "https://graph.microsoft.com/V1.0/identity/conditionalAccess/policies/" + $CAPolicy.id 
    $RequestBody = @{
                    conditions =@{
                                applications =@{
                                              includeApplications = @( $Include )
                                               }
                                 }
                    }                
    $RequestBodyJSON = $RequestBody | ConvertTo-Json -Depth 3 
    $PatchedPolicy = Invoke-RestMethod -Method Patch -Headers $Header -Uri $Uri -Body $RequestBodyJSON -ContentType "application/json"
    }
}

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: