Edit

Share via


Indexing document Access Control Lists (ACLs) using the push REST APIs

Note

This feature is currently in public preview. This preview is provided without a service-level agreement and isn't recommended for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.

Indexing documents, along with their associated Access Control Lists (ACLs) and container Role-Based Access Control (RBAC) roles, into an Azure AI Search index via the push REST APIs offers fine-grained control over the indexing pipeline. This approach enables the inclusion of document entries with precise, document-level permissions directly within the index.

Key features include:

  • Flexible control over ingestion pipelines.
  • Standardized schema for permissions metadata.
  • Support for hierarchical permissions, such as folder-level ACLs.

This article explains how to use the push REST API to index document-level permissions' metadata in Azure AI Search. This process prepares your index to query and enforce end-user permissions on search results.

Prerequisites

  • Content with ACL metadata from Microsoft Entra ID or another POSIX-style ACL system.

  • Preview API version 2025-05-01-preview or a prerelease Azure SDK package providing equivalent features.

  • An index schema with a permissionFilterOption defined to hold the RBAC or ACL metadata.

Limitations

  • An ACL field with permission filter type userIds or groupIds can hold at most 32 values.

  • An index can hold at most five unique values among fields of type rbacScope on all documents. There's no limit on the number of documents that share the same value of rbacScope.

  • A preexisting field can't be converted into a permissionFilter field type for use with built-in ACLs or RBAC metadata filtering. To enable filtering on an existing index, new fields must be created with the correct permission filter type.

  • Only one field of each permissionFilter type such as groupIds, usersIds, and rbacScope, can exist in an index.

Create an index with permission filter fields

Indexing document ACLs and RBAC metadata with the REST API requires setting up an index schema that enables permission filters and has fields with permission filter assignments.

Permission filter field types can be added to an existing index on new fields. The value of permissionFilterOption can be set to either enabled or disabled while indexing documents. However, setting it to disabled turns off the permission filter functionality.

Here's a basic example schema that includes both user and group ACLs and RBAC metadata:

{  
  "fields": [  
    { "name": "UserIds", "type": "Collection(Edm.String)", "permissionFilter": "userIds", "filterable": true },  
    { "name": "GroupIds", "type": "Collection(Edm.String)", "permissionFilter": "groupIds", "filterable": true },  
    { "name": "RbacScope", "type": "Edm.String", "permissionFilter": "rbacScope", "filterable": true },  
    { "name": "DocumentId", "type": "Edm.String", "key": true }  
  ],
  "permissionFilterOption": "enabled"
}

REST API indexing example

Once you have an index with the desired permission filter fields, you can populate those values using the Indexing Push API as with any other document fields. Here's an example using the specified index schema.

POST https://exampleservice.search.windows.net/indexes('indexdocumentsexample')/docs/search.index?api-version=2025-05-01-preview
{
  "value": [
    {
      "@search.action": "upload",
      "DocumentId": "1",
      "UserIds": ["00aa00aa-bb11-cc22-dd33-44ee44ee44ee", "11bb11bb-cc22-dd33-ee44-55ff55ff55ff", "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"],
      "GroupIds": ["none"]
      "RbacScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/Example-Storage-rg/providers/Microsoft.Storage/storageAccounts/azurestorage12345/blobServices/default/containers/blob-container-01"
    },
    {
      "@search.action": "merge",
      "DocumentId": "2",
      "UserIds": ["all"],
      "GroupIds": ["33dd33dd-ee44-ff55-aa66-77bb77bb77bb", "44ee44ee-ff55-aa66-bb77-88cc88cc88cc"]
    },
    {
      "@search.action": "mergeOrUpload",
      "DocumentId": "3",
      "UserIds": ["1cdd8521-38cf-49ab-b483-17ddaa48f68f"],
      "RbacScope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/Example-Storage-rg/providers/Microsoft.Storage/storageAccounts/azurestorage12345/blobServices/default/containers/blob-container-03"
    }
  ]
}

ACL access resolution rules

This section explains how document access is determined for a user based on the ACL values assigned to each document. The key rule is that a user only needs to match one ACL type to gain access to the document. For example, if a document has fields for userIds, groupIds, and rbacScope, the user can access the document by matching any one of these ACL fields.

Special ACL values "all" and "none"

ACL fields, such as userIds and groupIds, typically contain lists of GUIDs (Globally Unique Identifiers) that identify the users and groups with access to the document. Two special string values, "all" and "none", are supported for these ACL field types. These values act as broad filters to control access at the global level as showcased in the following table.

userIds / groupIds value Meaning
["all"] Any user can access the document
["none"] No user can access the document by matching this ACL type
[] (empty array) No user can access the document by matching this ACL type

Because a user needs to match only one field type, the special value "all" grants public access regardless of the contents of any other ACL field, as all users are matched and granted permission. In contrast, setting userIds to "none" or "empty" means no users are granted access to the document based on their user ID. It might be possible that they're still granted access by matching their group ID or by RBAC metadata.

Access control example

This example illustrates how the document access rules are resolved based on the specific document ACL field values. For readability, this scenario uses ACL aliases such as "user1," "group1," etc., instead of GUIDs.

Document # userIds groupIds RBAC Scope Permitted users list Note
1 ["none"] [] Empty No users have access The values ["none"] and [] behave exactly the same
2 ["none"] [] scope/to/container1 Users with RBAC permissions to container1 The value of "none" doesn't block access by matching other ACL fields
3 ["none"] ["group1", "group2"] Empty Members of group1 or group2
4 ["all"] ["none"] Empty Any user Any querying user matches the ACL filter "all", so all users have access
5 ["all"] ["group1", "group2"] scope/to/container1 Any user Since all users match the "all" filter for userID, the groupID and RBAC filters don't have any impact
6 ["user1", "user2"] ["group1"] Empty User1, user2, or any member of group1
7 ["user1", "user2"] [] Empty User1, user2, or any user with RBAC permissions to container1

Next steps