|
14 | 14 |
|
15 | 15 | Before running the sample: |
16 | 16 |
|
17 | | - pip install azure-ai-projects azure-identity azure-ai-projects>=2.0.0b1 python-dotenv |
| 17 | + pip install azure-ai-projects azure-identity azure-ai-projects>=2.0.0b1 python-dotenv azure-mgmt-authorization azure-mgmt-resource |
18 | 18 |
|
19 | 19 | Set these environment variables with your own values: |
20 | 20 | 1) AZURE_AI_PROJECT_ENDPOINT - Required. The Azure AI Project endpoint, as found in the overview page of your |
21 | 21 | Azure AI Foundry project. It has the form: https://<account_name>.services.ai.azure.com/api/projects/<project_name>. |
22 | | - 2) DATASET_NAME - Optional. The name of the Dataset to create and use in this sample. |
23 | | - 3) DATASET_VERSION - Optional. The version of the Dataset to create and use in this sample. |
24 | | - 4) DATA_FOLDER - Optional. The folder path where the data files for upload are located. |
25 | | - 5) AGENT_NAME - Required. The name of the Agent to perform red teaming evaluation on. |
| 22 | + 2) AZURE_SUBSCRIPTION_ID - Required for RBAC assignment. The Azure subscription ID where the project is located. |
| 23 | + 3) AZURE_RESOURCE_GROUP_NAME - Required for RBAC assignment. The resource group name where the project is located. |
| 24 | + 4) DATASET_NAME - Optional. The name of the Dataset to create and use in this sample. |
| 25 | + 5) DATASET_VERSION - Optional. The version of the Dataset to create and use in this sample. |
| 26 | + 6) DATA_FOLDER - Optional. The folder path where the data files for upload are located. |
| 27 | + 7) AGENT_NAME - Required. The name of the Agent to perform red teaming evaluation on. |
26 | 28 | """ |
27 | 29 |
|
28 | 30 | from datetime import datetime |
|
32 | 34 | from pprint import pprint |
33 | 35 | from azure.identity import DefaultAzureCredential |
34 | 36 | from azure.ai.projects import AIProjectClient |
| 37 | +from azure.mgmt.authorization import AuthorizationManagementClient |
| 38 | +from azure.mgmt.resource import ResourceManagementClient |
| 39 | +import uuid |
35 | 40 | from azure.ai.projects.models import ( |
36 | 41 | AgentVersionObject, |
37 | 42 | EvaluationTaxonomy, |
|
53 | 58 |
|
54 | 59 |
|
55 | 60 | def main() -> None: |
| 61 | + print("Assigning RBAC permissions...") |
| 62 | + assign_rbac() |
56 | 63 | print("Scheduling Dataset based Evaluation...") |
57 | 64 | schedule_dataset_evaluation() |
58 | 65 | print("Scheduling RedTeam based Evaluation...") |
59 | 66 | schedule_redteam_evaluation() |
60 | 67 |
|
| 68 | +def assign_rbac(): |
| 69 | + """ |
| 70 | + Assign the "Azure AI User" role to the Azure AI Foundry project's Managed Identity. |
| 71 | + """ |
| 72 | + load_dotenv() |
| 73 | + |
| 74 | + endpoint = os.environ.get("AZURE_AI_PROJECT_ENDPOINT", "") |
| 75 | + subscription_id = os.environ.get("AZURE_SUBSCRIPTION_ID", "") |
| 76 | + resource_group_name = os.environ.get("AZURE_RESOURCE_GROUP_NAME", "") |
| 77 | + |
| 78 | + if not endpoint or not subscription_id or not resource_group_name: |
| 79 | + print("Error: AZURE_AI_PROJECT_ENDPOINT, AZURE_SUBSCRIPTION_ID, and AZURE_RESOURCE_GROUP_NAME environment variables are required") |
| 80 | + return |
| 81 | + |
| 82 | + # Parse project information from the endpoint |
| 83 | + # Format: https://<account_name>.services.ai.azure.com/api/projects/<project_name> |
| 84 | + try: |
| 85 | + import re |
| 86 | + pattern = r"https://(.+)\.services\.ai\.azure\.com/api/projects/(.+)" |
| 87 | + match = re.match(pattern, endpoint) |
| 88 | + if not match: |
| 89 | + print("Error: Invalid project endpoint format") |
| 90 | + return |
| 91 | + account_name = match.group(1) |
| 92 | + project_name = match.group(2) |
| 93 | + except Exception as e: |
| 94 | + print(f"Error parsing endpoint: {e}") |
| 95 | + return |
| 96 | + |
| 97 | + with DefaultAzureCredential() as credential: |
| 98 | + # Initialize clients |
| 99 | + auth_client = AuthorizationManagementClient(credential, subscription_id) |
| 100 | + resource_client = ResourceManagementClient(credential, subscription_id) |
| 101 | + |
| 102 | + try: |
| 103 | + # Get the AI Foundry project resource |
| 104 | + # Based on resource ID pattern: /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.CognitiveServices/accounts/{account}/projects/{project} |
| 105 | + |
| 106 | + # Try to find the resource group and project |
| 107 | + print(f"Searching for project: {project_name} under account: {account_name} in resource group: {resource_group_name}") |
| 108 | + |
| 109 | + # Get the project's managed identity principal ID |
| 110 | + try: |
| 111 | + # Get the AI project resource |
| 112 | + project_resource = resource_client.resources.get( |
| 113 | + resource_group_name=resource_group_name, |
| 114 | + resource_provider_namespace="Microsoft.CognitiveServices", |
| 115 | + parent_resource_path=f"accounts/{account_name}", |
| 116 | + resource_type="projects", |
| 117 | + resource_name=project_name, |
| 118 | + api_version="2025-06-01" |
| 119 | + ) |
| 120 | + |
| 121 | + # Extract the managed identity principal ID |
| 122 | + if project_resource.identity and project_resource.identity.principal_id: |
| 123 | + principal_id = project_resource.identity.principal_id |
| 124 | + print(f"Found project managed identity principal ID: {principal_id}") |
| 125 | + else: |
| 126 | + print("Error: Project does not have a managed identity enabled") |
| 127 | + return |
| 128 | + |
| 129 | + except Exception as e: |
| 130 | + print(f"Error retrieving project resource: {e}") |
| 131 | + return |
| 132 | + |
| 133 | + # Define the Azure AI User role definition ID |
| 134 | + # This is the built-in role ID for "Azure AI User" |
| 135 | + azure_ai_user_role_id = "64702f94-c441-49e6-a78b-ef80e0188fee" |
| 136 | + |
| 137 | + # Create the scope (project level) |
| 138 | + scope = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.CognitiveServices/accounts/{account_name}/projects/{project_name}" |
| 139 | + |
| 140 | + # Create role assignment |
| 141 | + role_assignment_name = str(uuid.uuid4()) |
| 142 | + |
| 143 | + print(f"Assigning 'Azure AI User' role to managed identity...") |
| 144 | + |
| 145 | + role_assignment = auth_client.role_assignments.create( |
| 146 | + scope=scope, |
| 147 | + role_assignment_name=role_assignment_name, |
| 148 | + parameters={ |
| 149 | + "role_definition_id": f"{scope}/providers/Microsoft.Authorization/roleDefinitions/{azure_ai_user_role_id}", |
| 150 | + "principal_id": principal_id, |
| 151 | + "principal_type": "ServicePrincipal" |
| 152 | + } |
| 153 | + ) |
| 154 | + |
| 155 | + print(f"Successfully assigned 'Azure AI User' role to project managed identity") |
| 156 | + print(f"Role assignment ID: {role_assignment.name}") |
| 157 | + |
| 158 | + except Exception as e: |
| 159 | + print(f"Error during role assignment: {e}") |
| 160 | + |
| 161 | + # Check for specific error types and provide helpful guidance |
| 162 | + error_message = str(e) |
| 163 | + if "AuthorizationFailed" in error_message: |
| 164 | + print("\n🔒 AUTHORIZATION ERROR:") |
| 165 | + print("You don't have sufficient permissions to assign roles at this scope.") |
| 166 | + print("\n📋 REQUIRED PERMISSIONS:") |
| 167 | + print("To assign roles, you need one of the following roles:") |
| 168 | + print(" • Owner - Full access including role assignments") |
| 169 | + print(" • User Access Administrator - Can manage user access to Azure resources") |
| 170 | + print(" • Custom role with 'Microsoft.Authorization/roleAssignments/write' permission") |
| 171 | + print("\n🎯 SCOPE:") |
| 172 | + project_scope = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.CognitiveServices/accounts/{account_name}/projects/{project_name}" |
| 173 | + print(f" Resource: {project_scope}") |
| 174 | + print("\n💡 SOLUTIONS:") |
| 175 | + print("1. Ask your Azure administrator to grant you 'Owner' or 'User Access Administrator' role") |
| 176 | + print("2. Ask your admin to assign the 'Azure AI User' role to the project's managed identity") |
| 177 | + print("3. Run this script with an account that has the required permissions") |
| 178 | + print("4. If you recently got permissions, try refreshing your credentials:") |
| 179 | + print(" - Run 'az logout && az login' in Azure CLI") |
| 180 | + print(" - Or restart this application") |
| 181 | + raise |
| 182 | + |
| 183 | + elif "RoleAssignmentExists" in error_message: |
| 184 | + print("\n✅ ROLE ASSIGNMENT ALREADY EXISTS:") |
| 185 | + print("The 'Azure AI User' role is already assigned to the project's managed identity.") |
| 186 | + print("No action needed - the required permissions are already in place.") |
| 187 | + |
| 188 | + elif "InvalidResourceTypeNameFormat" in error_message: |
| 189 | + print("\n🔧 RESOURCE FORMAT ERROR:") |
| 190 | + print("The resource path format is incorrect. Please check:") |
| 191 | + print(" • Resource group name is correct") |
| 192 | + print(" • Project endpoint format matches expected pattern") |
| 193 | + print(" • Account and project names are properly extracted") |
| 194 | + raise ValueError("Invalid resource type name format") |
| 195 | + |
| 196 | + elif "NoRegisteredProviderFound" in error_message: |
| 197 | + print("\n🌐 API VERSION ERROR:") |
| 198 | + print("The API version or resource type is not supported in this region.") |
| 199 | + print("This usually indicates a service availability issue.") |
| 200 | + |
| 201 | + else: |
| 202 | + print(f"\n❌ UNEXPECTED ERROR:") |
| 203 | + print("An unexpected error occurred. Please check the error details above.") |
| 204 | + raise |
61 | 205 |
|
62 | 206 | def schedule_dataset_evaluation() -> None: |
63 | 207 | endpoint = os.environ[ |
|
0 commit comments