Managing Identity and Role Assignments in Pulumi with C#
TLDR
If you need to rename role assignment, rename identity too.
Otherwise deployment will fail with role already exists error as Pulumi will try to create new role before deleting old one.
This if DeleteBeforeReplace
is not already in state. If it is in state, role exists error may not happen.
If you need to rename identity name, rename Cosmos RBAC role assignments (e.g. DocumentDB.SqlResourceSqlRoleAssignment). Otherwise issues like “Updating SQL Role Assignment Principal ID is not permitted. You may only update the associated Role Definition.” are likely to happen.
Introduction
When working with infrastructure as code (IaC) tools like Pulumi, particularly when provisioning cloud resources in Azure, handling resource identities and their associated role assignments is critical. A common scenario arises when you need to rename either a resource’s identity or its role assignment. If not handled correctly, this can lead to errors that can disrupt your deployment process. This post will guide you through handling these situations using C# in Pulumi.
Problem Overview
In Azure, resources like databases, storage accounts, or virtual machines often have associated identities and role assignments. When renaming these, Pulumi may encounter issues if it tries to create new resources before deleting the old ones. This can lead to errors such as:
Role assignment already exists
: Occurs if Pulumi tries to create a new role assignment before deleting the old one.Updating SQL Role Assignment Principal ID is not permitted
: Occurs if Pulumi attempts to update certain properties of an existing Cosmos RBAC role assignment directly, which Azure does not allow.
Key Concepts
Before diving into code examples, let’s clarify a few key concepts:
- DeleteBeforeReplace: This is a Pulumi option that controls whether Pulumi should delete an existing resource before creating its replacement. When renaming resources, setting this option can help avoid conflicts.
- Role Assignments: These define the permissions for an identity over a particular scope (e.g., a resource group or a database). Azure does not allow modifying the
PrincipalId
(the identity) of an existing role assignment directly; instead, you must delete and recreate the assignment. - Identity: This can be a managed identity in Azure that is assigned to a resource. It is often tied to role assignments, which give it specific permissions.
Handling Renaming Scenarios
1. Renaming Role Assignment and Identity Simultaneously
If you need to rename both role assignment and its associated identity, you must be cautious. Pulumi’s default behavior might try to create the new role assignment before deleting the old one, leading to a “role already exists” error. To avoid this:
- Rename the role assignment: Make sure to rename the identity at the same time.
- Use
DeleteBeforeReplace
: Ensure that the old role assignment is deleted before the new one is created.
Here is how you can implement this in Pulumi using C#:
using Pulumi;
using Pulumi.AzureNative.Authorization;
using Pulumi.AzureNative.Authorization.Inputs;
using Pulumi.AzureNative.ManagedIdentity;
class MyStack : Stack
{
public MyStack()
{
var identity = new UserAssignedIdentity("newIdentity", new UserAssignedIdentityArgs
{
ResourceGroupName = "my-resource-group",
// Other identity properties
});
var roleAssignment = new RoleAssignment("newRoleAssignment", new RoleAssignmentArgs
{
PrincipalId = identity.PrincipalId,
RoleDefinitionId = "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/{roleDefinitionId}",
Scope = "/subscriptions/{subscriptionId}/resourceGroups/my-resource-group",
}, new CustomResourceOptions
{
DeleteBeforeReplace = true
});
}
}
In this example, DeleteBeforeReplace
is explicitly set to true
, ensuring that Pulumi deletes the old role assignment before creating the new one.
Note that DeleteBeforeReplace
needs to already be in Pulumi state for it to take effect. So a rename takes place in the same commit/revision when enabling DeleteBeforeReplace
, it won’t take effect.
2. Renaming Identity Without Renaming Role Assignments
If you only rename the identity but leave the role assignments unchanged, you can run into issues such as:
Updating SQL Role Assignment Principal ID is not permitted
: This error occurs because Azure does not allow direct updates to thePrincipalId
of a role assignment.
To avoid this, you must also rename the role assignment when renaming the identity:
using Pulumi;
using Pulumi.AzureNative.Authorization;
using Pulumi.AzureNative.Authorization.Inputs;
using Pulumi.AzureNative.ManagedIdentity;
class MyStack : Stack
{
public MyStack()
{
var identity = new UserAssignedIdentity("updatedIdentity", new UserAssignedIdentityArgs
{
ResourceGroupName = "my-resource-group",
// Other identity properties
});
// Role assignment must be renamed alongside the identity
var roleAssignment = new DocumentDB.SqlResourceSqlRoleAssignment("updatedRoleAssignment", new DocumentDB.SqlResourceSqlRoleAssignmentArgs
{
PrincipalId = identity.PrincipalId,
RoleDefinitionId = "/subscriptions/{subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/{roleDefinitionId}",
Scope = "/subscriptions/{subscriptionId}/resourceGroups/my-resource-group",
}, new CustomResourceOptions
{
DeleteBeforeReplace = true
});
}
}
Here, the role assignment is renamed to match the identity’s new name, and DeleteBeforeReplace
ensures that the transition happens smoothly without encountering errors.
Potential Pitfalls
- State File Considerations: If
DeleteBeforeReplace
is already in the state, you might not encounter the “role already exists” error because the resource will be replaced cleanly. However, always double-check your resource states and configurations, especially when working in a collaborative environment where the state might have been modified by others. - Resource Dependencies: Ensure that your Pulumi code correctly models dependencies between resources. For instance, role assignments should depend on the existence of the identity, which Pulumi typically handles, but it’s good practice to verify this.
Conclusion
Handling renaming of identities and role assignments in Pulumi requires careful planning to avoid common pitfalls. By using DeleteBeforeReplace
and ensuring that associated resources like role assignments are renamed together, you can avoid errors and ensure a smooth deployment process. Pulumi’s flexibility with C# allows you to manage these intricacies effectively, enabling reliable infrastructure provisioning in Azure.