I wrote this blog because configuring sign-in and audit log export from Azure AD B2C to Azure Monitor based on the existing guide may appear complex – Especially without previous knowledge of two distinct concepts: 1. Delegation model of Azure Lighthouse and the 2 .tenant model introduced by B2C.
Link: Azure guide
If you are well versed in both (1,2), It doesn’t matter which guide you use to configure. To be honest, I think the docs.microsoft.com one is gonna stay bit more updated, vs a blog which tends to be more of an snapshot of its writing times assumptions. Also since this concept for at least me was bit confusing initially, there might be some false assumptions, if so don’t hesitate to DM in twitter…
Update: added new part for monitoring administrative changes
Expected knowledge after reading this blog
- How Azure Lighthouse and delegated access work in conjunction to expose log export settings in B2C
- How to export to sign-in and and audit logs to Azure Storage, Log Analytics, or Event Hub
post structure
- How B2C Monitoring works
- Tenant structure
- MSP Delegation model in B2C monitoring
- Creating MSP offer to myself?
- Two or three tenants? :)…
- Configuration
- prerequisites
- Configuration 1. Create the delegation offer
- Configuration 2. Deploy the offer
- Configuration 3. Configure log export in B2C
- Wrapping it up
- Troubleshooting tips
How B2C Monitoring works
Tenant structure
If you look at the hierarchy in Azure, the B2C tenant is a resource under Azure Subscription of another Azure tenant

- This can get confusing because typically in Azure the top level object is the tenant – There are no sub-tenants, only management groups, subscriptions, resource groups, and finally resources.
MSP Delegation model in B2C monitoring
The monitoring of Azure AD B2C is configured utilizing the MSP model introduced by Azure Lighthouse, even though its not clearly stated, I think this is an clever way to expose a feature to an resource (B2C), that from ”tenant level” does not have subscriptions as sub-concept where the resources could exist

Creating MSP offer to myself?

If you are the sole Azure party managing the B2C tenant, and the Azure tenant which in B2C exists as an resource, you end up creating an MSP offer to yourself. Nothing bad with this (Its actually pretty cool concept using the MSP model) but it might be hard to grasp at first sight…
- The root reason for this is that you can’t create MSP delegations inside the same tenant.
- This is enforced by the fact, that with B2C you end up always having two tenants anyways (Creating B2C requires a subscription which must exist in another tenant, before the B2C tenant exist)

