Dynamic Client Role Assignments for Multi-Tenant SaaS Applications
PythonTo implement dynamic client role assignments for multi-tenant SaaS (Software as a Service) applications, we often need to create and manage roles and permissions that are scoped to individual tenants. In the context of Azure Active Directory (Azure AD), this can be done by defining roles within an application registration and then assigning these roles to users or service principals at runtime.
To accomplish this, we would use the Azure AD roles and permissions model, which includes the concepts of Application Roles and Role Assignments. An application role represents a permission that a user or service principal can be granted. Role assignments are records that map a role to a user or service principal for a particular scope, such as an Azure AD application.
The Pulumi components that facilitate this task are:
azuread.Application
: Defines an Azure AD application registration, including the app roles.azuread.AppRoleAssignment
: Represents the assignment of an app role to a user, group, or service principal in Azure AD.
Below is an illustrative Pulumi program written in Python that creates an Azure AD application with a custom application role and assigns that role to a service principal for a specific scope. The explanation of the code follows its completion.
import pulumi import pulumi_azuread as azuread # Create an Azure AD application with a custom "TenantAdmin" role. app = azuread.Application("multiTenantApp", # Define the application roles. app_roles=[azuread.ApplicationAppRoleArgs( allowed_member_types=["User"], description="Admins can manage tenant features in a multi-tenant application", display_name="TenantAdmin", is_enabled=True, value="TenantAdmin" # The role value that will be used in the role assignment. )] ) # Create a service principal for the Azure AD application. service_principal = azuread.ServicePrincipal("multiTenantAppSp", application_id=app.application_id ) # Assign the "TenantAdmin" role to the service principal for a specific tenant. app_role_assignment = azuread.AppRoleAssignment("adminRoleAssignment", app_role_id=pulumi.Output.all(app.app_roles).apply( lambda roles: next(role.id for role in roles if role.value == "TenantAdmin")), principal_object_id=service_principal.object_id, resource_object_id=app.object_id ) # Export the application id of the Azure AD application. pulumi.export("application_id", app.application_id)
Explanation of the Program:
-
AzureAD Application Creation: We begin by creating an Azure AD application (
azuread.Application
). When creating this application, we define the app roles withapp_roles
. Here, we define a single role called "TenantAdmin". This role will be assigned to users who need administrative privileges over a particular tenant within the multi-tenant SaaS application. -
Service Principal Creation: A service principal is created for the Azure AD application (
azuread.ServicePrincipal
). This represents the application's own identity, which can be assigned roles and can perform actions within Azure based on these roles. -
App Role Assignment: Next, we create an
azuread.AppRoleAssignment
to assign the "TenantAdmin" role to the service principal for a specific application. Since we have defined the roles when creating the application, we must retrieve the appropriate role ID dynamically. We do this by using a PulumiOutput.all()
combinator to iterate over theapp_roles
of the application and find the role with the value "TenantAdmin". Then, we use the discoveredrole_id
to create the role assignment. -
Exports: Finally, we export the
application_id
of the Azure AD application so that it can be used as needed, for example, in other parts of our infrastructure or application code.
By running this Pulumi program, you've set up a basic structure for managing dynamic client role assignments in a multi-tenant SaaS application using Azure AD. This allows for granular control over permissions, ensuring that users have only the access they need.