자습서: 보안 JavaScrip 앱에서 Microsoft Graph에 앱으로 액세스

Azure App Service에서 실행되는 웹앱에서 Microsoft Graph에 액세스하는 방법에 대해 알아봅니다.

Diagram that shows accessing Microsoft Graph.

웹앱용 Microsoft Graph를 호출하려고 합니다. 웹앱에 데이터 액세스 권한을 부여하는 안전한 방법은 시스템이 할당한 관리 ID를 사용하는 것입니다. Microsoft Entra ID의 관리 ID를 사용하면 앱 자격 증명 없이 App Service가 RBAC(역할 기반 액세스 제어)를 통해 리소스에 액세스할 수 있습니다. 웹앱에 관리 ID를 할당한 후에는 인증서를 만들고 배포하는 작업을 Azure가 처리합니다. 사용자는 비밀 또는 앱 자격 증명 관리에 대해 신경 쓸 필요가 없습니다.

이 자습서에서는 다음을 하는 방법을 알아볼 수 있습니다.

  • 웹앱에서 시스템이 할당한 관리 ID를 만듭니다.
  • 관리 ID에 Microsoft Graph API 권한을 추가합니다.
  • 관리 ID를 사용하여 웹앱에서 Microsoft Graph를 호출합니다.

Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.

사전 요구 사항

앱에서 관리 ID 사용

Visual Studio를 통해 웹앱을 만들고 게시하는 경우 앱에서 관리 ID를 사용하도록 자동으로 설정되었습니다.

  1. 앱 서비스의 왼쪽 창에서 ID를 선택한 다음, 시스템 할당을 선택합니다.

  2. 상태켜기로 설정되어 있는지 확인합니다. 설정되지 않았으면 저장을 선택한 다음, 를 선택하여 시스템이 할당한 관리 ID를 사용하도록 설정합니다. 관리 ID를 사용하도록 설정하면 상태가 켜기로 설정되고 개체 ID를 사용할 수 있습니다.

  3. 다음 단계에서 필요한 개체 ID 값을 기록해 둡니다.

Screenshot that shows the system-assigned identity.

Microsoft Graph에 액세스

Microsoft Graph에 액세스할 때 수행하려는 작업에 대한 적절한 권한이 관리 ID에 있어야 합니다. 현재는 Microsoft Entra 관리 센터를 통해 이러한 권한을 할당할 수 있는 옵션이 없습니다.

  1. 다음 스크립트를 실행하여 관리 ID 서비스 주체 개체에 요청된 Microsoft Graph API 권한을 추가합니다.

    # Install the module.
    # Install-Module Microsoft.Graph -Scope CurrentUser
    
    # The tenant ID
    $TenantId = "11111111-1111-1111-1111-111111111111"
    
    # The name of your web app, which has a managed identity.
    $webAppName = "SecureWebApp-20201106120003" 
    $resourceGroupName = "SecureWebApp-20201106120003ResourceGroup"
    
    # The name of the app role that the managed identity should be assigned to.
    $appRoleName = "User.Read.All"
    
    # Get the web app's managed identity's object ID.
    Connect-AzAccount -Tenant $TenantId
    $managedIdentityObjectId = (Get-AzWebApp -ResourceGroupName $resourceGroupName -Name $webAppName).identity.principalid
    
    Connect-MgGraph -TenantId $TenantId -Scopes 'Application.Read.All','AppRoleAssignment.ReadWrite.All'
    
    # Get Microsoft Graph app's service principal and app role.
    $serverApplicationName = "Microsoft Graph"
    $serverServicePrincipal = (Get-MgServicePrincipal -Filter "DisplayName eq '$serverApplicationName'")
    $serverServicePrincipalObjectId = $serverServicePrincipal.Id
    
    $appRoleId = ($serverServicePrincipal.AppRoles | Where-Object {$_.Value -eq $appRoleName }).Id
    
    # Assign the managed identity access to the app role.
    New-MgServicePrincipalAppRoleAssignment `
        -ServicePrincipalId $managedIdentityObjectId `
        -PrincipalId $managedIdentityObjectId `
        -ResourceId $serverServicePrincipalObjectId `
        -AppRoleId $appRoleId
    
  2. 스크립트를 실행한 후에는 Microsoft Entra 관리 센터에서 요청된 API 권한이 관리 ID에 할당되었는지 확인할 수 있습니다.

  3. 애플리케이션으로 이동하여 엔터프라이즈 애플리케이션을 선택합니다. 이 창에는 테넌트의 모든 서비스 주체가 표시됩니다. "애플리케이션 유형 == 관리 ID"에 필터를 추가하고 해당 관리 ID의 서비스 주체를 선택합니다.

    이 자습서를 수행하는 경우 동일한 표시 이름(예: SecureWebApp2020094113531)을 가진 두 개의 서비스 주체가 있습니다. 홈페이지 URL이 있는 서비스 주체는 테넌트의 웹앱을 나타냅니다. 관리 ID에 표시되는 서비스 주체에는 홈페이지 URL이 나열되지 않아야 하며 개체 ID이전 단계에서 관리 ID의 개체 ID 값과 일치해야 합니다.

  4. 관리 ID의 서비스 주체를 선택합니다.

    Screenshot that shows the All applications option.

  5. 개요에서 권한을 선택하면 Microsoft Graph에 대한 추가 권한이 표시됩니다.

    Screenshot that shows the Permissions pane.