Two or three tenants? :)…
- Circular condition: There is no explicit reason, other than convenience that you end up creating a delegation from sub resource in your tenant to your tenant hosting the sub resource
- You could create the delegation to an third subscription, which would break the seemingly circular condition, but this would actually make things more complex. Let me show why
- Current model ”Two tenants”
- Azure Tenant hosting the B2C resource configured to expose Log Analytics feature via delegation (3) to B2C tenant (2)
- B2C Tenant
- Delegation from B2C tenant (2) to (1) Azure Tenant to access Azure Monitor (Log Analytics)
- Other model ”Three tenants” (Haven’t tested this one…)
- Azure Tenant hosting the B2C resource
- B2C Tenant
- Azure Tenant configured to expose Log Analytics feature via delegation (4) to B2C tenant (2)
- Delegation from B2C tenant (2) to (3) Azure Tenant to access Azure Monitor (Log Analytics)
Configuration
Prerequisites
Have to following done before you start with 1.
- B2C tenant linked to an subscription
- Group (Principal) in B2C tenant, which you grant the access to delegated resources exposed in another tenant
- Place the B2C admin user in the group
- Most convenient way to create a group in Azure AD B2C directory, is to access it from the aad.portal.azure.com (this accesses it from the Azure AD Side… I know that sounds confusing, but perhaps an subject to another blog post)
- Group (Principal) in B2C tenant, which you grant the access to delegated resources exposed in another tenant
- Azure Tenant
- Resource Group which you which you expose to the delegation
- Log analytics workspace
- Tools
- AZ powershell module
- VScode, or any other preferable editor
Screenshots for prerequisites
B2C group getting tenantID
Configuration 1. Create the delegation offer
- mspOfferName, any suitable string ”SecureCloudBlog B2C management by delegation”
- rgName is the name of the resource group you created earlier
- managedByTenantId is the tenantId of the B2C tenant
- not the tenant ID of the tenant hosting the subscription
- principalId, is the group you created in the B2C directory earlier
- principalIdDisplayName, is dispaly name for corresponding use case. In my example ’Azure Monitor Access’
- roleDefinitionId, is the default ID for contributor access for the resource group you enable delegation to
B2CMSPparams.JSON
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mspOfferName": {
"value": "SecureCloudBlog B2C management by delegation"
},
"rgName": {
"value": "B2C"
},
"mspOfferDescription": {
"value": "Provide Azure Monitor for B2C resource"
},
"managedByTenantId": {
"value": "972103f7-60e5-4153-a8fa-1840f0f03678"
},
"authorizations": {
"value": [
{
"principalId": "ba2d04e4-e3cb-4b69-b898-ee3facc0bf13",
"principalIdDisplayName": "Azure Monitor Access",
"roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c"
}
]
}
}
}
B2CMSPtemplate.JSON
{ "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "mspOfferName": { "type": "string", "metadata": { "description": "Specify the name of the offer from the Managed Service Provider" } }, "mspOfferDescription": { "type": "string", "metadata": { "description": "Name of the Managed Service Provider offering" } }, "managedByTenantId": { "type": "string", "metadata": { "description": "Specify the tenant id of the Managed Service Provider" } }, "authorizations": { "type": "array", "metadata": { "description": "Specify an array of objects, containing tuples of Azure Active Directory principalId, a Azure roleDefinitionId, and an optional principalIdDisplayName. The roleDefinition specified is granted to the principalId in the provider's Active Directory and the principalIdDisplayName is visible to customers." } }, "rgName": { "type": "string" } }, "variables": { "mspRegistrationName": "[guid(parameters('mspOfferName'))]", "mspAssignmentName": "[guid(parameters('rgName'))]" }, "resources": [ { "type": "Microsoft.ManagedServices/registrationDefinitions", "apiVersion": "2019-06-01", "name": "[variables('mspRegistrationName')]", "properties": { "registrationDefinitionName": "[parameters('mspOfferName')]", "description": "[parameters('mspOfferDescription')]", "managedByTenantId": "[parameters('managedByTenantId')]", "authorizations": "[parameters('authorizations')]" } }, { "type": "Microsoft.Resources/deployments", "apiVersion": "2018-05-01", "name": "rgAssignment", "resourceGroup": "[parameters('rgName')]", "dependsOn": [ "[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]" ], "properties":{ "mode":"Incremental", "template":{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": {}, "resources": [ { "type": "Microsoft.ManagedServices/registrationAssignments", "apiVersion": "2019-06-01", "name": "[variables('mspAssignmentName')]", "properties": { "registrationDefinitionId": "[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]" } } ] } } } ], "outputs": { "mspOfferName": { "type": "string", "value": "[concat('Managed by', ' ', parameters('mspOfferName'))]" }, "authorizations": { "type": "array", "value": "[parameters('authorizations')]" } } }
Configuration 2. Deploy the offer
- Save the files created in step 1. to an location you can reference in the following script
Ensure you have the correct subscription selected (select-AZsubscription works here)
$template = ".\B2CMSPtemplate.JSON"
$templateParams = ".\B2CMSPparams.json"
Connect-AzAccount -SubscriptionId "YourSubID"
New-AzDeployment -Name "B2Cmonitoring" `
-Location "westeurope" `
-TemplateFile $template `
-TemplateParameterFile $templateParams `
-Verbose

The expected end result is as follows.
- There might be small delay before the delegation is available in the services

After the delegation you should be able to login with B2C admin user, and use Azure LightHouse navigation experience of delegated directories including the subscriptions

Azure delegated resource management: Manage your customers’ Azure resources securely from within your own tenant, without having to switch context and control planes. Subscriptions and resource groups can be delegated to specified users and roles in the managing tenant, with the ability to remove access as needed. For more info, see Azure delegated resource management.”
Configuration 3. Configure log export in B2C

- Access Azure AD B2C directory as user who is in the delegation group
- You should have the delegation selected for both directories, and the subscription where the Log Analytics is in order to successfully deploy the monitoring to B2C tenant
Final touches
- From sign-ins select ’Export Data Settings’

- Select ’Add diagnostic settings’ to configure the log export settings
- If you see error here, then review the prerequisites, or ensure the ’Directory + subscription’ has the correct selections

- Select the destinations you wish to export the logs to


Wrapping it up:
After successful configuration you will see Azure AD B2C events in the Log Analytics workspace.
- Please note, that in Azure AD B2C Federated login goes to AuditLogs, and local directory sign-in goes to the SignInLogs
- events are split between audit and sign-in logs also for some operations for local account sign-ins

Lighthouse and service provider settings
- You can view lighthouse settings from the B2C tenant and see the Azure tenant where the log analytics is placed as a customer

- You can view service provider settings in the tenant where delegation is exposed to

Troubleshooting tips
The following conditions can introduce set of seemingly terminating or intermittent error
- wrong subscription selected in any of the subscription filters
- trying to create delegation within single tenant
- B2C resource not linked to subscription
- defined principals do not exist in the target subscription
- when browsing logs in B2C you have user who has wrong subscription context ”ERROR RETRIEVING DATA”
- You can workaround this with using a user who is in both directories, or just in the AAD directory
- By my quick testing it looks like the even though the MSP offering works correctly, its trying to fetch the registered providers from the B2C tenant which is the party using the delegation. You wont see this error if the admin account is present in both directories besides having access to the delegation (For example the user you used to create the B2C directory)



ERROR RETRIEVING DATA Register resource provider 'Microsoft.Insights' for this subscription to enable this query If issue persists, please open a support ticket. Request id:
New-AzDeployment : 8:46:49 AM - Resource Microsoft.Resources/deployments 'rgAssignment' failed with message '{ "status": "Failed", "error": { "code": "ResourceDeploymentFailure", "message": "The resource operation completed with terminal provisioning state 'Failed'.", "details": [ { "code": "DeploymentFailed", "message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.", "details": [ { "code": "BadRequest", "message": "{\r\n \"error\": {\r\n \"code\": \"RegistrationAssignmentInvalidUpdate\",\r\n \"message\": \"Registration assignment '7df986f4-8c48-5c92-ab0c-66c7f11517c6' not allowed to update registration definition reference.\"\r\n }\r\n}" } ] } ] } }'
Extra: Monitoring administrative changes to Azure AD B2C
I added this part to the blog, as I was recently asked, about monitoring administrative operations performed on B2C side
For B2C changes you need to access the ”AAD” side of the service to peek the audit logs:

Example: Audit event ’Create user flow’

- You will see similar event the B2C side audit logs

Both views seem to use similar API,
- Client side rendering is different
- AAD side uses V2 version
- AAD side requests audit attributes in body payload, whereas B2C is API requests these attributes via query params.


- There is rendering difference of the events, but the event is the same (CorrelationId)
- in AAD Side of the logs modification is shown in target pane, whereas b2c side its rendered as single object
Exporting
- Exporting of these logs is configured on earlier step (of this blog)

- You can search the event via correlationId from Log Analytics workspace

Great write up, I actually came across this having completed the above config after wading through the articles and sloly wrapping my head around it also. Whilst this covers Azure AD events in the B2C tenancy what I’m currently struggling to understand is how to monitor any changes made to the B2C configuration. If this was in a normal sub that would be achived via the activity logs which have their diagnostic settings defined at sub level. I can’t find any way of enabling Activity Logs for the B2C config, any thoughts?
TykkääTykkää
Hi, Thats a great question. I would assume that some operations are part of the audit logs, which cover also federation ops (and not the sign in logs, which at first glimpse might feel strange) – I will take a look and perhaps make an update post, if I find anything that fits the bill 🙂
TykkääTykkää
Hi, Blog is now updated on my take. Hope it helps, if there is something that its sorely missing just ping a new question!
TykkääTykkää