Monitoring with PowerShell: Monitoring O365 / Azure Breakglass account logon.

Microsoft advises to keep a “breakglass” account for environments in case of a major cell malfunction or other emergency situations. Our worry about these accounts has always been how to check if they have not been compromised or even used in anyway.

I’ve created the following two scripts for this. These scripts are for two cases:

  • The first script is to check the status of break glass accounts in general.
  • The second script is to check the logon status of any admin account.

The second script was designed for just-in-time administration. We have partner access to all of our clients so we don’t need admin accounts, normally speaking. The only problem with this is that some items such as the Security Center cannot be used by partner administrators or delegated access. To get access to these parts we create a temporary admin. We alert on -ANY- logged on admin.

Break-glass monitoring

#We match on the following account. prefix all your breakglass accounts with this. e.g. "Breakglass-1234321"
$BreakGlassUser = "Breakglass*"
############################################################
$ApplicationId         = 'xxxx-xxxx-xxx-xxxx-xxxx'
$ApplicationSecret     = 'TheSecretTheSecrey' | Convertto-SecureString -AsPlainText -Force
$TenantID              = 'YourTenantID'
$RefreshToken          = 'RefreshToken'
$ExchangeRefreshToken  = 'ExchangeRefreshToken'
$upn                   = 'UPN-Used-To-Generate-Tokens'
#############################################################
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID

Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken
$customers = Get-MsolPartnerContract -All
foreach ($customer in $customers) {
  $token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716'-RefreshToken $ExchangeRefreshToken -Scopes 'https://outlook.office365.com/.default' -Tenant $customer.TenantId
  $tokenValue = ConvertTo-SecureString "Bearer $($token.AccessToken)" -AsPlainText -Force
  $credential = New-Object System.Management.Automation.PSCredential($upn, $tokenValue)
  $customerId = $customer.DefaultDomainName
  $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($customerId)&BasicAuthToOAuthConversion=true" -Credential $credential -Authentication Basic -AllowRedirection
  Import-PSSession $session -allowclobber -DisableNameChecking
  $startDate = (Get-Date).AddDays(-1)
  $endDate = (Get-Date)
  $Logs = @()
  Write-Host "Retrieving logs for $($customer.name)" -ForegroundColor Blue
  do {
    $logs += Search-unifiedAuditLog -SessionCommand ReturnLargeSet -SessionId $customer.name  -ResultSize 5000 -StartDate $startDate -EndDate $endDate -Operations UserLoggedIn
    Write-Host "Retrieved $($logs.count) logs" -ForegroundColor Yellow
  }while ($Logs.count % 5000 -eq 0 -and $logs.count -ne 0)
  Write-Host "Finished Retrieving logs" -ForegroundColor Green
  $logs | Select-Object UserIds, Operations, CreationDate | Where-Object {$_.UserIds -like $BreakGlassUser}
}

Just-In-Time Admin logging

 ############################################################
$ApplicationId         = 'xxxx-xxxx-xxx-xxxx-xxxx'
$ApplicationSecret     = 'TheSecretTheSecrey' | Convertto-SecureString -AsPlainText -Force
$TenantID              = 'YourTenantID'
$RefreshToken          = 'RefreshToken'
$ExchangeRefreshToken  = 'ExchangeRefreshToken'
$upn                   = 'UPN-Used-To-Generate-Tokens'
#############################################################
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID 
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID 

Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken
$customers = Get-MsolPartnerContract -All
foreach ($customer in $customers) {
  $adminaccounts  = (Get-MsolRoleMember -TenantId $customer.tenantid -RoleObjectId (Get-MsolRole -RoleName "Company Administrator").ObjectId).EmailAddress
  $token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716'-RefreshToken $ExchangeRefreshToken -Scopes 'https://outlook.office365.com/.default' -Tenant $customer.TenantId
  $tokenValue = ConvertTo-SecureString "Bearer $($token.AccessToken)" -AsPlainText -Force
  $credential = New-Object System.Management.Automation.PSCredential($upn, $tokenValue)
  $customerId = $customer.DefaultDomainName
  $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($customerId)&BasicAuthToOAuthConversion=true" -Credential $credential -Authentication Basic -AllowRedirection
  Import-PSSession $session -allowclobber -DisableNameChecking
  $startDate = (Get-Date).AddDays(-1)
  $endDate = (Get-Date)
  $Logs = @()
  Write-Host "Retrieving logs for $($customer.name)" -ForegroundColor Blue
  do {
    $logs += Search-unifiedAuditLog -SessionCommand ReturnLargeSet -SessionId $customer.name  -ResultSize 5000 -StartDate $startDate -EndDate $endDate -Operations UserLoggedIn
    Write-Host "Retrieved $($logs.count) logs" -ForegroundColor Yellow
  }while ($Logs.count % 5000 -eq 0 -and $logs.count -ne 0)
  Write-Host "Finished Retrieving logs" -ForegroundColor Green
  $logs | Select-Object UserIds, Operations, CreationDate | Where-Object {$_.UserIds -in $AdminAccounts}
}

As always my suggestion would be to use your RMM system for monitoring these on a regular basis. We run the scripts every 30 minutes. You’ll have to modify them for your own RMM of course.

And that’s it! as always, Happy PowerShelling.

Recent Articles

The return of CyberDrain CTF

CyberDrain CTF returns! (and so do I!)

It’s been since september that I actually picked up a digital pen equivalent and wrote anything down. This was due to me being busy with life but also my side projects like CIPP. I’m trying to get back into the game of scripting and blogging about these scripts. There’s still so much to automate and so little time, right? ;)

Monitoring with PowerShell: Monitoring Acronis Backups

Intro

This is a monitoring script requested via Reddit, One of the reddit r/msp users wondered how they can monitor Acronis a little bit easier. I jumped on this because it happened pretty much at the same time that I was asked to speak at the Acronis CyberSummit so it kinda made sense to script this so I have something to demonstrate at my session there.

Monitoring with PowerShell: Monitoring VSS Snapshots

Intro

Wow! It’s been a while since I’ve blogged. I’ve just been so swamped with CIPP that I’ve just let the blogging go entirely. It’s a shame because I think out of all my hobbies it’s one I enjoy the most. It’s always nice helping others achieve their scripting target. I even got a couple of LinkedIn questions asking if I was done with blogging but I’m not. Writing always gives me some more piece of mind so I’ll try to catch up again. I know I’ve said that before but this time I’ll follow through. I’m sitting down right now and scheduling the release of 5 blogs in one go. No more whining and no more waiting.