Azure AI Search의 결과를 한정하기 위한 보안 필터

Azure AI Search는 문서 수준 권한을 제공하지 않으며 사용자 권한에 따라 동일한 인덱스 내에서 검색 결과를 변경할 수 없습니다. 해결 방법으로 그룹 또는 사용자 ID가 포함된 문자열을 기반으로 검색 결과를 자르는 필터를 만들 수 있습니다.

이 문서에서는 다음 단계를 포함하는 보안 필터링 패턴을 설명합니다.

  • 필요한 콘텐츠로 원본 문서 어셈블
  • 보안 주체 식별자에 대한 필드 만들기
  • 인덱싱을 위해 검색 인덱스로 문서 푸시
  • search.in 필터 함수를 사용하여 인덱스 쿼리

보안 필터 패턴 정보

Azure AI Search는 인덱스 내의 콘텐츠에 액세스하기 위해 보안 하위 시스템과 통합되지 않지만 문서 수준 보안 요구 사항이 있는 많은 고객은 필터가 요구 사항을 충족할 수 있음을 발견했습니다.

Azure AI Search에서 보안 필터는 일치하는 값에 따라 검색 결과를 포함하거나 제외하는 일반 OData 필터입니다. 단, 보안 필터에서 조건은 보안 주체로 구성된 문자열입니다. 보안 주체를 통한 인증 또는 권한 부여는 없습니다. 보안 주체는 검색 결과에서 문서를 포함하거나 제외하기 위해 필터 식에 사용되는 문자열일 뿐입니다.

보안 필터링을 달성하는 방법에는 여러 가지가 있습니다. 한 가지 방법은 예를 들어 Id eq 'id1' or Id eq 'id2'와 같은 같음 표현의 복잡한 분리를 통해서입니다. 이 방법은 오류가 발생하기 쉽고, 유지 관리가 어려우며, 목록에 수백 수천 개의 값이 있는 경우 쿼리 응답 시간(초)이 느려집니다.

더 나은 솔루션은 이 문서에 설명된 대로 보안 필터에 search.in 함수를 사용하는 것입니다. 같음 식 대신에 search.in(Id, 'id1, id2, ...')을 사용한다면 1초 미만의 응답 시간을 기대할 수 있습니다.

필수 조건

  • 그룹 또는 사용자 ID를 포함하는 필드는 필터링 가능한 특성이 있는 문자열이어야 합니다. 컬렉션이어야 합니다. null을 허용하면 안 됩니다.

  • 동일한 문서의 다른 필드는 해당 그룹 또는 사용자가 액세스할 수 있는 콘텐츠를 제공해야 합니다. 다음 JSON 문서에서 "security_id" 필드에는 보안 필터에 사용된 ID가 포함되며 호출자의 ID가 문서의 "security_id"과 일치하는 경우 이름, 급여 및 결혼 여부가 포함됩니다.

    {  
        "Employee-1": {  
            "id": "100-1000-10-1-10000-1",
            "name": "Abram",   
            "salary": 75000,   
            "married": true,
            "security_id": "10011"
        },
        "Employee-2": {  
            "id": "200-2000-20-2-20000-2",
            "name": "Adams",   
            "salary": 75000,   
            "married": true,
            "security_id": "20022"
        } 
    }  
    

    참고 항목

    보안 주체 식별자를 검색하고 해당 문자열을 Azure AI Search에서 인덱싱할 수 있는 소스 문서에 삽입하는 프로세스는 이 문서에서 다루지 않습니다. 식별자 가져오기에 대한 도움말은 ID 서비스 공급자의 설명서를 참조하세요.

보안 필드 만들기

검색 인덱스의 필드 컬렉션 내에는 이전 예제의 가상 "security_id" 필드와 유사한 그룹 또는 사용자 ID가 포함된 필드가 하나 필요합니다.

  1. 보안 필드를 Collection(Edm.String)으로 추가합니다. 검색 결과가 사용자가 보유한 액세스 권한에 따라 필터링되도록 filterable 속성이 true로 설정되어 있는지 확인합니다. 예를 들어 file_name이 "secured_file_b"인 문서에 대해 group_ids 필드를 ["group_id1, group_id2"]로 설정할 경우, 그룹 ID가 "group_id1" 또는 "group_id2"에 속한 사용자만 파일 읽기 권한을 보유합니다.

    필드의 retrievable 특성이 false로 설정하여 검색 요청의 일부로 반환되지 않게 합니다.

  2. 인덱스에는 문서 키가 필요합니다. "file_id" 필드는 해당 요구 사항을 충족합니다. 인덱스에는 검색 가능한 콘텐츠도 포함되어야 합니다. 이 예제에서는 "file_name" 및 "file_description" 필드가 이를 나타냅니다.

    POST https://[search service].search.windows.net/indexes/securedfiles/docs/index?api-version=2023-11-01
    {
         "name": "securedfiles",  
         "fields": [
             {"name": "file_id", "type": "Edm.String", "key": true, "searchable": false },
             {"name": "file_name", "type": "Edm.String", "searchable": true },
             {"name": "file_description", "type": "Edm.String", "searchable": true },
             {"name": "group_ids", "type": "Collection(Edm.String)", "filterable": true, "retrievable": false }
         ]
     }
    

