Azure Active Directory를 사용하여 Azure AI Search 결과를 트리밍하기 위한 보안 필터

이 문서에서는 Azure AI Search의 필터와 함께 보안 ID를 사용하여 사용자 그룹 멤버 자격에 따라 검색 결과를 자르는 방법을 보여 줍니다.

이 문서에서는 다음 작업을 다룹니다.

  • 그룹 및 사용자 만들기
  • 만든 그룹과 사용자 연결
  • 새 그룹 캐시
  • 연결된 그룹을 사용하여 문서 인덱싱
  • 그룹 식별자 필터를 사용하여 검색 요청 발급

필수 구성 요소

Azure AI Search의 인덱스에는 문서에 대한 읽기 액세스 권한이 있는 그룹 ID 목록을 저장할 보안 필드가 있어야 합니다. 이 사용 사례에서는 보안 항목(예: 개인의 대학 지원)과 해당 항목에 액세스할 수 있는 사람(입학 담당자)을 지정하는 보안 필드 간의 일대일 대응을 가정합니다.

사용자, 그룹 및 연결을 만들려면 테넌트 관리자 권한(소유자 또는 관리자)이 있어야 합니다.

다음 절차에 설명된 대로 애플리케이션을 다중 테넌트 앱으로 등록해야 합니다.

Azure Active Directory에 애플리케이션 등록

이 단계에서는 사용자 및 그룹 계정의 로그인을 수락하기 위해 애플리케이션을 Azure Active Directory와 통합합니다. 조직의 테넌트 관리자가 아닌 경우 다음 단계를 수행하기 위해 새 테넌트를 만들어야 할 수 있습니다.

  1. Azure 포털에서 Azure Active Directory 테넌트를 찾습니다.

  2. 왼쪽의 관리아래에서 앱 등록을 선택하고, 새 등록을 선택합니다.

  3. 등록에 검색 응용 프로그램 이름과 비슷한 이름(예: 이름)을 지정합니다. 다른 선택적 속성에 대한 자세한 내용은 이 문서 참조하세요.

  4. 등록선택합니다.

  5. 앱 등록이 만들어지면 애플리케이션(클라이언트) ID를 복사합니다. 애플리케이션에 이 문자열을 제공해야 합니다.

    DotNetHowToSecurityTrimming을 단계별로 실행하는 경우 이 값을 app.config 파일에 붙여넣습니다.

  6. 디렉터리(테넌트) ID를 복사합니다.

  7. 왼쪽에서 API 사용 권한을 선택한 다음, 권한 추가를 선택합니다.

  8. Microsoft Graph 선택한 다음 위임된 권한 선택합니다.

  9. 다음 위임된 권한을 검색한 다음 추가합니다.

    • Directory.ReadWrite.All
    • Group.ReadWrite.All
    • User.ReadWrite.All

    Microsoft Graph는 REST API를 통해 Azure Active Directory에 프로그래밍 방식으로 액세스할 수 있는 API를 제공합니다. 이 연습의 코드 샘플에서는 사용 권한을 사용하여 그룹, 사용자 및 연결을 만들기 위해 Microsoft Graph API를 호출합니다. API는 더 빠른 필터링을 위해 그룹 식별자를 캐시하는 데도 사용됩니다.

  10. 테넌트 대한 관리자 동의 부여 선택하여 동의 프로세스를 완료합니다.

사용자 및 그룹 만들기

설정된 애플리케이션에 검색을 추가하는 경우 Azure Active Directory에 기존 사용자 및 그룹 식별자가 있을 수 있습니다. 이 경우 다음 세 단계를 건너뛸 수 있습니다.

그러나 기존 사용자가 없는 경우 Microsoft Graph API를 사용하여 보안 주체를 만들 수 있습니다. 다음 코드 조각에서는 Azure AI Search 인덱스의 보안 필드에 대한 데이터 값이 되는 식별자를 생성하는 방법을 보여 줍니다. 우리의 가상 대학 입학 응용 프로그램에서, 이것은 입학 직원에 대한 보안 식별자가 될 것입니다.

사용자 및 그룹 멤버 자격은 특히 대규모 조직에서 매우 유동적일 수 있습니다. 사용자 및 그룹 ID를 빌드하는 코드는 조직 멤버 자격의 변경 내용을 선택할 수 있을 만큼 자주 실행되어야 합니다. 마찬가지로 Azure AI Search 인덱스에는 허용된 사용자 및 리소스의 현재 상태를 반영하기 위해 유사한 업데이트 일정이 필요합니다.

1단계: 그룹 만들기

