Azure Lighthouse – A Cloud Native Managed Services Model for Service Providers

Recently Azure announced this service called ‘Azure Lighthouse’. It allows managed service providers and customers to manage the tenant access and the delegation from a single point of interface in the Azure Portal itself. With some marketing garnish, I would like to call it as Cloud Native Managed Service Model. Let me take you through the fundamentals of Azure Lighthouse.

Before proceeding further, this post assumes, you’re familiar with AAD concepts like tenants/directories, object ids, service principles, RBAC etc. I have not referenced or elaborated them here.

Before diving in, let’s look at how the existing managed service providers access their customer tenants. Generally, they use either one of the following.

  1. Service Provider access Customer Tenant as a Guest.
  2. Service Provider access Customer Tenant with a customer tenant user account.

Consider this example, Aventude Digital with its Azure tenant looking for a partner to manage our Azure Resources. MassRover is a managed service provider; Aventude Digital reaches MassRover and requests their service. Bob is the support engineer from MassRover with his UPN (bob@massrover.onmicrosoft.com) should gain access to Aventude Digital tenant.

Scenario #1

Bob gets access to Aventude Digital tenant as a Guest user. In this case Aventude Digital administrator Linda should invite Bob to her tenant, with the required RBAC permissions. Once Bob receives the invitation, he can access Aventude Digital directory. When Bob logs in using his own UPN (bob@massrover.onmicrosoft.com), he can see two directories in Azure – MassRover directory where he is a direct member and Aventude Digital directory where he’s a guest user.

Bob can switch between them and access the resources as per the granted permissions and continue his support work. The invitation process is manual and repetitive. Below image shows, how Bob access different tenants, being the Guest user.

aventude guest directories

Scenario #2

Bob gets a user account from Aventude Digital tenant. Aventude Digital administrator creates a user account in their directory for Bob, something like bob_ext@aventudedigital.onmicrosoft.com. Bob must use this user to access Aventude Digital tenant. This becomes a mess when Bob manages many customers, because he has to switch between different tenants using different UPNs and related passwords. Bob ends up maintaining a table of UPNs and passwords for each tenant he works for.

In short, Guest access is commonly used. But still this is an AAD level delegation only. It is manual and when Bob selects different directories the authentication takes place and the experience is not smooth.

How Azure Lighthouse Improves this.

Azure Lighthouse offers service providers a single control plane to view and manage Azure across all their customers with higher automation, scale, and enhanced governance. With Azure Lighthouse, service providers can deliver managed services using comprehensive and robust management tooling built into the Azure platform. This offering can also benefit enterprise IT organizations managing resources across multiple tenants.

At the core of Azure Lighthouse is Azure Delegated Resource Management, on top of this Azure Portal based Cross Tenant Management Experience comes. Addition to this, we can have Extended Scenarios like Market Place & Managed Apps.

Rest of this post covers the technical implementation of Azure Delegated Resource Management and Cross Tenant Management Experience.

Delegated access can be done by two aspects, one is by manually executing the Azure Delegated Resource Management ARM scripts or by installing the published Market Place Managed Service Offering from the customer. In this post will cover the manual approach.

First, as a service provider, we should create the required ARM template to obtain the Azure Delegated Resource Management permissions from the customer tenant. These permissions can be obtained at subscription level or at the resource group level. Service Provider prepares the required ARM template, and this should be executed at the customer subscription

Below is the ARM template and the associated parameter file.

{
"$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."
}
}
},
"variables": {
"mspRegistrationName": "[guid(parameters('mspOfferName'))]",
"mspAssignmentName": "[guid(parameters('mspOfferName'))]"
},
"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.ManagedServices/registrationAssignments",
"apiVersion": "2019-06-01",
"name": "[variables('mspAssignmentName')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]"
],
"properties": {
"registrationDefinitionId": "[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]"
}
}
],
"outputs": {
"mspOfferName": {
"type": "string",
"value": "[concat('Managed by', ' ', parameters('mspOfferName'))]"
},
"authorizations": {
"type": "array",
"value": "[parameters('authorizations')]"
}
}
}
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"mspOfferName": {
"value": "Aventude Ops Servive"
},
"mspOfferDescription": {
"value": "Aventude Ops Service for Azure Managed Customers Tier1"
},
"managedByTenantId": {
"value": "261e3bf5-f768-49cc-a8bb-ab7dcc73817c"
},
"authorizations": {
"value": [
{
"principalId": "6665e9a2-e27a-42f0-8ce1-203c03255695",
"principalIdDisplayName": "Individual User",
"roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c"
},
{
"principalId": "52f00b53-e404-4b0e-9564-ffb8388702cd",
"principalIdDisplayName": "User Group Id (reccomended)",
"roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c"
}
]
}
}
}
view raw parameter.json hosted with ❤ by GitHub

The ARM template expects certain meta data like the managed service offering name, description and mainly the required delegated permissions (as authorizations). These authorizations are AAD principles (users / groups / service principles) paired with the RBAC roles. The values are fed to the ARM template using the corresponding parameter file.

AAD principle Ids can be found in the relevant blades (we need to use the respective Object IDs) and RBAC role IDs can be obtained from this link

Example: Bob’s Object ID in the MassRover (service provider) tenant is – 6665e9a2-e27a-42f0-8ce1-203c03255695 and we’re requesting a Contributor permission for this user. Azure RBAC ID for the Contributor role is – b24988ac-6180-42a0-ab88-20f7382dd24c. (obtained from the above link). This combination along with a name we provide to be displayed makes one authorization delegated access management record as below.

azure lighthouse authorization snippet

We can add many and different authorizations.

parameter file with different authorizations

Once the ARM template and associated parameter file are completed, customer should execute this in their subscription. In order to execute this, a non-guest user from the customer tenant with Owner permissions to the subscription is required.

PS C:\Windows\system32> az deployment create --name AzureLightHouseDeployment1 --location southeastasia --template-file "C:\Users\Thuru\Desktop\light house blog\json\al.json" --parameters "C:\Users\Thuru\Desktop\light house blog\json\alparam.json" –verbose

It takes, some time and the CLI will spit out an output json.

I used two tenants for this testing. One is called MassRover (service provider) and the other one is Aventude Digital (customer). Above script is executed at the Aventude Digital subscription and script was prepared with the parameters from MassRover. (Bob is in the MassRover tenant).

After execution. In the MassRover tenant Lighthouse, under the My Customers section we can see Aventude Digital.

In the  Aventude Digital tenant Lighthouse, under the Service Providers section we can see MassRover.

This explains the basic of Azure Lighthouse, but it has some limitations at this point. One of the key limitations is, if DataBricks is provisioned in a tenant, then Azure Delegated Resource Management fails, and there are some other limitations too.

If you’re a service provider Azure Lighthouse provides a greater visibility by being in the marketplace. This requires additional setup via partner portal. Also, using service principle delegation, service providers can programmatically automate management tasks. Customers can view the Service Providers at one place including the granted access permissions.

In this post I have covered only one path of Azure Lighthouse, (subscription level delegated resource management), Let me know your experience with Azure Lighthouse and any interesting combinations.