REST API를 사용하여 인덱스에 데이터 푸시

인덱스 URL 엔드포인트의 문서 컬렉션으로 에 HTTP POST 요청을 보냅니다(문서 - 인덱스 참조). HTTP 요청의 본문은 인덱싱할 문서의 JSON 렌더링입니다.

POST https://[search service].search.windows.net/indexes/securedfiles/docs/index?api-version=2023-11-01

요청 본문에 문서 콘텐츠를 지정합니다.

{
    "value": [
        {
            "@search.action": "upload",
            "file_id": "1",
            "file_name": "secured_file_a",
            "file_description": "File access is restricted to the Human Resources.",
            "group_ids": ["group_id1"]
        },
        {
            "@search.action": "upload",
            "file_id": "2",
            "file_name": "secured_file_b",
            "file_description": "File access is restricted to Human Resources and Recruiting.",
            "group_ids": ["group_id1", "group_id2"]
        },
        {
            "@search.action": "upload",
            "file_id": "3",
            "file_name": "secured_file_c",
            "file_description": "File access is restricted to Operations and Logistics.",
            "group_ids": ["group_id5", "group_id6"]
        }
    ]
}

그룹 목록으로 기존 문서를 업데이트해야 하는 경우 merge 또는 mergeOrUpload 동작을 사용할 수 있습니다.

{
    "value": [
        {
            "@search.action": "mergeOrUpload",
            "file_id": "3",
            "group_ids": ["group_id7", "group_id8", "group_id9"]
        }
    ]
}

쿼리에 보안 필터 적용

group_ids 액세스에 기초해 문서를 다듬으려면 group_ids/any(g:search.in(g, 'group_id1, group_id2,...')) 필터를 사용해 검색 쿼리를 발급해야 합니다. 여기서 'group_id1 group_id2...'는 검색 요청 발급자가 속해 있는 그룹입니다.

이 필터는 주어진 식별자 중 하나가 group_ids 필드에 들어 있는 모든 문서와 일치합니다. Azure AI Search를 사용한 문서 검색에 대한 상세한 내용은 문서 검색에서 확인할 수 있습니다.

이 샘플에서는 POST 요청을 사용하여 쿼리를 설정하는 방법을 보여줍니다.

HTTP POST 요청을 발급합니다.

POST https://[service name].search.windows.net/indexes/securedfiles/docs/search?api-version=2020-06-30
Content-Type: application/json  
api-key: [admin or query key]

요청 본문에 필터를 지정합니다.

{
   "filter":"group_ids/any(g:search.in(g, 'group_id1, group_id2'))"  
}

group_ids에 "group_id1" 또는 "group_id2"가 들어 있는 곳에 문서를 되돌려 두어야 합니다. 즉, 사용자는 요청 발급자에게 읽기 권한이 있는 문서를 가져옵니다.

{
 [
   {
    "@search.score":1.0,
     "file_id":"1",
     "file_name":"secured_file_a",
   },
   {
     "@search.score":1.0,
     "file_id":"2",
     "file_name":"secured_file_b"
   }
 ]
}

다음 단계

이 문서에서는 사용자 ID 및 search.in() 함수를 기준으로 결과를 필터링하는 패턴에 대해 설명했습니다. 이 함수를 사용하면 요청하는 사용자가 각 대상 문서와 연결된 보안 주체 식별자에 맞출 보안 주체 식별자를 전달할 수 있습니다. 검색 요청이 처리될 때, search.in 함수는 사용자의 보안 주체 중 아무도 읽기 권한이 없는 검색 결과를 필터링합니다. 보안 주체 식별자는 보안 그룹, 역할 또는 심지어 사용자 본인 ID와 같은 것을 나타낼 수 있습니다.

Microsoft Entra ID를 기준으로 하는 대체 패턴의 경우 또는 다른 보안 기능을 다시 확인하려면 다음 링크를 참조하세요.