Adding Least-Privilege RBAC to an Azure AI Foundry POC with Bicep and Azure DevOps

Series: Azure AI-103 infrastructure POC with Bicep, Azure DevOps, and Microsoft Foundry

In the previous phases of this Azure AI infrastructure POC, I focused on deploying the platform foundation: a resource group, Azure AI Services, a Microsoft Foundry project,  Azure AI Search, Application Insights, Storage and also a model deployments + basic model smoke test from Azure DevOpsmodel deployments + basic model smoke test from Azure DevOps.

That proved that the infrastructure could be deployed and that a deployed model could be called successfully.

The next step is access control.

For an Azure AI platform, especially one that may later support agents, RAG, model deployments, indexing pipelines, and application runtimes, RBAC cannot be an afterthought. It needs to be planned, defined, reviewed, and deployed in the same repeatable way as the infrastructure itself.

This post covers how I added a dedicated RBAC layer to the POC using:

  • Microsoft Entra security groups
  • JSON configuration files
  • Microsoft Learn-verified Azure role IDs
  • Bicep role assignments
  • Azure DevOps step templates
  • least-privilege scope design

The result is a more realistic Azure AI platform deployment pattern, and it also maps directly to the AI-103 exam focus on planning, managing, securing, monitoring, and operationalising Azure AI solutions.

How This Fits AI-103 exam objectives

The official AI-103 study guide describes the target candidate as an Azure AI engineer who builds, manages, and deploys agents and AI solutions that use Microsoft Foundry. It also says the role collaborates with DevOps engineers and cloud security engineers to design, implement, and maintain AI solutions.

The study guide lists Plan and manage an Azure AI solution as 25–30% of the exam. Under that area, it includes designing Azure infrastructure for AI apps and agents, configuring model and agent deployments, integrating Foundry projects with CI/CD pipelines, monitoring model/search/ingestion quality, and configuring security including managed identity, private networking, keyless credentials, and role policies.

AI-103 objective areaHow this RBAC phase supports it
Plan and manage an Azure AI solution Defines a practical access model for Foundry, model access, Azure AI Search, Storage, and monitoring.
Set up AI solutions in Foundry Adds repeatable access control around Foundry resources deployed through Bicep and Azure DevOps.
Integrate Foundry projects with CI/CD pipelines Moves RBAC from manual portal configuration into the Azure DevOps deployment flow.
Manage, monitor, and secure AI systems Applies security groups, role assignments, least privilege, and scoped access to AI resources.
Build retrieval and grounding pipelines Uses Azure AI Search data roles to separate index writers from index readers.
Optimize and operationalize generative AI systems Makes access control repeatable, auditable, and aligned with infrastructure-as-code practices.

RBAC Best Practices Used

The RBAC design follows four Microsoft Learn best practices that matter in real Azure environments:

Best practiceHow I applied it in the POC
Grant least privilege Different groups receive different roles depending on whether they administer Foundry, call model deployments, write search indexes, read search indexes, read secrets, or view monitoring data.
Assign roles to groups, not users Users are managed through Microsoft Entra groups. Azure role assignments target groups instead of individual user accounts.
Use role IDs in automation The JSON config remains readable with friendly role names, but the pipeline maps role names to stable built-in role definition IDs before deploying Bicep.
Use narrow scopes Roles are assigned at the AI Services account, Search service, Storage account, Application Insights component, or resource group scope instead of the subscription where possible.

This explains why many production environments use a role mapping file. Humans prefer readable names such as Foundry User. Automation should use stable role IDs such as 53ca6127-db72-4b80-b1b0-d745d6d5456d.

Repository Structure Added for RBAC

I kept the RBAC implementation separate from the main infrastructure deployment. The main Bicep template deploys the AI platform resources. The RBAC deployment assigns access after those resources exist.

Infra
├── Bicep
│   └── role_assignments.bicep
├── Rbac
│   ├── security-groups.json
│   ├── azure-role-map.json
│   └── role-assignments.json
└── Steps
    ├── step-create-security-groups.yml
    └── step-assign-rbac.yml

This separation keeps the pipeline easier to troubleshoot and makes it clear that access control is a distinct platform concern.

Security Groups Used in the POC

The groups follow the same naming convention used elsewhere in the POC:

#{EnvCode}#-#{ZoneCode}#-ai-<purpose>

For the development environment, this creates names such as:

