Introduction
Azure Lighthouse is a hot topic, but based on my experiences not a lot of people know exactly what it does, how it works or how to use it themselves.
So letās try to remedy that. Do keep in mind this is my understanding of how Azure Lighthouse works - I might be completely off, but I have made it work at least twice so atleast Iāve got that going for me.
What is Azure Lighthouse?
In itās simplest form, Azure Lighthouse is a management tool - it allows us to perform management of Azure resources across tenants.
How does it give access across tenants?
It gives a principal in the managing tenant a level of access to a scope in the managed tenant:
graph LR
subgraph "Managing tenant"
p[Principal]
end
subgraph "Managed tenant"
a[Access] --> s[Scope]
end
p --> a
In order to explain a bit better, consider this matrix for each of the terms used above:
Legend | Description |
---|---|
Principal | Azure AD user, group or SPN (app registration) |
Access | Azure RBAC role |
Scope | Azure resource scope, i.e subscription or resource group |
Managing tenant | The service provider tenant |
Managed tenant | Customer tenant |
We can also draw the map again, assuming that we want to give an Azure AD group in the managing tenant an Azure RBAC role on a subscription in the managed tenant:
graph LR
subgraph "Managing tenant"
p[Azure AD group]
end
subgraph "Managed tenant"
a[Azure RBAC role] --> s[Subscription]
end
p --> a
So what does that mean, in plain english?
Letās assume we have two companies:
- Shortcake Company - managed service provider (MSSP)
- Strawberry Ltd - customer
Strawberry Ltd wants someone to manage their Microsoft Sentinel. Shortcake Company will create a managed service offer in the form of a lighthouse-template. In this template they define that:
- Their internal Azure AD group
Customer Strawberry Ltd - Sentinel Responder
needs access to the Microsoft Sentinel Contributor. - This access is required on the subscription
str-ltd-sub-sec
where Strawberry Ltd has deployed their Log Analytics Workspace.
If we expressed this in the form of the mermaid-diagram used earlier, it would look like this:
graph LR
subgraph "Shortcake MSSP tenant"
p[Customer Strawberry Ltd - Sentinel Responder]
end
subgraph "Strawberry Ltd tenant"
a[Microsoft Sentinel Contributor] --> s[str-ltd-sub-sec]
end
p --> a
How do you set up Azure Lighthouse?
As mentioned earlier, Azure Lighthouse requires two tenants; the managing tenant and the managed tenant, but apart from that all that is required is a template, or an offer. The offer is defined by the MSSP and is either published to the Azure marketplace or sent directly to the customer as an ARM-template:
Defining an offer
We can find some samples directly from Microsoft. For this blogpost I will break down a template for the subscription
-level scope. You can find Microsoft-templates for resource groups here and marketplace here.
Azure Lighthouse managed subscription
Letās break a template down to itās parts in order to understand it. We will use a template Iāve created for the above example - to view the full template, click here.
Parameters
mspOfferName
This refers to the name of your managed service offering - which needs to be unique.
"parameters": {
"mspOfferName": {
"type": "string",
"metadata": {
"description": "Specify a unique name for your offer"
},
"defaultValue": "Shortcake Company - Managed Sentinel"
}
mspOfferDescription
Description of the managed service offering.
"mspOfferDescription": {
"type": "string",
"metadata": {
"description": "Name of the Managed Service Provider offering"
},
"defaultValue": "Managed Sentinel as a Service"
}
managedByTenantId
As it says, this is the tenantId
of the managing tenant - in this case the the Shortcake Company, which is the MSSP. This value is also how Azure Lighthouse knows where to look for the defined principals
we talked about above.
"managedByTenantId": {
"type": "string",
"metadata": {
"description": "Specify the tenant id of the Managed Service Provider"
},
"defaultValue": "tenantId"
}
Authorizations
This is where we combine the the principals
with the access
.
principalId
refers to the Azure ADobjectId
of theprincipal
you want to assign access to. In this case, our value forprincipalId
is theobjectId
of the Azure AD groupCustomer Strawberry Ltd - Sentinel Contributor
.principalIdDisplayName
(as far as I know) is the name that will show up in the customer tenant when they look at their āService Providersā tag.roleDefinitionId
refers to the GUID of the Azure RBAC-role you want to assign. In this case this is the Microsoft Sentinel Contributor - we can find the GUID by looking at the built in roles.
"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."
},
"defaultValue": [
{
"principalId": "00000000-0000-0000-0000-000000000000",
"principalIdDisplayName": "Customer Strawberry Ltd - Sentinel Contributor",
"roleDefinitionId": "ab8e14d6-4a74-4a29-9ba8-549422addade"
}
]
}
}
Resources
Microsoft.ManagedServices/registrationDefinitions
We can look at what this type does by going to the deployment reference. In my mind (which might be wrong), this creates a definition in the managed (customer) tenant - I read this similar as creating a policy definition, but not assigning it.
For our example, this means that it will create a managed services registration definition that says that a group in the tenant of the Shortcake Company will be allowed to access a subscription with a certain role once the definition is applied.
"resources": [
{
"type": "Microsoft.ManagedServices/registrationDefinitions",
"apiVersion": "2019-09-01",
"name": "[variables('mspRegistrationName')]",
"properties": {
"registrationDefinitionName": "[parameters('mspOfferName')]",
"description": "[parameters('mspOfferDescription')]",
"managedByTenantId": "[parameters('managedByTenantId')]",
"authorizations": "[parameters('authorizations')]"
}
}
Microsoft.ManagedServices/registrationAssignments
Again we can peek at the deployment reference.
This registers the definition - in effect applying it and registering the offer.
{
"type": "Microsoft.ManagedServices/registrationAssignments",
"apiVersion": "2019-09-01",
"name": "[variables('mspAssignmentName')]",
"dependsOn": [
"[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]"
],
"properties": {
"registrationDefinitionId": "[resourceId('Microsoft.ManagedServices/registrationDefinitions/', variables('mspRegistrationName'))]"
}
}
]
Onboard the template
At this point the customer can onboard the template - this is usually done by deploying a custom template in the Azure Portal, but you can also use Azure CLI and Azure Powershell.
This is also where you would chose what subscription to deploy into. For templates on the resource group level, the difference would be that the second block (the registrationAssignments
) would instead refer to a resource group (which could be set with a parameter value, or the customer inputs it during onboarding):
{
"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'))]"
}
}
]
}
}
}
So what can we use Azure Lighthouse for?
I would say only imagination really stops you - personally I enjoy using it with Microsoft Sentinel because it allows for a shared incident view and doing cross-workspace queries using the workspace()
function in Kusto.
This isnāt really the post to get into details on this - but I will share some more on how to use Azure Lighthouse for service principals and Sentinel in the future.
Disclaimer
Hopefully this gives some insight into Azure Lighthouse - if anything is wrong, unclear or you have any other questions feel free to reach out to me, as I mentioned in the start this is my understanding of Azure Lighthouse. I will update the post if I find any errors (or Iām made aware of them).
I am aware there are more use cases for Azure Lighthouse than simply managed services, if you are looking for ideas you can check out Microsoftās own samples. We can also do stuff like deploy Sentinel or create policies.
There are also multiple blocks to play around with in the schema, like eligibleAuthorizations
which allows you to assign users as eligible to a role via Azure PIM.
Also do keep in mind that Azure Lighthouse currently does not support Azure AD roles - if this ever changes I will most likely write about how to use that as an addition to this post.
Sources and more resources
If you want to know more you can read Microsofts very good documentation on onboarding customers or what Azure Lighthouse is.
If you want to read some of my old posts regarding Lighthouse, check out how to use Azure Lighthouse and deployment-templates to assign roles to a managed identity or if you prefer a user managed identity you can read about that as well.