6 min read
Azure Lighthouse for Multi-Tenant Management
Introduction
Azure Lighthouse enables service providers and enterprises to manage multiple Azure tenants with enhanced visibility, automation, and governance. Through Azure delegated resource management, you can access customer resources directly from your tenant while maintaining security and compliance. This guide covers practical implementation patterns for multi-tenant scenarios.
Understanding Azure Lighthouse
Key Concepts
**Managing Tenant**: Your organization's Azure AD tenant
**Customer Tenant**: The tenant you're managing (customer or subsidiary)
**Delegation**: Permission grant from customer to managing tenant
**Authorization**: Specific RBAC roles granted to managing tenant users/groups
Benefits:
- Single pane of glass for multiple tenants
- No context switching between directories
- Automated at-scale operations
- Audit trail across tenants
Onboarding Customers
ARM Template for Delegation
{
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mspOfferName": {
"type": "string",
"metadata": {
"description": "Managed Service Provider offer name"
},
"defaultValue": "Contoso Managed Services"
},
"mspOfferDescription": {
"type": "string",
"metadata": {
"description": "Description of the MSP offer"
},
"defaultValue": "Provides monitoring, security, and management services"
},
"managedByTenantId": {
"type": "string",
"metadata": {
"description": "Managing tenant ID"
}
},
"authorizations": {
"type": "array",
"metadata": {
"description": "Array of authorization objects"
}
}
},
"variables": {
"mspRegistrationName": "[guid(parameters('mspOfferName'))]",
"mspAssignmentName": "[guid(parameters('mspOfferName'))]"
},
"resources": [
{
"type": "Microsoft.ManagedServices/registrationDefinitions",
"apiVersion": "2020-02-01-preview",
"name": "[variables('mspRegistrationName')]",
"properties": {
"registrationDefinitionName": "[parameters('mspOfferName')]",
"description": "[parameters('mspOfferDescription')]",
"managedByTenantId": "[parameters('managedByTenantId')]",
"authorizations": "[parameters('authorizations')]"
}
},
{
"type": "Microsoft.ManagedServices/registrationAssignments",
"apiVersion": "2020-02-01-preview",
"name": "[variables('mspAssignmentName')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedServices/registrationDefinitions', variables('mspRegistrationName'))]"
],
"properties": {
"registrationDefinitionId": "[resourceId('Microsoft.ManagedServices/registrationDefinitions', variables('mspRegistrationName'))]"
}
}
],
"outputs": {
"registrationDefinitionId": {
"type": "string",
"value": "[resourceId('Microsoft.ManagedServices/registrationDefinitions', variables('mspRegistrationName'))]"
}
}
}
Parameters File
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mspOfferName": {
"value": "Contoso Managed Services"
},
"mspOfferDescription": {
"value": "Infrastructure monitoring and management services"
},
"managedByTenantId": {
"value": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"authorizations": {
"value": [
{
"principalId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"roleDefinitionId": "acdd72a7-3385-48ef-bd42-f606fba81ae7",
"principalIdDisplayName": "MSP Operators Group"
},
{
"principalId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
"roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c",
"principalIdDisplayName": "MSP Administrators Group"
},
{
"principalId": "cccccccc-cccc-cccc-cccc-cccccccccccc",
"roleDefinitionId": "91c1777a-f3dc-4fae-b103-61d183457e46",
"principalIdDisplayName": "MSP Security Team",
"delegatedRoleDefinitionIds": [
"a]7ffa36-a066-4b39-a5ea-ed1dbe8e3e6c"
]
}
]
}
}
}
Deploying Delegation
PowerShell Deployment
# Deploy to customer subscription
$customerSubscriptionId = "customer-subscription-id"
# Connect to customer tenant
Connect-AzAccount -Tenant "customer-tenant-id" -Subscription $customerSubscriptionId
# Deploy the delegation template
New-AzSubscriptionDeployment `
-Location "australiaeast" `
-TemplateFile "./lighthouse-delegation.json" `
-TemplateParameterFile "./lighthouse-params.json" `
-Name "ContosoDelegation"
Azure CLI Deployment
# Login to customer context
az login --tenant customer-tenant-id
# Set subscription
az account set --subscription customer-subscription-id
# Deploy delegation
az deployment sub create \
--location australiaeast \
--template-file lighthouse-delegation.json \
--parameters @lighthouse-params.json \
--name ContosoDelegation
Managing Delegated Resources
Listing Delegated Subscriptions
# From managing tenant
Connect-AzAccount -Tenant "managing-tenant-id"
# List all delegated subscriptions
Get-AzSubscription | ForEach-Object {
$sub = $_
$delegation = Get-AzManagedServicesAssignment -Scope "/subscriptions/$($sub.Id)" -ErrorAction SilentlyContinue
if ($delegation) {
[PSCustomObject]@{
SubscriptionName = $sub.Name
SubscriptionId = $sub.Id
TenantId = $sub.TenantId
OfferName = $delegation.Properties.RegistrationDefinitionName
}
}
}
Cross-Tenant Azure CLI Commands
# List VMs across all delegated subscriptions
az vm list --query "[].{Name:name, ResourceGroup:resourceGroup, Location:location}" --output table
# Query with Resource Graph across delegated subscriptions
az graph query -q "
Resources
| where type =~ 'microsoft.compute/virtualmachines'
| project name, resourceGroup, subscriptionId, location
| limit 100"
Automation with Azure Lighthouse
Azure Automation Runbook
# Runbook: Start-DelegatedVMs.ps1
param(
[Parameter(Mandatory=$false)]
[string]$TagName = "AutoStart",
[Parameter(Mandatory=$false)]
[string]$TagValue = "True"
)
# Authenticate using Managed Identity
Connect-AzAccount -Identity
# Get all delegated subscriptions
$subscriptions = Get-AzSubscription
foreach ($sub in $subscriptions) {
Set-AzContext -SubscriptionId $sub.Id
# Find VMs with specific tag
$vms = Get-AzVM | Where-Object {
$_.Tags[$TagName] -eq $TagValue
}
foreach ($vm in $vms) {
Write-Output "Starting VM: $($vm.Name) in subscription $($sub.Name)"
Start-AzVM -ResourceGroupName $vm.ResourceGroupName `
-Name $vm.Name -NoWait
}
}
Azure Policy at Scale
# Apply policy to all delegated subscriptions
$policyDefinitionId = "/providers/Microsoft.Authorization/policyDefinitions/0015ea4d-51ff-4ce3-8d8c-f3f8f0179a56"
$subscriptions = Get-AzSubscription
foreach ($sub in $subscriptions) {
Set-AzContext -SubscriptionId $sub.Id
$existingAssignment = Get-AzPolicyAssignment -Name "DiagnosticSettings" -Scope "/subscriptions/$($sub.Id)" -ErrorAction SilentlyContinue
if (-not $existingAssignment) {
New-AzPolicyAssignment `
-Name "DiagnosticSettings" `
-DisplayName "Enable Diagnostic Settings" `
-PolicyDefinition (Get-AzPolicyDefinition -Id $policyDefinitionId) `
-Scope "/subscriptions/$($sub.Id)"
Write-Output "Policy assigned to: $($sub.Name)"
}
}
Azure Functions for Multi-Tenant Operations
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Compute;
public class CrossTenantVmService
{
private readonly ArmClient _armClient;
public CrossTenantVmService()
{
// Uses Managed Identity - works across delegated subscriptions
_armClient = new ArmClient(new DefaultAzureCredential());
}
public async Task<IList<VmInfo>> GetAllVmsAsync()
{
var vms = new List<VmInfo>();
await foreach (var subscription in _armClient.GetSubscriptions())
{
await foreach (var vm in subscription.GetVirtualMachinesAsync())
{
vms.Add(new VmInfo
{
Name = vm.Data.Name,
SubscriptionId = subscription.Id,
ResourceGroup = vm.Id.ResourceGroupName,
Location = vm.Data.Location,
PowerState = vm.Data.InstanceView?.Statuses?
.FirstOrDefault(s => s.Code?.StartsWith("PowerState/") == true)?.Code
});
}
}
return vms;
}
public async Task StartVmAsync(string subscriptionId, string resourceGroup, string vmName)
{
var subscription = await _armClient.GetSubscriptions()
.GetAsync(subscriptionId);
var vm = await subscription.Value.GetResourceGroups()
.GetAsync(resourceGroup)
.Result.Value.GetVirtualMachines()
.GetAsync(vmName);
await vm.Value.PowerOnAsync(Azure.WaitUntil.Started);
}
}
public record VmInfo
{
public string Name { get; init; }
public string SubscriptionId { get; init; }
public string ResourceGroup { get; init; }
public string Location { get; init; }
public string PowerState { get; init; }
}
Monitoring Delegated Resources
Log Analytics Workspace Query
// Query across all delegated workspaces
union withsource=SubscriptionId *
| where TimeGenerated > ago(24h)
| where Category == "Administrative"
| summarize EventCount = count() by SubscriptionId, OperationName
| order by EventCount desc
Azure Monitor Alerts
{
"type": "Microsoft.Insights/scheduledQueryRules",
"apiVersion": "2021-08-01",
"name": "CrossTenantAlert",
"location": "australiaeast",
"properties": {
"displayName": "Critical Events Across Tenants",
"severity": 1,
"enabled": true,
"evaluationFrequency": "PT5M",
"windowSize": "PT5M",
"scopes": [
"/subscriptions/{subscription-id}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{workspace}"
],
"criteria": {
"allOf": [
{
"query": "AzureActivity | where Level == 'Critical' | summarize count() by SubscriptionId",
"timeAggregation": "Count",
"operator": "GreaterThan",
"threshold": 0
}
]
},
"actions": {
"actionGroups": ["/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Insights/actionGroups/ops-team"]
}
}
}
Best Practices
1. **Use Azure AD Groups** - Assign roles to groups, not individuals
2. **Principle of Least Privilege** - Grant minimum required permissions
3. **Separate Environments** - Different delegations for prod/non-prod
4. **Audit Regularly** - Review delegation assignments
5. **Document Authorizations** - Maintain clear records
6. **Use Eligible Roles** - Enable PIM for sensitive operations
7. **Automate Onboarding** - Use templates for consistency
Conclusion
Azure Lighthouse transforms multi-tenant management from a fragmented experience to a unified operational model. Whether you’re a managed service provider or an enterprise with multiple subsidiaries, Lighthouse enables efficient, secure, and auditable cross-tenant operations. Combined with Azure Policy and automation, it provides the foundation for scalable governance.