Custom role for deployment to Azure Web App slots

Azure Web App supports deployment slots. Production slot is the main one and there can be a couple of others. In order to follow a principle of least privileges different slots should have different security principals for deployment.

A service principal with deployment permissions for only a dedicated slot is useful in order to limit access to production deployment.

How to create such a service principal in Azure AD?

A service principal with a role in a dedicated slot

It looks like easiest way to achieve it is to create a service principal with “Contributor” role assignment for a dedicated slot only. And give no access to this service principal to the whole web app, no role there.

However this scenario doesn’t work. A service principal without permission for the whole web app is not able to deploy even to that specified slot:

az login --service-principal --username XXX --password ... --tenant XXX

az webapp deployment source config-zip --resource-group myresgroup --name mywebapp --src --slot test

ERROR: AuthorizationFailed - The client 'XXX' with object id 'XXX' 
does not have authorization to perform action 'Microsoft.Web/sites/publishxml/action' 
over scope '/subscriptions/XXX/resourceGroups/myresgroup/providers/Microsoft.Web/sites/mywebapp' 
or the scope is invalid. 
If access was recently granted, please refresh your credentials.

Even “Owner” role in a slot has the same result: the slot owner can not deploy to that slot it has no permission over the Web App.

The solution that works: custom role

The solution is to define a custom role.

From the deployment error above it is clear that this role needs a permission to Microsoft.Web/sites/publishxml/Action

  1. Create Publishing profile reader role at the Web App level. Publishing profile reader role is copied from the Contributor role and should have the following JSON definition:
  "properties": {
    "roleName": "Publishing profile reader",
    "description": "Role has permission to read website publishing profile.",
    "assignableScopes": [
    "permissions": [
        "actions": [
        "notActions": [
        "dataActions": [],
        "notDataActions": []

2. Assign this custom Publishing profile reader role at main Web App level to a service principal that is used for slot deployment. Thus service principals assigned for this custom role have permission to only read xml profile and have NO permission for deployment at main slot.

3. Assign Contributor role to that service principal at slot level.

Thus this service principal can deploy at a slot only and has no permission for deployment to production. Bingo!