Manage Azure Role Assignments

The azure-native:authorization:RoleAssignment resource, part of the Pulumi Azure Native provider, links Azure AD principals to role definitions at a specific scope: subscription, resource group, or individual resource. This guide focuses on two capabilities: scope hierarchy and principal-to-role linking.

Role assignments connect existing Azure AD principals to existing role definitions. The target scope must already exist. The examples are intentionally small. Combine them with your own principal IDs, role definitions, and resource paths.

Grant subscription-wide access to a user

Most deployments begin by granting access at the subscription level, allowing principals to manage resources across all resource groups.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const roleAssignment = new azure_native.authorization.RoleAssignment("roleAssignment", {
    principalId: "ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principalType: azure_native.authorization.PrincipalType.User,
    roleAssignmentName: "05c5a614-a7d6-4502-b150-c2fb455033ff",
    roleDefinitionId: "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope: "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2",
});
import pulumi
import pulumi_azure_native as azure_native

role_assignment = azure_native.authorization.RoleAssignment("roleAssignment",
    principal_id="ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principal_type=azure_native.authorization.PrincipalType.USER,
    role_assignment_name="05c5a614-a7d6-4502-b150-c2fb455033ff",
    role_definition_id="/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope="subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2")
package main

import (
	authorization "github.com/pulumi/pulumi-azure-native-sdk/authorization/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := authorization.NewRoleAssignment(ctx, "roleAssignment", &authorization.RoleAssignmentArgs{
			PrincipalId:        pulumi.String("ce2ce14e-85d7-4629-bdbc-454d0519d987"),
			PrincipalType:      pulumi.String(authorization.PrincipalTypeUser),
			RoleAssignmentName: pulumi.String("05c5a614-a7d6-4502-b150-c2fb455033ff"),
			RoleDefinitionId:   pulumi.String("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d"),
			Scope:              pulumi.String("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var roleAssignment = new AzureNative.Authorization.RoleAssignment("roleAssignment", new()
    {
        PrincipalId = "ce2ce14e-85d7-4629-bdbc-454d0519d987",
        PrincipalType = AzureNative.Authorization.PrincipalType.User,
        RoleAssignmentName = "05c5a614-a7d6-4502-b150-c2fb455033ff",
        RoleDefinitionId = "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
        Scope = "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.authorization.RoleAssignment;
import com.pulumi.azurenative.authorization.RoleAssignmentArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var roleAssignment = new RoleAssignment("roleAssignment", RoleAssignmentArgs.builder()
            .principalId("ce2ce14e-85d7-4629-bdbc-454d0519d987")
            .principalType("User")
            .roleAssignmentName("05c5a614-a7d6-4502-b150-c2fb455033ff")
            .roleDefinitionId("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d")
            .scope("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2")
            .build());

    }
}
resources:
  roleAssignment:
    type: azure-native:authorization:RoleAssignment
    properties:
      principalId: ce2ce14e-85d7-4629-bdbc-454d0519d987
      principalType: User
      roleAssignmentName: 05c5a614-a7d6-4502-b150-c2fb455033ff
      roleDefinitionId: /subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d
      scope: subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2

The scope property defines where permissions apply. A subscription scope grants access to all resources within that subscription. The principalId identifies the Azure AD user, service principal, or managed identity receiving permissions. The roleDefinitionId specifies which built-in or custom role to assign. The principalType clarifies whether the principal is a User, ServicePrincipal, or other type.

Scope access to a resource group

Teams often isolate environments into resource groups and grant access only within that boundary.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const roleAssignment = new azure_native.authorization.RoleAssignment("roleAssignment", {
    principalId: "ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principalType: azure_native.authorization.PrincipalType.User,
    roleAssignmentName: "05c5a614-a7d6-4502-b150-c2fb455033ff",
    roleDefinitionId: "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope: "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg",
});
import pulumi
import pulumi_azure_native as azure_native

role_assignment = azure_native.authorization.RoleAssignment("roleAssignment",
    principal_id="ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principal_type=azure_native.authorization.PrincipalType.USER,
    role_assignment_name="05c5a614-a7d6-4502-b150-c2fb455033ff",
    role_definition_id="/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope="subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg")
package main

import (
	authorization "github.com/pulumi/pulumi-azure-native-sdk/authorization/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := authorization.NewRoleAssignment(ctx, "roleAssignment", &authorization.RoleAssignmentArgs{
			PrincipalId:        pulumi.String("ce2ce14e-85d7-4629-bdbc-454d0519d987"),
			PrincipalType:      pulumi.String(authorization.PrincipalTypeUser),
			RoleAssignmentName: pulumi.String("05c5a614-a7d6-4502-b150-c2fb455033ff"),
			RoleDefinitionId:   pulumi.String("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d"),
			Scope:              pulumi.String("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var roleAssignment = new AzureNative.Authorization.RoleAssignment("roleAssignment", new()
    {
        PrincipalId = "ce2ce14e-85d7-4629-bdbc-454d0519d987",
        PrincipalType = AzureNative.Authorization.PrincipalType.User,
        RoleAssignmentName = "05c5a614-a7d6-4502-b150-c2fb455033ff",
        RoleDefinitionId = "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
        Scope = "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.authorization.RoleAssignment;
import com.pulumi.azurenative.authorization.RoleAssignmentArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var roleAssignment = new RoleAssignment("roleAssignment", RoleAssignmentArgs.builder()
            .principalId("ce2ce14e-85d7-4629-bdbc-454d0519d987")
            .principalType("User")
            .roleAssignmentName("05c5a614-a7d6-4502-b150-c2fb455033ff")
            .roleDefinitionId("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d")
            .scope("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg")
            .build());

    }
}
resources:
  roleAssignment:
    type: azure-native:authorization:RoleAssignment
    properties:
      principalId: ce2ce14e-85d7-4629-bdbc-454d0519d987
      principalType: User
      roleAssignmentName: 05c5a614-a7d6-4502-b150-c2fb455033ff
      roleDefinitionId: /subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d
      scope: subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg

The scope narrows to a resource group path, limiting permissions to resources within that group. This follows Azure’s hierarchical permission model: assignments at narrower scopes override broader ones. The same principal and role definition properties apply, but the scope path now includes the resource group name.

Grant access to a specific resource

For fine-grained control, you can assign permissions to individual resources like storage accounts or databases.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const roleAssignment = new azure_native.authorization.RoleAssignment("roleAssignment", {
    principalId: "ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principalType: azure_native.authorization.PrincipalType.User,
    roleAssignmentName: "05c5a614-a7d6-4502-b150-c2fb455033ff",
    roleDefinitionId: "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope: "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account",
});
import pulumi
import pulumi_azure_native as azure_native

role_assignment = azure_native.authorization.RoleAssignment("roleAssignment",
    principal_id="ce2ce14e-85d7-4629-bdbc-454d0519d987",
    principal_type=azure_native.authorization.PrincipalType.USER,
    role_assignment_name="05c5a614-a7d6-4502-b150-c2fb455033ff",
    role_definition_id="/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
    scope="subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account")
package main

import (
	authorization "github.com/pulumi/pulumi-azure-native-sdk/authorization/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := authorization.NewRoleAssignment(ctx, "roleAssignment", &authorization.RoleAssignmentArgs{
			PrincipalId:        pulumi.String("ce2ce14e-85d7-4629-bdbc-454d0519d987"),
			PrincipalType:      pulumi.String(authorization.PrincipalTypeUser),
			RoleAssignmentName: pulumi.String("05c5a614-a7d6-4502-b150-c2fb455033ff"),
			RoleDefinitionId:   pulumi.String("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d"),
			Scope:              pulumi.String("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var roleAssignment = new AzureNative.Authorization.RoleAssignment("roleAssignment", new()
    {
        PrincipalId = "ce2ce14e-85d7-4629-bdbc-454d0519d987",
        PrincipalType = AzureNative.Authorization.PrincipalType.User,
        RoleAssignmentName = "05c5a614-a7d6-4502-b150-c2fb455033ff",
        RoleDefinitionId = "/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d",
        Scope = "subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.authorization.RoleAssignment;
import com.pulumi.azurenative.authorization.RoleAssignmentArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var roleAssignment = new RoleAssignment("roleAssignment", RoleAssignmentArgs.builder()
            .principalId("ce2ce14e-85d7-4629-bdbc-454d0519d987")
            .principalType("User")
            .roleAssignmentName("05c5a614-a7d6-4502-b150-c2fb455033ff")
            .roleDefinitionId("/subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d")
            .scope("subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account")
            .build());

    }
}
resources:
  roleAssignment:
    type: azure-native:authorization:RoleAssignment
    properties:
      principalId: ce2ce14e-85d7-4629-bdbc-454d0519d987
      principalType: User
      roleAssignmentName: 05c5a614-a7d6-4502-b150-c2fb455033ff
      roleDefinitionId: /subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/providers/Microsoft.Authorization/roleDefinitions/0b5fe924-9a61-425c-96af-cfe6e287ca2d
      scope: subscriptions/a925f2f7-5c63-4b7b-8799-25a5f97bc3b2/resourceGroups/testrg/providers/Microsoft.DocumentDb/databaseAccounts/test-db-account

The scope path extends to a specific resource, providing the narrowest possible permissions. This example targets a Cosmos DB account, but the pattern applies to any Azure resource. The scope format follows Azure’s resource ID structure: subscription, resource group, provider namespace, and resource name.

Beyond these examples

These snippets focus on specific role assignment features: scope hierarchy (subscription, resource group, resource) and principal and role definition linking. They’re intentionally minimal rather than full access control solutions.

The examples reference pre-existing infrastructure such as Azure AD principals (users, service principals, managed identities), role definitions (built-in or custom), and target resources, resource groups, or subscriptions. They focus on configuring the assignment rather than creating the underlying identity or authorization infrastructure.

To keep things focused, common role assignment patterns are omitted, including:

  • Conditional access policies (condition, conditionVersion)
  • Delegated managed identity assignments
  • Assignment descriptions and metadata
  • Time-based or attribute-based access control

These omissions are intentional: the goal is to illustrate how each assignment scope is wired, not provide drop-in access control modules. See the RoleAssignment resource reference for all available configuration options.

Let's manage Azure Role Assignments

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Scope & Assignment Basics
What scope levels can I assign roles at?
You can assign roles at three levels: subscription, resource group, or individual resource. The scope property format varies by level, as shown in the examples.
What properties can't I change after creating a role assignment?
The principalId, scope, and roleAssignmentName properties are immutable. To change these, you must delete and recreate the role assignment.
What should I use for the roleAssignmentName?
Any valid GUID can be used for roleAssignmentName.
Principal Configuration
What's the difference between principalId and principalType?
principalId is the ID of the user, group, or service principal receiving the role. principalType classifies what type of principal it is (User, Group, ServicePrincipal, etc.).
What's the default value for principalType?
principalType defaults to User if not specified.
Conditions & Constraints
How do I restrict a role assignment to specific resources?
Use the condition property with Azure condition syntax. For example: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase 'foo_storage_container'.
What conditionVersion should I use?
Currently, only 2.0 is accepted for conditionVersion.

Using a different cloud?

Explore security guides for other cloud providers: