Custom Resource Providers vs Managed Applications in Azure: When to Use What
Azure offers two powerful mechanisms for exposing services and extending the platform: Custom Resource Providers (CRP) and Managed Applications. While they both allow you to expose functionality to Azure users, they differ significantly in scope and purpose. This post breaks down the key differences, use cases, and example ARM templates for each.
Key Difference in Exposure
Custom Resource Providers (CRP):
- Expose a service as a first-class Azure resource type (e.g.,
MyCompany.Proxy
) with its own API surface. - The service appears and behaves like a native Azure resource (e.g.,
Microsoft.Storage/storageAccounts
). - Ideal for creating custom resource types that are provisioned, managed, and interacted with like native Azure resources.
Managed Applications:
- Expose a pre-packaged solution as a single deployable unit in the customer’s subscription.
- The provider retains management control, while the customer consumes the service through a managed identity or service principal.
- Ideal for SaaS-style offerings that bundle multiple resources and require ongoing management.
Use Cases and Decision Criteria
Criteria | Custom Resource Provider | Managed Application |
---|---|---|
Custom API Endpoint | You need to expose a custom API endpoint as a resource in Azure, such as MyCompany.Proxy . |
Not suitable. Managed Apps are packaged solutions, not custom API endpoints. |
Service Integration | You want to integrate a third-party service and expose it as an Azure resource type. | You want to provide a service composed of multiple resources (e.g., VM + Function + Storage). |
Lifecycle Management | The logic of the service is external, and you need full control over scaling, monitoring, and versioning. | The service includes multiple Azure resources, and you need to manage their lifecycle as a cohesive unit. |
SaaS Offering | Not ideal for SaaS. Focus is on extending Azure API capabilities. | Ideal for SaaS-like solutions where you manage resources in a customer’s subscription. |
Access Control | Azure AD and RBAC at the resource level. | Managed Identity or Service Principal, with customer-configured RBAC. |
User Experience | The service is exposed as a native Azure resource, integrated with ARM, CLI, and Portal. | The service is deployed as a packaged application, with customer-facing configuration and management. |
Example Scenarios
Scenario 1: Proxy API Layer Exposing a Custom Function
- Requirement: A team wants to create a service that validates JSON data against a schema and returns the result. This service is implemented as an Azure Function.
CRP Approach:
- Create a CRP called
MyCompany.Validator
. - Expose a
validate
operation that forwards requests to the Azure Function. - The user interacts with the
MyCompany.Validator
resource as they would with any Azure resource. - Azure handles identity, API versioning, and access management.
Why CRP?
- The focus is on creating a reusable, first-class Azure resource that is part of the Azure API ecosystem.
- The service appears as a native resource and can be managed with Azure policies, RBAC, etc.
Scenario 2: Multi-Resource SaaS Deployment
- Requirement: A team has developed a security monitoring solution that includes:
- A VM for running a scanning agent.
- A Logic App for alerting.
- An Azure SQL Database for reporting.
Managed Application Approach:
- Package all resources as a Managed Application.
- Customer deploys the app into their subscription.
- The service provider manages the scanning agent, alerting logic, and database schema.
Why Managed Application?
- The service consists of multiple interdependent resources.
- The service provider needs ongoing access to manage and update the components.
- The customer maintains the resources but delegates management to the provider.
Example ARM Templates
/*
Azure Custom Resource Provider (CRP) ARM Template
- This template deploys a Custom Resource Provider that acts as a proxy to an Azure Function.
*/
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Resources/deploymentScripts",
"apiVersion": "2020-10-01",
"name": "crp-function-proxy",
"location": "[resourceGroup().location]",
"properties": {
"scriptContent": "az functionapp create --name myFunctionApp --resource-group [resourceGroup().name] --consumption-plan-location [resourceGroup().location]",
"cleanupPreference": "OnSuccess",
"forceUpdateTag": "1"
}
},
{
"type": "Microsoft.CustomProviders/resourceProviders",
"apiVersion": "2018-09-01-preview",
"name": "myCompany.proxy",
"location": "[resourceGroup().location]",
"properties": {
"resourceTypes": [
{
"name": "validate",
"endpoint": "[concat('https://', variables('functionAppUrl'), '/api/validate')]"
}
]
}
}
]
}
/*
Azure Managed Application ARM Template
- This template deploys a VM, a Function, and a Storage Account as a managed application.
*/
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Solutions/applications",
"apiVersion": "2019-07-01",
"name": "managedAppDeployment",
"location": "[resourceGroup().location]",
"properties": {
"managedResourceGroupId": "[resourceGroup().id]",
"applicationDefinitionId": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Solutions/applicationDefinitions/{definitionName}",
"parameters": {
"vmName": { "value": "myVM" },
"functionName": { "value": "myFunctionApp" },
"storageAccountName": { "value": "mystorageacct" }
}
}
}
]
}
Key Takeaway:
- Use a Custom Resource Provider when you want to extend Azure’s API with a new resource type or operation that behaves like a native Azure resource.
- Use a Managed Application when you want to bundle multiple Azure resources into a single, deployable solution that you manage on behalf of the customer.