Breach Defence Automation: Creating Your Hybrid Account Kill Switch with Microsoft Sentinel and Logic Apps

In cybersecurity, response time is everything. When a suspicious user account is detected, every second counts. Today, I'm sharing a comprehensive security automation tool I've built using Logic Apps to respond to Microsoft Sentinel incidents by automatically disabling compromised accounts across both Entra ID and on-premises Active Directory environments.

This solution was inspired by Peter Klapwijk’s excellent blog post on revoking user access in emergency situations. While his approach uses a SharePoint list and manual action for initiation, this Logic App takes it a step further by leveraging Microsoft Sentinel to automatically trigger the workflow based on security incidents. This provides a fully automated, end-to-end response that aligns with modern threat detection and response strategies.

By leveraging Sentinel’s automation rules, the workflow is triggered automatically in response to security incidents—eliminating the need for manual intervention. This creates a fully automated, end-to-end response system that enables security teams to react instantly to potential compromises, even during off-hours or when they’re away from their desks.

The Challenge: Rapid Response Across Hybrid Environments

For organisations with hybrid identity environments, responding to security incidents often means juggling multiple systems. When a user account is compromised, security teams need to:

  1. Disable the account in Entra ID (formerly Azure AD)
  2. Disable the corresponding account in on-premises Active Directory
  3. Remove authentication methods to prevent continued access
  4. Document the actions taken

Doing this manually takes valuable time, especially during critical security incidents.

The Solution: Automated Account Lockdown

This Logic App workflow seamlessly bridges the cloud-on-premises divide by leveraging Microsoft's provisioning API to ensure compromised accounts are disabled everywhere they exist.

Screenshot of the Logic App designer showing the overall workflow

Create a Logic App with System Assigned Managed Identity

First, we need to create a Logic App with a System Assigned Managed Identity that will have permissions to read Entra ID groups and manage Sentinel watchlists.

  1. Navigate to Sentinel portal and create a new Logic App with an Incident trigger
  2. Once created, go to Identity under Settings
  3. Switch the Status to On under the System assigned tab
  4. Click Save to create the managed identity

Enable Logic App System Assigned Managed Identity

After enabling the System Assigned Managed Identity, you'll see that your Logic App now has an Object (principal) ID.

Now we need to grant the managed identity the necessary permissions to work with Microsoft Sentinel.

Assign roles directly from the Logic App

  1. In your Logic App's Identity page, click on Azure role assignments
  2. Click Add role assignment
  3. Configure the role assignment:
    • Scope: Resource group
    • Subscription: Select your subscription
    • Resource group: Select the resource group containing your Sentinel workspace
    • Role: Microsoft Sentinel Responder
  4. Click Save

How It Works: Step-by-Step

1. Incident Detection

Everything begins when Microsoft Sentinel creates a new incident involving a user account.

Microsoft Sentinel Incident Trigger

2. Extracting User Information

The workflow extracts account information from the Sentinel incident using the "Entities - Get Accounts" action. It then filters for domain-joined accounts that need to be disabled.

Screenshot of the entities extraction and filtering

Step 3: Filtering for Domain-Joined Accounts

After extracting account entities from the Sentinel incident, we need to isolate the domain-joined accounts that require action. This crucial filtering step ensures we only process legitimate corporate accounts.

Screenshot showing the Filter domainJoined action in Logic Apps

The filter works by:

  1. Taking the accounts extracted from the incident
  2. Checking the "IsDomainJoined" property of each account
  3. Only allowing accounts with this property set to "true" to continue through the workflow

This filtering is essential because it ensures we only take action on organisational accounts that are properly joined to your domain, avoiding potential issues with personal or external accounts that might appear in the incident data.

Step 4: Creating the User Principal Name

After filtering for domain-joined accounts, we need to construct the full User Principal Name (UPN) that will be used in our API calls. The UPN is essential for uniquely identifying the user in both Entra ID and on-premises Active Directory.

Screenshot showing the Compose account UPN action in Logic Apps

The Compose action uses this expression:

concat(first(body('Filter_domainJoined')).accountName, '@', first(body('Filter_domainJoined')).upnSuffix)

This expression works by:

  1. Taking the first account from our filtered results
  2. Extracting the account name (username)
  3. Adding the '@' symbol
  4. Appending the UPN suffix (domain name)