dev-poc-ai-foundry-owners
dev-poc-ai-foundry-project-managers
dev-poc-ai-foundry-users
Security group Purpose Typical role Typical scope
dev-poc-ai-foundry-owners Administrators for the Foundry account and Foundry projects. Foundry Owner Azure AI Services account / Foundry resource scope
dev-poc-ai-foundry-project-managers Delegated users who can manage Foundry projects and support project-level access management. Foundry Project Manager Azure AI Services account / Foundry resource scope
dev-poc-ai-foundry-users Users who work inside Foundry projects. Foundry User Foundry project scope, or Azure AI Services account / Foundry resource scope for this simplified POC

Verified Role Map for Common AI-103 / Foundry Study Scenarios

The following role IDs were checked against Microsoft Learn built-in role documentation. For this phase of the POC, I would keep only the Foundry-specific roles in Infra/Rbac/azure-role-map.json.

{
  "Foundry Owner": "c883944f-8b7b-4483-af10-35834be79c4a",
  "Foundry Project Manager": "eadc314b-1a2d-4efa-be10-5d325db5065e",
  "Foundry User": "53ca6127-db72-4b80-b1b0-d745d6d5456d"
}

Important note about Azure AI Developer and Cognitive Services roles

Azure AI Developer and Cognitive Services roles may appear during study, in the Azure portal, or in older examples. However, for this Foundry project POC, I would not use them as the main project-access roles. Microsoft’s Foundry RBAC guidance says that for Foundry project access, use Foundry-specific roles such as Foundry User, Foundry Project Manager, or Foundry Owner instead.

Roles such as Cognitive Services OpenAI User, Search Index Data Contributor, Storage Blob Data Contributor, and Monitoring Reader may still be useful later, but they belong to separate runtime, RAG, storage, or observability scenarios. They are intentionally not included in this Foundry-only RBAC section.

Most Relevant Roles by Scenario

Recommended Role Assignments for This POC

For this AI-103 POC, I would keep the active role assignment list smaller than the full role map. The map can include many verified roles for future phases, but the actual assignment config should only assign what the environment needs right now.

For Microsoft Foundry-specific permissions, I used the official Microsoft Foundry RBAC guidance as the reference point, rather than assigning broad permissions by default.

The important point is that this section is focused on Foundry access only. Other roles, such as Azure AI Search, Storage, Key Vault, Monitoring, or direct Cognitive Services roles, may still be useful later, but they belong to separate runtime, RAG, observability, or application access scenarios.

Scenario Most relevant role Role ID Why it matters
Full administration of Foundry projects/accounts Foundry Owner c883944f-8b7b-4483-af10-35834be79c4a Grants full access to manage Foundry projects and resources, build and develop in projects, manage models, publish agents, and conditionally assign selected roles.
Delegated Foundry project manager Foundry Project Manager eadc314b-1a2d-4efa-be10-5d325db5065e Can perform project management and development actions, and can assign the Foundry User role through a constrained role assignment condition.
Normal Foundry project user Foundry User 53ca6127-db72-4b80-b1b0-d745d6d5456d Provides least-privilege access for users who need to work with Foundry projects and perform project data actions without managing the platform.

For this POC, I would start with three Entra ID groups. This keeps the access model easy to understand while still separating platform ownership, delegated project management, and normal project usage.

[
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-foundry-owners",
    "principalType": "Group",
    "roleName": "Foundry Owner",
    "scopeType": "AiServices"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-foundry-project-managers",
    "principalType": "Group",
    "roleName": "Foundry Project Manager",
    "scopeType": "AiServices"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-foundry-users",
    "principalType": "Group",
    "roleName": "Foundry User",
    "scopeType": "AiServices"
  }
]

I intentionally removed the non-Foundry roles from the active assignment example. Roles such as Cognitive Services OpenAI User, Search Index Data Contributor, Search Index Data Reader, Storage Blob Data Contributor, Key Vault Secrets User, and Monitoring Reader can still exist in the broader role map, but they should only be assigned when the POC moves into those specific scenarios.

This keeps the current RBAC configuration aligned with the purpose of this phase: controlling access to the Microsoft Foundry project without over-permissioning the environment.

Bicep Role Assignments

The RBAC Bicep template receives role assignments grouped by scope. This avoids hardcoding every role assignment as a separate Bicep resource and keeps the template reusable.

The key part is the deterministic role assignment name:

name: guid(aiServices.id, assignment.principalId, assignment.roleDefinitionId)

