Adding a dedicated RBAC layer to my Azure AI-103 infrastructure POC using Bicep, Azure DevOps, Microsoft Entra groups, and least-privilege role assignments.

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 model deployments with a 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:

At this stage of the POC, the RBAC configuration still includes both Foundry access groups and supporting runtime groups for model access, RAG, storage, and monitoring. However, for the Foundry-specific part of the design, the important roles are Foundry Owner and Foundry User.

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

For the development environment, this creates names such as:

dev-poc-ai-foundry-admins
dev-poc-ai-foundry-users
dev-poc-ai-model-users
dev-poc-ai-rag-indexers
dev-poc-ai-rag-readers
dev-poc-ai-storage-contributors
dev-poc-ai-monitor-readers
Security groupPurposeTypical roleTypical scope
dev-poc-ai-foundry-admins Administrators for the Foundry account and Foundry projects. Foundry Owner Azure AI Services account / Foundry resource scope
dev-poc-ai-foundry-users Users who work inside Foundry projects. Foundry User Azure AI Services account / Foundry resource scope
dev-poc-ai-model-users Users or identities that call model deployments directly. Cognitive Services OpenAI User Azure AI Services account
dev-poc-ai-rag-indexers Users or identities that write documents to Azure AI Search indexes. Search Index Data Contributor Azure AI Search service
dev-poc-ai-rag-readers Users or identities that query Azure AI Search index data. Search Index Data Reader Azure AI Search service
dev-poc-ai-storage-contributors Users or identities that upload or manage source documents. Storage Blob Data Contributor Storage account
dev-poc-ai-monitor-readers Operations users who need read access to logs and metrics. Monitoring Reader Resource group

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

The following role IDs were checked against Microsoft Learn built-in role documentation. In this POC, I keep the role map broader than the Foundry-only access model because later phases may need runtime, RAG, storage, and monitoring permissions. The active Foundry project-access roles remain deliberately small, but the map can safely include other verified roles for future use.

{
  "Foundry Owner": "c883944f-8b7b-4483-af10-35834be79c4a",
  "Foundry User": "53ca6127-db72-4b80-b1b0-d745d6d5456d",
  "Cognitive Services OpenAI User": "5e0bd9bd-7b93-4f28-af87-19fc36ad61bd",
  "Search Index Data Contributor": "8ebe5a00-799e-43f5-93ac-243d3dce84a7",
  "Search Index Data Reader": "1407120a-92aa-4202-b7e9-c0e197c71c8f",
  "Storage Blob Data Contributor": "ba92f5b4-2d11-453d-a403-e96b0029c9fe",
  "Monitoring Reader": "43d0d8ad-25c7-4714-9337-8ba259a9fe05"
}

Important note about Azure AI Developer, Cognitive Services, and Azure OpenAI 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 treat them as the main project-access roles. Microsoft’s current Foundry RBAC guidance recommends using Foundry-specific roles for Foundry project access, such as Foundry User, Foundry Project Manager, or Foundry Owner.

This distinction matters because Foundry project access and Azure OpenAI service access are not always the same thing. Foundry roles are used to control what a user can do inside a Foundry account or project, such as working with projects, assets, models, agents, and related Foundry resources. Azure OpenAI and Cognitive Services roles are more relevant when access is required directly against the Azure OpenAI or Azure AI Services resource itself.

For example, Cognitive Services OpenAI User is commonly used when an identity needs to call Azure OpenAI models, such as sending prompts to a deployed model endpoint. Cognitive Services OpenAI Contributor is more privileged and is generally used when an identity needs broader Azure OpenAI management capabilities, such as working with deployments or service-level configuration. These roles should normally be scoped carefully to the specific Azure OpenAI or Azure AI Services resource rather than assigned broadly at the subscription or resource group level.

In a real solution, these Azure OpenAI roles may be combined with other service-specific roles depending on the architecture. For example, a RAG solution may also require Search Index Data Reader or Search Index Data Contributor for Azure AI Search, Storage Blob Data Reader or Storage Blob Data Contributor for storage-backed content, and Monitoring Reader or Log Analytics roles for observability.