The result is a complete UPN like "[email protected]" that uniquely identifies the user in your directory services and can be used in subsequent Graph API calls to retrieve details and perform actions on the account.

Step 5: Setting Up Status Tracking

Before performing any actions on user accounts, we need a way to track the results of our operations. This is where the status variable comes into play.

Screenshot showing the Initialise disableUserStatus action in Logic Apps

In this step, we:

  1. Create a new string variable called "disableUserStatus"
  2. Leave the initial value empty
  3. This variable will be used to track the success or failure of account disabling operations

This status tracking is crucial as it allows us to:

  • Append success or failure messages based on the results of API calls
  • Provide meaningful updates to the Sentinel incident
  • Enable proper error handling and reporting
  • Create a clear audit trail of actions taken

Throughout the workflow, we'll update this variable with "Success" or "Failed" values depending on the outcome of our account disabling operations in both Entra ID and on-premises AD.

Step 6: Retrieving User Details from Microsoft Graph

After constructing the user's UPN, we need to gather comprehensive information about the account to determine how to proceed with the disabling process.

Screenshot showing the HTTP GET User details action in Logic Apps

This crucial step involves making a direct call to the Microsoft Graph API to retrieve the user's key attributes:

  1. Method: We use the GET method to retrieve data.
  2. Authentication: The action uses Managed Identity authentication with:

URI: We construct the endpoint URL with the user's UPN and select specific attributes:

https://graph.microsoft.com/v1.0/users/@{outputs('Compose_account_UPN')}?$select=id,userPrincipalName,displayName,givenName,surname,employeeId,onPremisesSyncEnabled

The most important attribute we're retrieving is onPremisesSyncEnabled, which tells us whether the account is synchronized from on-premises Active Directory. This critical piece of information will determine our branching logic in subsequent steps.

Other attributes like employeeId will be needed if we need to disable the account in on-premises AD, as this is often used as the matching attribute between systems.

Step 7: Determining the Account Type for Disabling

Once we have the user details, we need to determine which path to take for disabling the account based on whether it's synced from on-premises Active Directory or exists only in Entra ID.

Screenshot showing the "Condition disable onPrem or Entra" action in Logic Apps

This conditional branch is the decision point in our workflow:

  1. If True (On-Premises Synced Account):
    • The workflow will execute actions to disable the account in both Entra ID and on-premises AD
    • This requires making API calls to both systems
    • The on-premises disabling uses the provisioning API via SCIM protocol
  2. If False (Cloud-Only Account):
    • The workflow will only disable the account in Entra ID
    • This is a simpler process requiring just one Graph API call

Condition Expression:

@{body('Parse_JSON_GET_User_detail')?['onPremisesSyncEnabled']} is equal to true

This branching logic ensures we take the appropriate action based on where the account is mastered, avoiding unnecessary calls while ensuring comprehensive coverage across your identity infrastructure.

Screenshot of Logic Apps showing the condition that determines the account disabling path

Step 8: Simultaneous Disabling of Accounts in Hybrid Environments

When dealing with accounts that are synced from on-premises Active Directory, it's critical to disable the account in both environments. Our Logic App handles this with parallel processing for maximum efficiency.

Screenshot showing the parallel structure with two HTTP actions - one for Entra ID and one for on-premises AD

Creating the Parallel Branch Structure

As shown in Image, after the workflow determines the account is synced from on-premises, we create two parallel branches:

  1. Left branch: Handles disabling the account in Entra ID
  2. Right branch: Handles disabling the account in on-premises Active Directory

How to create this parallel structure:

  • In the "If true" section of your conditional branch, add multiple actions
  • Logic Apps automatically arranges them in parallel when they don't have dependencies on each other
  • This parallel execution ensures both systems are updated simultaneously

Left Branch: Disabling in Entra ID

The left branch makes a PATCH request to Microsoft Graph API:

Screenshot showing the HTTP PATCH disable user account (Entra ID) action in Logic Apps

This action makes a direct call to the Microsoft Graph API to disable the user account:

URI:

https://graph.microsoft.com/v1.0/users/@{outputs('Compose_account_UPN')}

Method: PATCH

    • This allows us to update specific properties without changing the entire user object.
    • This simple JSON payload sets the account status to disabled.