This matters because role assignment resources need stable names for repeatable deployments. The Microsoft Learn role assignment template documentation shows the use of Microsoft.Authorization/roleAssignments with API version 2022-04-01, and it explains that role assignments need the target principal object ID and role definition ID.

For new service principals or managed identities, Microsoft also notes that principalType should be specified to reduce replication-delay issues. Even though this POC is currently using groups, including principalType is still a good habit.

Azure DevOps Flow

The RBAC steps run after the main infrastructure deployment and only in the main region, because the Azure AI Services account and Foundry project are created only in the main region in this POC.

Deploy Bicep infrastructure
  ↓
Create or validate Entra security groups
  ↓
Resolve role assignment config and role map
  ↓
Deploy RBAC assignments with Bicep
  ↓
Show Azure AI endpoints
  ↓
Run model smoke test

The RBAC assignment step uses a DRY PowerShell structure with helper functions for token replacement, file validation, role definition ID lookup from the map, principal object ID resolution, assignment object creation, and scope bucket routing.

Pipeline Permission Requirements

There is an important permissions distinction here:

OperationPermission areaTypical requirement
Create Azure role assignments Azure RBAC Microsoft.Authorization/roleAssignments/write, typically through Role Based Access Control Administrator or User Access Administrator.
Read or create Entra groups Microsoft Entra ID Directory permissions to read groups and create groups.
Deploy Azure AI resources Azure Resource Manager Contributor or a narrower custom/platform deployment role, depending on the resource scope.

In my testing, the service connection could deploy Azure resources but failed to query Entra groups. That is expected if the pipeline identity does not have the required Entra directory permissions.

For a production-style pattern, I would normally separate this into two flows:

FlowResponsibility
Identity bootstrap Create or manage Microsoft Entra security groups.
Platform deployment Assign approved groups to Azure resource roles.

What I Would Expect to See in AI-103 Study Questions

I would not expect AI-103 to ask for every role ID from memory. However, I would expect scenario-style questions around choosing the right role and the right scope.

Possible study scenarioLikely answer pattern
A developer needs to work in a Foundry project but should not administer the account. Use Foundry User, not subscription Contributor.
A platform admin needs to manage Foundry project/account access. Use Foundry Owner or Foundry Project Manager, scoped to the Foundry/AI resource where possible.
An application identity only needs to call a deployed GPT model. Use Cognitive Services OpenAI User, scoped to the AI Services/OpenAI resource.
An ingestion process needs to write documents into an Azure AI Search index. Use Search Index Data Contributor, scoped to the Search service or index-related scope.
An app only needs to query Azure AI Search index data. Use Search Index Data Reader.
A runtime identity needs to read source documents from Storage. Use Storage Blob Data Reader if read-only is enough; use Contributor only when write/delete is required.
An operator only needs to view logs and metrics. Use Monitoring Reader, not Contributor.

Lessons Learned

1. RBAC is part of platform design

Access control affects naming, deployment order, pipeline permissions, group design, and operational handover. It should be added early, not after the platform is already in use.

2. Foundry roles matter

For new Microsoft Foundry project access, the Foundry-specific roles are the ones to understand first: Foundry Owner, Foundry Project Manager, and Foundry User.

3. Azure AI Developer can be misleading

The portal may show Azure AI Developer, but Microsoft’s role description says to use Foundry User or Foundry Owner for Foundry project access.

4. Role names are for humans; role IDs are for pipelines

A role map gives both readability and stable automation. This is why using azure-role-map.json is a sensible production-style pattern.

5. Azure permissions and Entra permissions are different

A service connection can have permission to deploy Azure resources while still being unable to query or create Entra groups.

Final Thoughts

This RBAC phase made the Azure AI Foundry POC feel much closer to a real platform deployment.

The POC now has:

  • Azure AI infrastructure deployed through Bicep,
  • Foundry project deployment,
  • model deployment automation,
  • model smoke testing from Azure DevOps,
  • security group configuration,
  • verified Azure role ID mapping,
  • Bicep-based Azure RBAC assignments,
  • least-privilege access patterns for common AI platform roles.

The most important improvement is that access control is no longer a portal-click task. It is part of the delivery model.

For AI-103 study, this is useful because it connects Microsoft Foundry, Azure AI Search, model deployment, CI/CD, monitoring, and security into one practical implementation. That is much closer to how the exam objectives describe the Azure AI engineer role than simply deploying a model and calling an endpoint.

References