For this reason, I keep the Foundry project-access roles conceptually separate from runtime and supporting-service roles. The Foundry access model focuses on who can access and manage the Foundry project, while Azure OpenAI, Search, Storage, and Monitoring roles support later runtime, RAG ingestion, data access, and operational monitoring scenarios.

Recommended Role Assignments for This POC

For this POC, I started with a broader but still structured set of Entra ID groups. The Foundry access model is intentionally small, with separate groups for Foundry administrators and Foundry users. The same RBAC configuration also includes supporting groups for model access, RAG indexing, RAG querying, storage-backed content, and monitoring.

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 treats Foundry access as the starting point, but the current POC also includes supporting runtime roles for model access, Azure AI Search, Storage, and monitoring. Those roles are separated by group and scope so they can be reviewed, removed, or expanded independently as the POC evolves.

ScenarioMost relevant roleRole IDWhy 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.
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.
Direct model access Cognitive Services OpenAI User 5e0bd9bd-7b93-4f28-af87-19fc36ad61bd Useful when a user or identity needs to call deployed Azure OpenAI / Azure AI Services model endpoints directly.
RAG indexing Search Index Data Contributor 8ebe5a00-799e-43f5-93ac-243d3dce84a7 Allows an ingestion identity to upload, update, or delete documents in Azure AI Search indexes.
RAG querying Search Index Data Reader 1407120a-92aa-4202-b7e9-c0e197c71c8f Allows query-only access to Azure AI Search index data.
Storage-backed source content Storage Blob Data Contributor ba92f5b4-2d11-453d-a403-e96b0029c9fe Allows upload and management of source documents stored in Azure Storage.
Monitoring read access Monitoring Reader 43d0d8ad-25c7-4714-9337-8ba259a9fe05 Allows operations users to view monitoring data without giving them contributor access.

The active assignment configuration currently looks like this:

[
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-foundry-admins",
    "principalType": "Group",
    "roleName": "Foundry Owner",
    "scopeType": "AiServices"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-foundry-users",
    "principalType": "Group",
    "roleName": "Foundry User",
    "scopeType": "AiServices"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-model-users",
    "principalType": "Group",
    "roleName": "Cognitive Services OpenAI User",
    "scopeType": "AiServices"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-rag-indexers",
    "principalType": "Group",
    "roleName": "Search Index Data Contributor",
    "scopeType": "SearchService"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-rag-readers",
    "principalType": "Group",
    "roleName": "Search Index Data Reader",
    "scopeType": "SearchService"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-storage-contributors",
    "principalType": "Group",
    "roleName": "Storage Blob Data Contributor",
    "scopeType": "StorageAccount"
  },
  {
    "principalDisplayName": "#{EnvCode}#-#{ZoneCode}#-ai-monitor-readers",
    "principalType": "Group",
    "roleName": "Monitoring Reader",
    "scopeType": "ResourceGroup"
  }
]

The active assignment example includes both the small Foundry access model and the supporting runtime roles currently used by the POC. The important point is that each access type is separated by group and scope, so Foundry administration, Foundry usage, model access, RAG indexing, RAG querying, storage access, and monitoring can be managed independently.

This keeps the current RBAC configuration aligned with the purpose of this phase: making access control repeatable while avoiding broad subscription-level permissions.

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.

Successful RBAC Deployment from Azure DevOps

After adding the security group and RBAC assignment steps to the deployment flow, I ran the pipeline again for the development environment. The RBAC step completed successfully and assigned the configured roles to the Entra security groups.

The pipeline output confirmed that the step resolved each group, mapped the friendly role name to the correct Azure role definition ID, and deployed the role assignments through Bicep.

For the dev-auea deployment, the successful run showed the expected Foundry and supporting runtime security groups being processed:

dev-poc-ai-foundry-admins
dev-poc-ai-foundry-users
dev-poc-ai-model-users
dev-poc-ai-rag-indexers
dev-poc-ai-rag-readers
dev-poc-ai-storage-contributors
dev-poc-ai-monitor-readers