Body:json

{
  "accountEnabled": false
}

This targets the specific user by their UPN that we constructed earlier.

Authentication:

Right Branch: Disabling in On-Premises AD

Screenshot showing the HTTP POST configuration for disabling an account in on-premises AD

This action leverages the Microsoft Graph API's provisioning capabilities to disable the user account in on-premises Active Directory:

URI:

https://graph.microsoft.com/v1.0/servicePrincipals/{PrincipalId}/synchronization/jobs/{JobId}/bulkUpload

This endpoint connects to your on-premises provisioning service principal and synchronisation job.

At the end of this blog you will configure API-driven inbound provisioning to on-premises AD enterprise application, once this has been configured it will give you an endpoint, you this endpoint in the URL field

Method: POST

    • We're sending an operation to be processed by the on-premises provisioning agent.

Headers:

Content-Type: application/scim+json
  • Specifies we're using the SCIM protocol format for identity management.

Body: json

{
  "schemas": [
    "urn:ietf:params:scim:api:messages:2.0:BulkRequest"
  ],
  "Operations": [
    {
      "method": "POST",
      "bulkId": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee",
      "path": "/Users",
      "data": {
        "schemas": [
          "urn:ietf:params:scim:schemas:core:2.0:User",
          "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
        ],
        "externalId": "@{body('Parse_JSON_GET_User_detail')?['employeeId']}",
        "active": false
      }
    }
  ],
  "failOnErrors": null
}
  • This SCIM-formatted payload identifies the user via employeeId and sets "active" to false.

Authentication:

This parallel approach significantly reduces response time compared to sequential execution and ensures comprehensive coverage across your hybrid identity environment.

Step 9: Checking Disable Operation Results

After attempting to disable the user account in both Entra ID and on-premises AD, we need to verify that these operations completed successfully.

Screenshot showing the "Condition disable user account (on-prem AD)" action in Logic Apps

This condition serves as a critical checkpoint in our workflow:

  1. Status Code References:
    • On-premises operation status: @outputs('HTTP_POST_disable_user_account_(on-prem_AD)')?['statusCode']
    • Entra ID operation status: @outputs('HTTP_PATCH_disable_user_account_(Entra_ID)1')?['statusCode']
  2. Success Criteria:
    • The on-premises AD operation returns status code 200 when successful
    • The Entra ID operation returns status code 204 (No Content) when successful
    • If either operation succeeds, we consider the overall disable action to be successful

Condition Expression: Uses an OR operator to check for successful status codes:

This verification step is crucial because it:

  • Ensures we accurately track the results of our security actions
  • Allows for proper incident documentation
  • Enables additional remediation steps if the disabling operations fail
  • Provides accountability and audit trail for security operations

The OR logic is particularly important because it recognises that even partial success (disabling in one system but not the other) still provides some security benefit during an incident.

Step 10: Tracking Operation Status

After evaluating whether our disable operations succeeded, we need to record the outcome for reporting and documentation purposes.

The workflow uses string variable operations to track the status:

  1. Success Branch: When the account disabling operations succeed (either in Entra ID, on-premises AD, or both), the workflow:
    • Uses the "AppendToStringVariable" action
    • Targets the "disableUserStatus" variable we created earlier
    • Appends the value "Success" to the variable
Screenshot showing the "Append to disable on-prem AD Success" action, which appends "Success" to the disableUserStatus variable

  1. Failure Branch: When both account disabling operations fail, the workflow:
    • Uses a similar "AppendToStringVariable" action
    • Targets the same "disableUserStatus" variable
    • Appends the value "Failed" to the variable
Screenshot showing the "Append to disable on-prem AD Failed" action, which appends "Failed" to the disableUserStatus variable

This status tracking approach has several advantages:

  • Provides clear, consistent status reporting for downstream actions
  • Creates a single variable that summarizes the outcome of multiple operations
  • Enables conditional branching for different notification or remediation paths
  • Supports meaningful incident updates in Microsoft Sentinel

The variable will be used in subsequent steps to update the Sentinel incident with appropriate comments about the actions taken and their results.

Step 11: Handling Cloud-Only Accounts

Our workflow also handles accounts that exist only in Entra ID (not synced from on-premises). This branch executes when our initial condition detects that onPremisesSyncEnabled is false.

