AAD BreakGlass

Alternative take on Azure AD ‘Break Glass’ account

While these days its getting harder to block yourself from Azure ad via Conditional Access misconfiguration its still fairly easy to do it 🙂

I wanted to explore a way to create account, which in the first place cant be included in Conditional Access. This kind of Account would be an Application/SPN which signs in without delegated user context.

  • This stuff is still experimental testing, below is the best practice
  • At the moment, you cant monitor the spn’s, but anyone who has taken a peek to current azure ad sign-in logs export feature can guess that this feature is coming
  • I also wanted to ensure, that this is native passwordless account, we are in luck as SPN with Certificate can be just like that 🙂
  • Please note SPN’s could also be some where along the future included in CA’s :)…


  • Create Azure AD Application, and assign it permissions
  • Run the NodeJS sample
    • If there is any interest I will include the dependency list, for now the depedencies are only shown in code

Poc Run

  • This one is assigned with very heavy permissions, to be able to recover tenant from an utter disaster. It can also create an utter disaster (never run these demos in production tenant)

Create SPN with Powershell

$Subject = "CN=" + "BreakGlassAccountSecureCloud"
$Expiration = (get-date).AddYears(2)
$pass = Read-Host -Prompt "PFX exporting Password"
$cert = New-SelfSignedCertificate -CertStoreLocation "Cert:\CurrentUser\My" -Subject $Subject -KeySpec KeyExchange -NotAfter $Expiration
$AADKeyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
$cert| Export-PfxCertificate -FilePath (($Subject -split "=")[1] + ".pfx") -Password ($pass | ConvertTo-SecureString -AsPlainText -Force) 
#Navigate to directory where OpenSSL is installed
$certnfile = (($Subject -split "=")[1] + ".pem")
openssl.exe pkcs12 -in (($Subject -split "=")[1] + ".pfx") -passin "pass:$pass"  -out $certnfile -nodes
$data = get-content $certnfile
$data[$data.IndexOf("-----BEGIN PRIVATE KEY-----")..$data.IndexOf("-----END PRIVATE KEY-----")] | Out-File $certnfile-encoding "DEFAULT"
$naming = ($Subject -split "=")[1]
$application = New-AzureADApplication -DisplayName $naming -IdentifierUris  ("https://" + $naming + "recover.dewi.red") 
$sp = New-AzureADServicePrincipal -AppId $application.AppId 
Add-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | where-object {$_.DisplayName -eq "Company Administrator"}).Objectid -RefObjectId $sp.ObjectId
New-AzureADApplicationKeyCredential -ObjectId $application.ObjectId -CustomKeyIdentifier ($Subject -split "=")[1] -Type AsymmetricX509Cert -Usage Verify -Value $AADKeyValue -EndDate ($Expiration | get-date -format "dd.M.yyyy" )
    "thumbprint" = $cert.Thumbprint
    "subject" = $Subject
    "appid" = $application.appId 
    "tenantinfo" = (Get-AzureADTenantDetail).objectID
    "CertificatePath" = $certnfile
     } | ConvertTo-Json -Depth 4 | Out-File .\nodeconfig.JSON -Force -Encoding utf8
  • Assign the following permissions

NodeJS code example

Recap of the needed permissions (Includes permissions directory.readwrite.all related to managing the directory in a situation where no user driven management is possible)
  • Code will show the targeted policy and change its state to reporting only

Node.JS code with references to the certificate credentials flow

const fs = require('fs')
var config = require('./nodeconfig.json')
var chalk = require('chalk')
var request = require('request')
var {decode} = require('jsonwebtoken');
var {appid,tenantinfo,thumbprint,CertificatePath} =config
const {AuthenticationContext} = require('adal-node')
var authorityHostUrl = 'https://login.windows.net'
var tenant = tenantinfo; 
var authorityUrl = authorityHostUrl + '/' + tenant
var resource = 'https://graph.microsoft.com' 
var context = new AuthenticationContext(authorityUrl)
//Read Certificate into key
var ks = fs.readFileSync(CertificatePath).toString('UTF8')
context.acquireTokenWithClientCertificate(resource,appid,ks,thumbprint,(error,tokenresponse) => {
    var kvOpt = {
            "Authorization": "Bearer " + tokenresponse.accessToken
    request.get(kvOpt,(error,response2) => {
        //Remove [1] to show all policies
        //this is the targeted policy
        var patchob = response2.body.value[1].id
        //turn to reportOnly 
            kvOpt.method = "patch"
            kvOpt.uri = "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/" + patchob
            kvOpt.patch = "Enabled"
            kvOpt.headers['content-type'] = "application/json"
            kvOpt.json = {
            request(kvOpt, (error,response3) => console.log(response3.statusCode, response3.statusMessage))
  • Successful run will turn the selected array.item (policy) state to reportOnly
  • If there is interest I will share NodeJS Express App, that automates the steps above. This is just POC:ng it!


  • If you have insufficient permissions when calling graph api, you might see any of the following messages
error: {
code: 'AccessDenied',
message: 'You cannot perform the requested operation, required scopes are missing in the token.',
innerError: {
date: '2020-08-16T07:04:45',
'request-id': '2e557a9f-4ef0-4ab4-9e1c-7be3159f8808'

error: {
code: 'AccessDenied',
message: 'Insufficient privileges to create or update policy. Application.Read.All scope is required to add/edit application condition.',
innerError: {
date: '2020-08-16T07:18:45',
'request-id': '747a0f8c-fef2-4ca6-a0d6-ac7418ac350f'

0 comments on “Alternative take on Azure AD ‘Break Glass’ account


Täytä tietosi alle tai klikkaa kuvaketta kirjautuaksesi sisään:


Olet kommentoimassa WordPress.com -tilin nimissä. Log Out /  Muuta )


Olet kommentoimassa Facebook -tilin nimissä. Log Out /  Muuta )

Muodostetaan yhteyttä palveluun %s

%d bloggaajaa tykkää tästä: