Blog Post

Microsoft Defender for Cloud Blog
3 MIN READ

Remove Deprecated User Accounts across multiple Subscriptions

paggarwal's avatar
paggarwal
Icon for Microsoft rankMicrosoft
May 03, 2021

Deprecated accounts are the accounts that were once deployed to a subscription for some trial/pilot initiative or some other purpose and are not required anymore. The user accounts that have been blocked from signing in should be removed from subscriptions. These accounts can be targets for attackers finding ways to access your data without being noticed.
The Azure Security Center recommends identifying those accounts and removing any role assignments on them from the subscription, however, it could be tedious in the case of multiple subscriptions.

 

Pre-Requisite:
 - Az Modules must be installed
 - Service principal created as part of Step 1 must be having owner access to all subscriptions
 
Steps to follow:
Step 1: Create a service principal
Post creation of service principal, please retrieve below values.
  1. Tenant Id
  2. Client Secret
  3. Client Id
Step 2: Create a PowerShell function which will be used in generating authorization token
function Get-apiHeader{
[CmdletBinding()]
Param
(
 [Parameter(Mandatory=$true)]
 [System.String]
 [ValidateNotNullOrEmpty()]
 $TENANTID,
 [Parameter(Mandatory=$true)]
 [System.String]
 [ValidateNotNullOrEmpty()]
 $ClientId,
 [Parameter(Mandatory=$true)]
 [System.String]
 [ValidateNotNullOrEmpty()]
 $PasswordClient,
 [Parameter(Mandatory=$true)]
 [System.String]
 [ValidateNotNullOrEmpty()]
 $resource
)
$tokenresult=Invoke-RestMethod -Uri https://login.microsoftonline.com/$TENANTID/oauth2/token?api-version=1.0 -Method Post -Body @{"grant_type" = "client_credentials"; "resource" = "https://$resource/"; "client_id" = "$ClientId"; "client_secret" = "$PasswordClient" }
$token=$tokenresult.access_token
$Header=@{
  'Authorization'="Bearer $token"
  'Host'="$resource"
  'Content-Type'='application/json'
  }
return $Header
}

 

Step 3: Invoke API to retrieve authorization token using function created in above step
Note: Replace $TenantId, $ClientId and $ClientSecret with value captured in step 1

 

 

$AzureApiheaders = Get-apiHeader -TENANTID $TenantId -ClientId $ClientId -PasswordClient $ClientSecret -resource "management.azure.com"

 

 

 

Step 4: Extracting csv file containing list of all deprecated accounts from Azure Resource Graph

Please referhttps://github.com/MicrosoftDocs/azure-docs/blob/master/articles/governance/resource-graph/first-query-portal.md

Azure Resource graph explorer: https://docs.microsoft.com/en-us/azure/governance/resource-graph/overview

Query:

 

 

securityresources
        | where type == "microsoft.security/assessments"
        | extend source = tostring(properties.resourceDetails.Source)
        | extend resourceId =
            trim(" ", tolower(tostring(case(source =~ "azure", properties.resourceDetails.Id,
            extract("^(.+)/providers/Microsoft.Security/assessments/.+$",1,id)))))
        | extend status = trim(" ", tostring(properties.status.code))
        | extend cause = trim(" ", tostring(properties.status.cause))
        | extend assessmentKey = tostring(name)
        | where assessmentKey == "00c6d40b-e990-6acf-d4f3-471e747a27c4"

 

 

 

 

Click on "Download as CSV" and store at location where removal of deprecated account script is present. Rename the file as "deprecatedaccountextract"

 

 

Set-Location $PSScriptRoot
$RootFolder = Split-Path $MyInvocation.MyCommand.Path
$ParameterCSVPath =$RootFolder + "\deprecatedaccountextract.csv"
if(Test-Path -Path $ParameterCSVPath)                                                                          
{ 
$TableData = Import-Csv $ParameterCSVPath
}

foreach($Data in $TableData)
{
  #Get resourceID for specific resource 
  $resourceid=$Data.resourceId
  #Get control results column for specific resource
  $controlresult=$Data.properties
  $newresult=$controlresult | ConvertFrom-Json
  $ObjectIdList=$newresult.AdditionalData.deprecatedAccountsObjectIdList
  $regex="[^a-zA-Z0-9-]"
  $splitres=$ObjectIdList -split(',')
  $deprecatedObjectIds=$splitres -replace $regex
  foreach($objectId in $deprecatedObjectIds)
  {   
    #API to get role assignment details from Azure
    $resourceURL="https://management.azure.com$($resourceid)/providers/microsoft.authorization/roleassignments?api-version=2015-07-01"
    $resourcedetails=(Invoke-RestMethod  -Uri $resourceURL -Headers $AzureApiheaders -Method GET)
    if( $null -ne $resourcedetails )
    {        
     foreach($value in $resourcedetails.value)
     {
      if($value.properties.principalId -eq $objectId)
      {
       $roleassignmentid=$value.name
       $remidiateURL="https://management.azure.com$($resourceid)/providers/microsoft.authorization/roleassignments/$($roleassignmentid)?api-version=2015-07-01"
       Invoke-RestMethod  -Uri $remidiateURL -Headers $AzureApiheaders -Method DELETE
      }
     }
    }
    else
    {
     Write-Output "There are no Role Assignments in the subscription"
    }             
   }
}

 

 

 

References:

https://github.com/Azure/Azure-Security-Center/blob/master/Remediation%20scripts/Remove%20deprecated%20accounts%20from%20subscriptions/PowerShell/Remove-deprecated-accounts-from-subscriptions.ps1

https://docs.microsoft.com/en-us/azure/security-center/policy-reference#:~:text=Deprecated%20accounts%20are%20accounts%20that%20have%20been%20blocked%20from%20signing%20in.&text=Virtual%20machines%20without%20an%20enabled,Azure%20Security%20Center%20as%20recommendations.

 

 

Updated May 03, 2021
Version 2.0
  • TsholofeloM's avatar
    TsholofeloM
    Copper Contributor

    Hi paggarwal 

    Did anyone ever come across this error when running the script?

     

    Invoke-RestMethod : {"error":{"code":"AuthorizationFailed","message":"The client '' with object id '' does not have authorization to perform action
    'microsoft.authorization/roleassignments/read' over scope '/providers/microsoft.authorization' or the scope is invalid. If access was recently granted, please refresh your credentials."}}

     

    The App registration ClientID has been assigned owner RBAC permission to the subscription.