Screenshot showing the false branch of the main condition with its own account disabling process for cloud-only accounts

For cloud-only accounts, the process is streamlined compared to hybrid accounts:

  1. Single Disable Operation:
    • Only needs to execute the "HTTP PATCH disable user account (Entra ID)" action
    • Uses the same Graph API endpoint we described earlier
    • Sets "accountEnabled": false in the JSON payload
  2. Status Code Verification:
    • Uses a separate condition to check if the status code equals 204
    • The condition branches to appropriate success/failure variable updates
  3. Status Tracking:
    • Uses the same variable approach to record "Success" or "Failed"
    • Maintains consistent reporting across both branches of the workflow

Reusing Knowledge: If you're implementing this Logic App yourself, you can reuse the same approach we covered in Steps 8-10, with these key differences:

  • You only need the Entra ID PATCH request (no on-premises action)
  • The success condition only checks for status code 204
  • The variable updates should use appropriate messages for cloud-only accounts

This design ensures consistent handling regardless of where the user account is mastered, while optimising the process for cloud-only scenarios by eliminating unnecessary API calls to on-premises systems.

Step 12: Finalising and Documenting the Incident

After all account disabling operations are complete, our workflow performs a final check on the results and updates the Microsoft Sentinel incident with appropriate documentation.

Screenshot showing the final steps of the workflow, including the Compose DisableUserStatus action and a condition that updates the Sentinel incident based on the operation status.

Composing the Final Status

First, the workflow collects all the status information using a Compose action:

  1. Compose DisableUserStatus:
    • Takes the disableUserStatus variable as input
    • This variable now contains either "Success" or "Failed" based on our previous operations
    • This composition makes the status available for the final condition check

Evaluating the Final Status

Next, the workflow uses a condition to determine the appropriate incident update:

This checks if the status contains "Failed" and branches accordingly.

@outputs('Compose_DisableUserStatus')

Updating the Sentinel Incident

Based on the final status, the workflow adds an appropriate comment to the Microsoft Sentinel incident:

  1. Success Path:
    • Executes "Add comment to incident user account disabled"
    • Adds a comment confirming the account was successfully disabled
  2. Failure Path:
    • Executes "Add comment to incident user account disabled failed"
    • Adds a comment noting that the account disabling operation failed
    • This provides clear visibility to security analysts that manual intervention may be required

This final documentation step is crucial because it:

  • Creates a clear audit trail within the incident
  • Informs security analysts of the automated actions taken
  • Ensures proper follow-up for any failed operations
  • Completes the incident response lifecycle for the automated portion

With this comprehensive approach, our Logic App provides end-to-end automation of the account disabling process, from incident detection to final documentation, across both cloud and on-premises environments.

Step 13: Assigning Required Permissions to the Logic App's Managed Identity

For our Logic App to successfully execute all the actions we've configured, its Managed Identity needs appropriate permissions in Microsoft Graph and Entra ID.

Understanding the Permission Requirements

The script handles two types of required permissions:

  1. Microsoft Graph API Permissions:
    • User.ManageIdentities.All - Required for identity management
    • SynchronizationData-User.Upload - Required for on-premises provisioning actions
    • AuditLog.Read.All - Required to access incident details
  2. Entra ID Directory Role:
    • User Administrator - Provides necessary rights to manage user accounts

Running the Script

To use this script:

  1. Save it as AssignLogicAppPermissions.ps1
  2. Update the $miObjectId variable with your Logic App's Managed Identity Object ID
  3. Run the script in PowerShell with administrator privileges
  4. Connect with an account that has Global Administrator or Privileged Role Administrator permissions

The script performs several key tasks:

  • Connects to Microsoft Graph with appropriate scopes
  • Identifies the required app roles from the Microsoft Graph service principal
  • Checks for and assigns any missing permissions
  • Activates the User Administrator role if needed
  • Assigns the role to your Logic App's Managed Identity

Script Highlights

powershell

# Define all permissions to assign
$permissionsToAssign = @(
    "UserAuthenticationMethod.ReadWrite.All",
    "SynchronizationData-User.Upload",
    "AuditLog.Read.All"
)