private static Dictionary<Group, List<User>> CreateGroupsWithUsers(string tenant)
{
    Group group = new Group()
    {
        DisplayName = "My First Prog Group",
        SecurityEnabled = true,
        MailEnabled = false,
        MailNickname = "group1"
    };

2단계: 사용자 만들기

User user1 = new User()
{
    GivenName = "First User",
    Surname = "User1",
    MailNickname = "User1",
    DisplayName = "First User",
    UserPrincipalName = String.Format("user1@{0}", tenant),
    PasswordProfile = new PasswordProfile() { Password = "********" },
    AccountEnabled = true
};

3단계: 사용자 및 그룹 연결

List<User> users = new List<User>() { user1, user2 };
Dictionary<Group, List<User>> groups = new Dictionary<Group, List<User>>() { { group, users } };

4단계: 그룹 식별자 캐시

필요에 따라 네트워크 대기 시간을 줄이려면 사용자 그룹 연결을 캐시하여 검색 요청이 실행될 때 그룹이 캐시에서 반환되어 왕복을 저장할 수 있습니다. Batch API 사용하여 여러 사용자와 단일 Http 요청을 보내고 캐시를 빌드할 수 있습니다.

Microsoft Graph는 대량의 요청을 처리하도록 설계되었습니다. 엄청난 수의 요청이 발생하는 경우 Microsoft Graph는 HTTP 상태 코드 429를 사용하여 요청에 실패합니다. 자세한 내용은 Microsoft Graph 요청 제한을 참조하세요.

허용된 그룹이 있는 인덱스 문서

Azure AI Search의 쿼리 작업은 Azure AI Search 인덱스를 통해 실행됩니다. 이 단계에서 인덱싱 작업은 보안 필터로 사용되는 식별자를 포함하여 검색 가능한 데이터를 인덱스로 가져옵니다.

Azure AI Search는 사용자 ID를 인증하거나 사용자가 볼 수 있는 권한이 있는 콘텐츠를 설정하기 위한 논리를 제공하지 않습니다. 보안 트리밍의 사용 사례에서는 중요한 문서와 해당 문서에 대한 액세스 권한이 있는 그룹 식별자 간에 연결을 제공하고 검색 인덱스로 그대로 가져온 것으로 가정합니다.

가상 예제에서 Azure AI Search 인덱스의 PUT 요청 본문에는 지원자의 대학 에세이 또는 성적 증명서와 해당 콘텐츠를 볼 수 있는 권한이 있는 그룹 식별자가 포함됩니다.

이 연습의 코드 샘플에 사용된 제네릭 예제에서 인덱스 동작은 다음과 같이 표시될 수 있습니다.

private static void IndexDocuments(string indexName, List<string> groups)
{
    IndexDocumentsBatch<SecuredFiles> batch = IndexDocumentsBatch.Create(
        IndexDocumentsAction.Upload(
            new SecuredFiles()
            {
                FileId = "1",
                Name = "secured_file_a",
                GroupIds = new[] { groups[0] }
            }),
              ...
            };

IndexDocumentsResult result = searchClient.IndexDocuments(batch);

검색 요청을 발행하다

보안 트리밍을 위해 인덱스 보안 필드의 값은 검색 결과에 문서를 포함하거나 제외하는 데 사용되는 정적 값입니다. 예를 들어 허용에 대한 그룹 식별자가 "A11B22C33D44-E55F66G77-H88I99JKK"인 경우 보안 필드에 해당 식별자가 있는 Azure AI Search 인덱스의 모든 문서는 호출자에게 다시 전송된 검색 결과에 포함되거나 제외됩니다.

요청을 발급하는 사용자 그룹을 기반으로 검색 결과에 반환된 문서를 필터링하려면 다음 단계를 검토합니다.

1단계: 사용자의 그룹 식별자 검색

사용자의 그룹이 아직 캐시되지 않았거나 캐시가 만료된 경우 그룹 요청을 실행합니다.

private static async void RefreshCache(IEnumerable<User> users)
{
    HttpClient client = new HttpClient();
    var userGroups = await _microsoftGraphHelper.GetGroupsForUsers(client, users);
    _groupsCache = new ConcurrentDictionary<string, List<string>>(userGroups);
}

2단계: 검색 요청 작성

사용자의 그룹 멤버 자격이 있다고 가정하면 적절한 필터 값으로 검색 요청을 실행할 수 있습니다.

private static void SearchQueryWithFilter(string user)
{
    // Using the filter below, the search result will contain all documents that their GroupIds field   
    // contain any one of the Ids in the groups list
    string filter = String.Format("groupIds/any(p:search.in(p, '{0}'))", string.Join(",", String.Join(",", _groupsCache[user])));
    SearchOptions searchOptions =
        new SearchOptions()
        {
            Filter = filter
        };
    searchOptions.Select.Add("name");

    SearchResults<SecuredFiles> results = searchClient.Search<SecuredFiles>("*", searchOptions);

    Console.WriteLine("Results for groups '{0}' : {1}", _groupsCache[user], results.GetResults().Select(r => r.Document.Name));
}

3단계: 결과 처리

응답에는 사용자가 볼 수 있는 권한이 있는 문서로 구성된 필터링된 문서 목록이 포함됩니다. 검색 결과 페이지를 생성하는 방법에 따라 필터링된 결과 집합을 반영하도록 시각적 신호를 포함할 수 있습니다.

주요 사항

이 연습에서는 사용자 로그인을 사용하여 Azure AI Search 결과에서 문서를 필터링하고 요청에 제공된 필터와 일치하지 않는 문서의 결과를 잘라내는 패턴을 알아보았습니다.