Node.js로 Microsoft Graph 호출

이제 웹앱에 필요한 권한이 있으며 Microsoft Graph의 클라이언트 ID도 로그인 매개 변수에 추가됩니다.

@azure/identity 패키지의 DefaultAzureCredential 클래스는 Azure Storage에 대한 요청에 권한을 부여하기 위해 코드의 토큰 자격 증명을 가져오는 데 사용됩니다. 관리 ID를 사용하여 토큰을 가져오고 서비스 클라이언트에 연결하는 DefaultAzureCredential 클래스의 인스턴스를 만듭니다. 다음 코드 예제에서는 인증된 토큰 자격 증명을 가져와서 서비스 클라이언트 개체를 만드는 데 사용합니다. 이 개체는 그룹의 사용자를 가져옵니다.

이 코드를 샘플 애플리케이션의 일부로 보려면 다음을 참조하세요.

참고 항목

@azure/identity 패키지는 기본 인증/권한 부여를 위해 또는 Microsoft Graph로 요청을 인증하기 위해 웹앱에서 필요하지 않습니다. App Service 인증/권한 부여 모듈만 사용하도록 설정된 상태에서 다운스트림 API를 안전하게 호출하는 것이 가능합니다.

하지만 App Service 인증/권한 부여는 보다 기본적인 인증 시나리오를 위해 설계되었습니다. 더 복잡한 시나리오(예: 사용자 지정 클레임 처리)의 경우 @azure/identity 패키지가 필요합니다. 처음에는 설정 및 구성 작업이 조금 더 있지만 @azure/identity 패키지는 App Service 인증/권한 부여 모듈과 함께 실행할 수 있습니다. 나중에 웹앱에서 더 복잡한 시나리오를 처리해야 하는 경우 App Service 인증/권한 부여 모듈을 사용하지 않도록 설정할 수 있으며 @azure/identity는 이미 앱의 일부가 됩니다.

클라이언트 라이브러리 패키지 설치

npm을 사용하여 프로젝트에 @azure/identity@microsoft/microsoft-graph-client 패키지를 설치합니다.

npm install @azure/identity @microsoft/microsoft-graph-client

인증 정보 구성

인증 설정을 보관할 개체를 만듭니다.

// partial code in app.js
const appSettings = {
    appCredentials: {
        clientId: process.env.WEBSITE_AUTH_CLIENT_ID, // Enter the client Id here,
        tenantId: "common", // Enter the tenant info here,
        clientSecret: process.env.MICROSOFT_PROVIDER_AUTHENTICATION_SECRET // Enter the client secret here,
    },
    authRoutes: {
        redirect: "/.auth/login/aad/callback", // Enter the redirect URI here
        unauthorized: "/unauthorized" // enter the relative path to unauthorized route
    },
}

앱을 대신하여 Microsoft Graph 호출

다음 코드는 Microsoft Graph 컨트롤러를 앱으로 호출하고 일부 사용자 정보를 가져오는 방법을 보여 줍니다.

// graphController.js

const graphHelper = require('../utils/graphHelper');
const { DefaultAzureCredential } = require("@azure/identity");

exports.getUsersPage = async(req, res, next) => {

    const defaultAzureCredential = new DefaultAzureCredential();
    
    try {
        // get app's access token scoped to Microsoft Graph
        const tokenResponse = await defaultAzureCredential.getToken("https://graph.microsoft.com/.default");

        // use token to create Graph client
        const graphClient = graphHelper.getAuthenticatedClient(tokenResponse.token);

        // return profiles of users in Graph
        const users = await graphClient
            .api('/users')
            .get();

        res.render('users', { user: req.session.user, users: users });   
    } catch (error) {
        next(error);
    }
}

이전 코드는 다음 getAuthenticatedClient 함수를 사용하여 Microsoft Graph 클라이언트를 반환합니다.

// utils/graphHelper.js

const graph = require('@microsoft/microsoft-graph-client');

getAuthenticatedClient = (accessToken) => {
    // Initialize Graph client
    const client = graph.Client.init({
        // Use the provided access token to authenticate requests
        authProvider: (done) => {
            done(null, accessToken);
        }
    });

    return client;
}

리소스 정리

이 자습서를 완료하고 웹앱 또는 관련 리소스가 더 이상 필요하지 않으면 만든 리소스를 정리합니다.

리소스 그룹 삭제

Azure Portal의 포털 메뉴에서 리소스 그룹을 선택하고 앱 서비스 및 앱 서비스 계획이 포함된 리소스 그룹을 선택합니다.

리소스 그룹 삭제를 선택하여 리소스 그룹 및 모든 리소스를 삭제합니다.

Screenshot that shows deleting the resource group.

이 명령을 실행하는 데 몇 분 정도 걸릴 수 있습니다.

다음 단계

이 자습서에서는 다음 작업 방법을 알아보았습니다.

  • 웹앱에서 시스템이 할당한 관리 ID를 만듭니다.
  • 관리 ID에 Microsoft Graph API 권한을 추가합니다.
  • 관리 ID를 사용하여 웹앱에서 Microsoft Graph를 호출합니다.

.NET Core 앱, Python 앱, Java 앱 또는 Node.js 앱을 데이터베이스에 연결하는 방법을 알아봅니다.