# Assign Entra ID role
$roleName = "User Administrator"
Update user - Microsoft Graph v1.0
Update the properties of a user object.
Perform bulkUpload - Microsoft Graph v1.0
Perform a new bulkUpload.
Microsoft Graph permissions reference - Microsoft Graph
Microsoft Graph exposes granular permissions that control the access that apps have to resources, like users, groups, and mail. As a developer, you decide which permissions for Microsoft Graph your app requests.

This script makes the permission assignment process much easier and ensures your Logic App has all the permissions it needs to function properly across both cloud and on-premises environments.

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "AppRoleAssignment.ReadWrite.All", "RoleManagement.ReadWrite.Directory"

# Set your managed identity's object ID
$miObjectId = "LogticApp-Identity-ObjectId"

# Microsoft Graph service principal ID
$graphId = "00000003-0000-0000-c000-000000000000"

# Get Microsoft Graph service principal
$graphSP = Get-MgServicePrincipal -Filter "appId eq '$graphId'"

# Define all permissions to assign
$permissionsToAssign = @(
    "User.ManageIdentities.All",
    "SynchronizationData-User.Upload",
    "AuditLog.Read.All"
)

# Get required app roles from Microsoft Graph
$roles = @{}
foreach ($permission in $permissionsToAssign) {
    $roles[$permission] = $graphSP.AppRoles | Where-Object { $_.Value -eq $permission }
    
    # Verify the permission exists
    if ($null -eq $roles[$permission]) {
        Write-Warning "Permission '$permission' not found in Microsoft Graph API"
    }
}

# Create parameter hashtable
$params = @{
    ServicePrincipalId = $miObjectId
    PrincipalId = $miObjectId
    ResourceId = $graphSP.Id
}

# Assign permissions
foreach ($role in $roles.Keys) {
    # Skip if permission was not found
    if ($null -eq $roles[$role]) {
        continue
    }
    
    # Check if the permission is already assigned
    $existingAssignment = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $miObjectId | 
        Where-Object { $_.AppRoleId -eq $roles[$role].Id -and $_.ResourceId -eq $graphSP.Id }
    
    if ($existingAssignment) {
        Write-Host "Permission $role is already assigned" -ForegroundColor Yellow
    }
    else {
        $roleParams = $params.Clone()
        $roleParams.AppRoleId = $roles[$role].Id
        
        try {
            New-MgServicePrincipalAppRoleAssignment @roleParams
            Write-Host "Assigned $role permission" -ForegroundColor Cyan
        }
        catch {
            Write-Host "Failed to assign $role permission: $_" -ForegroundColor Red
        }
    }
}

Write-Host "All Graph permissions assigned!" -ForegroundColor Green

# Entra ID role displayname 
$roleName = "User Administrator"

# Get all directory roles
$directoryRoles = Get-MgDirectoryRole -All

# Find the User Administrator role
$role = $directoryRoles | Where-Object { $_.DisplayName -eq $roleName }

# If the role isn't activated yet, we need to activate it
if (-not $role) {
    # Get all role templates
    $roleTemplates = Get-MgDirectoryRoleTemplate -All
    
    # Find the User Administrator template
    $roleTemplate = $roleTemplates | Where-Object { $_.DisplayName -eq $roleName }
    
    if ($roleTemplate) {
        # Activate the role from the template
        $params = @{
            RoleTemplateId = $roleTemplate.Id
        }
        $role = New-MgDirectoryRole -BodyParameter $params
        Write-Host "Activated the $roleName role" -ForegroundColor Cyan
    }
    else {
        Write-Error "Could not find the $roleName role template."
        exit 1
    }
}

# Check if the role is already assigned to the managed identity
$roleAssignments = Get-MgRoleManagementDirectoryRoleAssignment -Filter "principalId eq '$miObjectId'" -All

$existingRoleAssignment = $roleAssignments | Where-Object { 
    $_.RoleDefinitionId -eq $role.RoleTemplateId -and 
    $_.DirectoryScopeId -eq "/"
}

if ($existingRoleAssignment) {
    Write-Host "The $roleName role is already assigned to the managed identity" -ForegroundColor Yellow
}
else {
    # Now assign the role to the managed identity
    try {
        # Create role assignment
        $params = @{
            DirectoryScopeId = "/"
            RoleDefinitionId = $role.RoleTemplateId
            PrincipalId = $miObjectId
        }
        
        New-MgRoleManagementDirectoryRoleAssignment -BodyParameter $params
        Write-Host "Assigned $roleName role to the managed identity" -ForegroundColor Green
    }
    catch {
        Write-Host "Failed to assign $roleName role: $_" -ForegroundColor Red
    }
}