The important part is that RBAC was no longer configured manually through the Azure portal. It was created as part of the same repeatable Azure DevOps deployment flow used for the rest of the platform.

Azure DevOps pipeline log showing a successful Assign Azure RBAC step for the dev-auea environment.

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 patternRecommended scopeReference
A developer needs to work in a Foundry project but should not administer the account. Use Foundry User. This is the safer least-privilege choice for normal project-level development work. Avoid using subscription Contributor. Scope to the specific Foundry project where possible, or to the relevant Foundry / AI resource if project-level scope is not available. Microsoft Foundry RBAC roles
A platform admin needs to manage Foundry project access, deployments, or project-level settings. Use Foundry Project Manager. This is usually the better answer when the person manages a project but should not have full account-level ownership. Scope to the specific Foundry project or relevant Foundry / AI resource. Avoid subscription-level scope unless the admin manages multiple Foundry resources. Microsoft Foundry RBAC roles
A platform owner needs to manage the Foundry account, projects, and broader Foundry administration. Use Foundry Account Owner when the user mainly needs account/project/resource management. Use Foundry Owner only when the user also needs full self-service development capability inside projects. Foundry Owner is more privileged overall because it combines management access with build/development capabilities. Scope to the Foundry account or relevant Foundry / AI resource. Use resource group or subscription scope only when broader ownership is genuinely required. Microsoft Foundry RBAC roles
An application or developer needs to use a model deployment through a Foundry project. Use the appropriate Foundry role, usually Foundry User for normal project usage. Do not use generic subscription Contributor. Scope to the specific Foundry project where possible, or the relevant Foundry / AI resource if project-level scope is not available. Microsoft Foundry RBAC roles
An ingestion process needs to create or manage Azure AI Search indexes, indexers, skillsets, knowledge bases, or data sources. Use Search Service Contributor. This role can create and manage search objects, but it cannot load documents, query indexes, or retrieve from knowledge bases. If the same identity also needs to load documents, add Search Index Data Contributor. Scope to the specific Azure AI Search service. For Search Index Data Contributor or Search Index Data Reader, you can also scope to a specific index where appropriate. Avoid resource group or subscription scope unless the identity must work across multiple Search services. Azure AI Search RBAC roles
An ingestion process needs to upload, update, or delete documents in an Azure AI Search index. Use Search Index Data Contributor. This provides read-write content access. It can load documents, query indexes, and retrieve from knowledge bases, but it cannot modify object definitions or retrieve admin keys. Scope to the specific Azure AI Search service, or to a specific index where supported and appropriate. Avoid broader resource group or subscription scope unless required. Azure AI Search RBAC roles
An app only needs to query Azure AI Search index data or retrieve from a knowledge base. Use Search Index Data Reader. This is the least-privilege role for read-only data-plane access. It can query indexes and retrieve from knowledge bases, but it cannot load documents, modify object definitions, or retrieve admin keys. Scope to the specific Azure AI Search service, or to a specific index where supported and appropriate. Avoid assigning broader Search or Azure Contributor roles. Azure AI Search RBAC roles
A runtime identity needs to read source documents from Azure Storage. Use Storage Blob Data Reader if read-only access is enough. Use Storage Blob Data Contributor only when upload, update, or delete access is required. Scope to the specific storage account or, preferably, the specific blob container that contains the source documents. Assign Azure roles for blob data access
An operator only needs to view logs, metrics, alerts, or monitoring data. Use Monitoring Reader. Do not use Contributor unless the operator needs to configure or modify monitoring resources. Scope to the relevant resource, resource group, or Log Analytics workspace. Use subscription scope only if the operator must view monitoring data across the whole subscription. Azure Monitor roles and permissions

Note: For direct Azure OpenAI / Azure AI Services access outside a Foundry project, Microsoft also has Cognitive Services roles such as Cognitive Services OpenAI User. These are separate from Foundry project RBAC and do not need to be included in this Foundry-focused table.

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