CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-azure-mgmt-msi

Microsoft Azure Managed Service Identity Management Client Library for Python

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

system-assigned-identities.mddocs/

System-Assigned Identity Access

System-assigned managed identities are automatically created and managed by Azure services. Unlike user-assigned identities, system-assigned identities have a lifecycle tied to the Azure resource that creates them and cannot be shared across multiple resources. This capability provides read-only access to system-assigned identity information.

Capabilities

Retrieve System-Assigned Identity

Retrieves the system-assigned managed identity for a specific Azure resource by its scope (resource ID). This operation is read-only as system-assigned identities are managed by the Azure service itself.

def get_by_scope(
    scope: str,
    **kwargs
) -> SystemAssignedIdentity:
    """
    Get the system-assigned identity for a resource.

    Parameters:
    - scope (str): The resource scope (full Azure resource ID)
    - **kwargs: Additional request options

    Returns:
    SystemAssignedIdentity: The system-assigned identity resource

    Raises:
    ResourceNotFoundError: If resource has no system-assigned identity
    HttpResponseError: For other API errors
    """

Usage Examples:

from azure.mgmt.msi import ManagedServiceIdentityClient
from azure.identity import DefaultAzureCredential
from azure.core.exceptions import ResourceNotFoundError

client = ManagedServiceIdentityClient(
    credential=DefaultAzureCredential(),
    subscription_id="your-subscription-id"
)

# Get system-assigned identity for a Virtual Machine
vm_scope = (
    "subscriptions/12345678-1234-1234-1234-123456789012/"
    "resourceGroups/myResourceGroup/"
    "providers/Microsoft.Compute/virtualMachines/myVM"
)

try:
    vm_identity = client.system_assigned_identities.get_by_scope(scope=vm_scope)
    
    print(f"VM Identity found:")
    print(f"  Name: {vm_identity.name}")
    print(f"  Client ID: {vm_identity.client_id}")
    print(f"  Principal ID: {vm_identity.principal_id}")
    print(f"  Tenant ID: {vm_identity.tenant_id}")
    print(f"  Location: {vm_identity.location}")
    
except ResourceNotFoundError:
    print("VM does not have a system-assigned identity enabled")

# Get system-assigned identity for an App Service
app_service_scope = (
    "subscriptions/12345678-1234-1234-1234-123456789012/"
    "resourceGroups/myResourceGroup/"
    "providers/Microsoft.Web/sites/myAppService"
)

try:
    app_identity = client.system_assigned_identities.get_by_scope(scope=app_service_scope)
    
    print(f"App Service Identity:")
    print(f"  Client ID: {app_identity.client_id}")
    print(f"  Principal ID: {app_identity.principal_id}")
    
except ResourceNotFoundError:
    print("App Service does not have a system-assigned identity")

# Get system-assigned identity for Azure Functions
function_scope = (
    "subscriptions/12345678-1234-1234-1234-123456789012/"
    "resourceGroups/myResourceGroup/"
    "providers/Microsoft.Web/sites/myFunctionApp"
)

function_identity = client.system_assigned_identities.get_by_scope(scope=function_scope)

Advanced Usage Patterns

Bulk System Identity Discovery

def discover_system_identities(resource_scopes: list):
    """
    Discover system-assigned identities across multiple resources.
    
    Args:
        resource_scopes: List of Azure resource IDs to check
        
    Returns:
        dict: Mapping of resource names to identity information
    """
    identities = {}
    
    for scope in resource_scopes:
        # Extract resource name from scope for easier identification
        resource_name = scope.split('/')[-1]
        
        try:
            identity = client.system_assigned_identities.get_by_scope(scope=scope)
            
            identities[resource_name] = {
                "has_identity": True,
                "client_id": identity.client_id,
                "principal_id": identity.principal_id,
                "tenant_id": identity.tenant_id,
                "location": identity.location,
                "scope": scope
            }
            
        except ResourceNotFoundError:
            identities[resource_name] = {
                "has_identity": False,
                "scope": scope
            }
        except Exception as e:
            identities[resource_name] = {
                "has_identity": False,
                "error": str(e),
                "scope": scope
            }
    
    return identities

# Example: Check multiple VMs for system-assigned identities
vm_scopes = [
    "subscriptions/sub-id/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm1",
    "subscriptions/sub-id/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm2",
    "subscriptions/sub-id/resourceGroups/rg2/providers/Microsoft.Compute/virtualMachines/vm3"
]

identity_report = discover_system_identities(vm_scopes)

print("System Identity Discovery Report:")
for resource, info in identity_report.items():
    if info["has_identity"]:
        print(f"✓ {resource}: {info['client_id']}")
    else:
        print(f"✗ {resource}: No system identity")

Identity Information Export

def export_system_identity_info(scope: str, export_format: str = "dict"):
    """
    Export system-assigned identity information in various formats.
    
    Args:
        scope: Azure resource scope
        export_format: Output format ('dict', 'json', 'env')
        
    Returns:
        Formatted identity information
    """
    try:
        identity = client.system_assigned_identities.get_by_scope(scope=scope)
        
        identity_info = {
            "resource_id": identity.id,
            "name": identity.name,
            "type": identity.type,
            "client_id": identity.client_id,
            "principal_id": identity.principal_id,
            "tenant_id": identity.tenant_id,
            "location": identity.location
        }
        
        if export_format == "json":
            import json
            return json.dumps(identity_info, indent=2)
        
        elif export_format == "env":
            resource_name = scope.split('/')[-1].upper().replace('-', '_')
            return f"""
# System-assigned identity for {scope.split('/')[-1]}
{resource_name}_CLIENT_ID={identity.client_id}
{resource_name}_PRINCIPAL_ID={identity.principal_id}
{resource_name}_TENANT_ID={identity.tenant_id}
""".strip()
        
        else:  # dict format
            return identity_info
            
    except ResourceNotFoundError:
        return None