Setting Up API-Driven Provisioning to On-Premises Active Directory

Before our Logic App can disable user accounts in on-premises Active Directory, we need to configure the API-driven provisioning integration. This creates the bridge between Microsoft Entra ID and your on-premises environment.

Configure API-driven inbound provisioning app - Microsoft Entra ID
Learn how to configure API-driven inbound provisioning app.

Step 1: Create the Enterprise Application

Sign in to the Entra or Azure Portal and navigate to Enterprise Applications

Click New application

Click New application

Search for "API-driven" and select API-driven provisioning to on-premises Active Directory

API-driven provisioning to on-premises Active Directory

Give the application a meaningful name (such as "OnPrem-AD-Provisioning") and click Create

Give the application a meaningful name

Step 2: Configure Provisioning Settings

Open the newly created app and browse to the Provisioning tab

Set Provisioning Mode to Automatic

Download the connector agent that needs to be installed on an on-premises server

Step 3: Install the Provisioning Agent On-Premises

  1. Switch to an on-premises server where you'll install the Microsoft Entra provisioning agent
  2. Run the downloaded agent installer
  3. Select HR-driven provisioning when prompted
  4. Authenticate to Entra ID with an account that has at least the Hybrid Identity Administrator role
  5. Provide domain admin credentials to create the required group managed service account
  6. Wait for the configuration to complete (this may take a few minutes)

Step 4: Complete the Cloud Configuration

  1. Return to the Entra portal and the provisioning tab of your application
  2. Fill in the Default OU for new users path in your Active Directory (this need to to be fully qualified and can be retrieved from ADSI Edit)
  3. Select the domain where you installed the connector
  4. Scroll down to review the Mappings section
  5. Verify that the default mapping is configured to use the employeeID attribute (or change it to match your organisation's requirements)
  6. Click Save to finalise the configuration

Step 5: Start Provisioning and Note the API Endpoint

  1. Navigate to the Overview tab
  2. Click the button to start provisioning
  3. Note the Provisioning API Endpoint URL - this is the crucial piece you'll need for the Logic App

This endpoint URL will be used in the Logic App's HTTP POST action when disabling on-premises accounts covered in Right Branch: Disabling in On-Premises AD. It contains your service principal ID and synchronisation job ID that are needed for the API calls.

Important: Make sure to copy the full Provisioning API Endpoint URL. You'll need to paste it into the URI for the Logic App's HTTP POST request that disables on-premises accounts.
You can also check out how Peter Klapwijk did it—same process, plus his blog is a great read!
Revoke user access in case of an emergency with a single click - on-premises AD integration | Peter Klapwijk - In The Cloud 24-7
The post describes an automated way of revoking user access in case of an emergency for on-premises Active Directory accounts with Azure Logic Apps.

Building Your Account Lockdown Automation: A Journey Complete

We've walked through the complete process of creating a robust security automation solution that bridges cloud and on-premises environments to respond to security incidents automatically. Let's recap what we've accomplished:

Our solution uses Graph API calls to disable accounts in Entra ID and leverages the provisioning API with SCIM protocol to reach into on-premises Active Directory. We also implemented comprehensive status tracking and incident documentation to create a clear audit trail of all automated actions.

This automation dramatically reduces response time from minutes or hours to mere seconds, ensuring consistent execution of security protocols across hybrid environments. By implementing this solution along with an Automation Rule, your security team can focus on complex investigation and remediation activities while knowing that initial containment steps happen automatically when incidents occur.

In an upcoming blog, we'll expand this automation framework to include advanced security measures like session revocation and multi-factor authentication removal, further enhancing the comprehensive account protection capabilities of this powerful security solution.


What security automation challenge would you like to tackle next?

CTA Image

I hope you've found this guide helpful in enhancing your security posture. If you've enjoyed this content and would like to support more like it, please consider joining the Supporters Tier. Your support helps me continue creating practical security automation content for the community.

Supporters Tier Upgrade