How can a publisher/ISV access the data plane of an Azure managed application?
Last updated
Last updated
ISVs can package and sell their solution as a managed application via Azure Marketplace, i.e. the ISV solution gets provisioned (via an ARM template) into the customer's environment. It's called 'managed' application because the publisher/ISV can indicate which identities from the publisher's Entra ID tenant are authorized to manage resources in the managed application.
Authorized employees (or applications) in the publisher's tenant can 'see' the customer's resources in their own Azure portal (and ARM REST API). One way is to configure (in partner center) a group in the publisher's Entra ID tenant to be an Owner
on managed resource groups. As a result, if the managed resource group for example contains a virtual machine, members of that group can turn the VM on or off.
The Owner
privileges configured in Azure partner center only apply to control plane operation, that is, to calls against managed resource group resource via the ARM API. For example, if the managed resource group contains a storage account, and the storage account allows access via storage account access keys, then authorized members at the publisher side can reveal the storage account's access keys (technically a POST
call against the ARM API).
Please note that the access tokens used by publisher employees to hit the ARM API are issued by the publisher's Entra ID tenant. For managed apps, the ARM API 'knows' that even if the token is not coming from the customer's Entra ID tenant, the access is still OK if it comes from the publisher.
If the service access should happen using Entra ID authentication (a Bearer / access token), or the service only supports Enta ID authN, then the previously mentioned 'access key' mechanism doesn't work, so Entra ID it is.
However, for data plane operations (like updating a secret in KeyVault or uploading a blob to blob storage), the access token must be issued by the customer's Entra ID tenant. And the publisher has no accounts in the customer's tenant.
During the provisioning of the managed application, you also cannot create a service principal with client_id and client_secret in the customer's tenant.
There are 3 ways how this can be solved:
In Azure Marketplace managed applications, you must distinguish between the "managed application" object, and the "managed resource group" that belongs to the managed application: The managed application object if of ARM resource type Microsoft.Solutions/applications
. This is the object that is fully customer-manageable; while the customer might not be allowed to delete resources within the managed resource group, they can delete the managed application object itself (which results in deletion of the corresponding resource group).
A 'managed application object' can have a managed identity (see the docs). In the ARM template, the ISV can create an RBAC assignment to make the managed application a Secrets Officer on the Key Vault resource. This managed identity lives in the right tenant (the customer tenant), and is authorized to access Key Vault (or other data planes). But how to get a token?
The docs show the necessary API call:
On the ISV side, an authorized identity first fetches a token for the ARM control plane (audience https://management.azure.com/
), and then POSTs against the Microsoft.Solutions/applications
resource at the customer side, with the listTokens
operation, to fetch a token of the managed app.
Alternatively, if there is a user-assigned managed identity in the managed resource group that is authorized to do whatever you want, you can also supply the "userAssignedIdentities": [...]
identity for which you'd like a token.
In addition to previously described approach of POSTing to the ARM API to list an access token (e.g. for a user-assigned managed identity), you can use workload identity federation to sign-in directly to the UAMI from a trusted IdP. I have a small demo for this approach in my GitHub repo chgeuer/metering_cloudshell.
In this example, the UAMI is configured to allow federated sign-in from an identity provider. So one first has to get an access token from that trusted IdP, and then do a client credentials grant against the customer's Entra tenant, with a "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
.
At the moment, you cannot configure the publisher's Entra ID tenant to be a trusted issuer for a federated credential in the customer's Entra ID tenant. You would get an AADSTS700222 error here. That's why in my sample chgeuer/metering_cloudshell I created a 'fake' IdP by storing the IdP metadata in a storage account.
In the past, publishers attached an authorized managed identity in the managed resource group to a virtual machine in the managed resource group. They then remotely signed in the the VM (via SSH), and fetched a token for the managed identity by talking the the VM's instance metadata service' endpoint (IMDS), on IP 169.254.169.254.
However, this is very inflexible (having to have a running VM), hard to automate, expensive and cumbersome (need a running VM), and certainly created security issues (remote connections to a VM might not give cozy feelings).