# Export VM identity as environment variables
vm_scope = "subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/myvm"
env_vars = export_system_identity_info(vm_scope, "env")
if env_vars:
    print(env_vars)

Resource Type-Specific Helpers

def get_vm_system_identity(subscription_id: str, resource_group: str, vm_name: str):
    """Get system-assigned identity for a Virtual Machine."""
    scope = f"subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Compute/virtualMachines/{vm_name}"
    return client.system_assigned_identities.get_by_scope(scope=scope)

def get_app_service_system_identity(subscription_id: str, resource_group: str, app_name: str):
    """Get system-assigned identity for an App Service."""
    scope = f"subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/sites/{app_name}"
    return client.system_assigned_identities.get_by_scope(scope=scope)

def get_function_app_system_identity(subscription_id: str, resource_group: str, function_name: str):
    """Get system-assigned identity for Azure Functions."""
    scope = f"subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Web/sites/{function_name}"
    return client.system_assigned_identities.get_by_scope(scope=scope)

def get_storage_account_system_identity(subscription_id: str, resource_group: str, storage_name: str):
    """Get system-assigned identity for a Storage Account."""
    scope = f"subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Storage/storageAccounts/{storage_name}"
    return client.system_assigned_identities.get_by_scope(scope=scope)

# Usage examples
subscription_id = "12345678-1234-1234-1234-123456789012"

# Get VM identity
vm_identity = get_vm_system_identity(subscription_id, "myResourceGroup", "myVM")
print(f"VM Identity Client ID: {vm_identity.client_id}")

# Get App Service identity  
app_identity = get_app_service_system_identity(subscription_id, "myResourceGroup", "myApp")
print(f"App Identity Principal ID: {app_identity.principal_id}")

Integration with Azure RBAC

def create_system_identity_rbac_assignment(
    scope: str,
    role_definition_id: str,
    target_scope: str
):
    """
    Helper to prepare RBAC assignment for system-assigned identity.
    Note: This prepares the data - actual RBAC assignment requires azure-mgmt-authorization.
    """
    try:
        identity = client.system_assigned_identities.get_by_scope(scope=scope)
        
        # Prepare RBAC assignment parameters
        rbac_assignment = {
            "principal_id": identity.principal_id,
            "principal_type": "ServicePrincipal",
            "role_definition_id": role_definition_id,
            "scope": target_scope,
            "description": f"System identity access for {scope.split('/')[-1]}"
        }
        
        return rbac_assignment
        
    except ResourceNotFoundError:
        raise ValueError(f"Resource at scope {scope} does not have system-assigned identity")

# Example: Prepare RBAC assignment for VM to access Key Vault
vm_scope = "subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/myvm"
key_vault_scope = "subscriptions/sub-id/resourceGroups/rg/providers/Microsoft.KeyVault/vaults/myvault"
reader_role = "subscriptions/sub-id/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6"

rbac_params = create_system_identity_rbac_assignment(
    scope=vm_scope,
    role_definition_id=reader_role,
    target_scope=key_vault_scope
)

print(f"RBAC assignment prepared for principal: {rbac_params['principal_id']}")

Common Resource Scope Patterns

System-assigned identities are available for various Azure resource types. Here are common scope patterns:

Virtual Machines

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Compute/virtualMachines/{vm-name}

App Services

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/sites/{app-name}

Azure Functions

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/sites/{function-name}

Storage Accounts

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-name}

Key Vault

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/vaults/{vault-name}

Container Instances

subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.ContainerInstance/containerGroups/{container-name}

Types

class SystemAssignedIdentity:
    """System-assigned managed identity resource (extends ProxyResource)."""
    # Read-only properties (all properties are read-only for system-assigned identities)
    id: str                    # Full Azure resource ID
    name: str                  # Resource name (matches the parent resource)
    type: str                  # Resource type (Microsoft.ManagedIdentity/systemAssignedIdentities)
    system_data: SystemData    # ARM metadata (creation/modification info)
    location: str              # Azure region (matches parent resource location)
    tags: Dict[str, str]       # Resource tags (matches parent resource tags)
    tenant_id: str            # Azure tenant ID where identity is created
    principal_id: str         # Service principal object ID in Azure AD
    client_id: str            # Application (client) ID for the identity
    client_secret_url: str    # ManagedServiceIdentity DataPlane URL for token requests

Error Handling

from azure.core.exceptions import ResourceNotFoundError, HttpResponseError

def safe_get_system_identity(scope: str):
    """Safely retrieve system-assigned identity with error handling."""
    try:
        return client.system_assigned_identities.get_by_scope(scope=scope)
    
    except ResourceNotFoundError:
        print(f"No system-assigned identity found for resource: {scope}")
        return None
    
    except HttpResponseError as e:
        if e.status_code == 403:
            print(f"Access denied - insufficient permissions to read identity for: {scope}")
        elif e.status_code == 404:
            print(f"Resource not found: {scope}")
        else:
            print(f"HTTP error {e.status_code}: {e.message}")
        return None
    
    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

Install with Tessl CLI

npx tessl i tessl/pypi-azure-mgmt-msi

docs

federated-identity-credentials.md

index.md

system-assigned-identities.md

user-assigned-identities.md

tile.json