The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

認識 Microsoft Entra ID 中的企業應用程式與服務主體物件

在 Microsoft Entra ID 中,有兩個很重要卻又有點抽象的物件,那就是「企業應用程式」(Enterprise applications) 與「服務主體」(Service Principal) 這兩項,這個應該有困擾我好幾年的時間,一直沒機會可以摸透這兩個物件的關聯性,這次終於在 Microsoft 的技術支援工程師的幫助下釐清了多年以來模糊的觀念,今天這篇文章我就來好好談談這個概念。

image

基本觀念

首先,你必須知道一件事,Microsoft Entra ID 的前身是 Azure Active Directory,它本質上是一個 Identity and Access Management (IAM) (身分識別與存取管理) 的解決方案,所以在這個目錄中,只要牽涉到「身分識別」(Identity),就需要給他一個「主體」(Principal),有了這個「主體」,你才能對這個「主體」進行「存取權管理」(Access Management)。換句話說,就是你在 Azure 進行 IAM 授權設定時,你必須選定一個「目標主體」才能授予權限給他們。

在 Microsoft Entra ID 稍微有點複雜,所有的「主體」物件大概分成以下幾種:

  1. 一般主體物件 (Normal identity)

    • 使用者 (User) (也可以稱呼為 User Principal)
    • 群組 (Group)
    • 服務帳戶 (Service Principal)
  2. 託管主體物件 (Managed identity)

    • 系統指派的託管主體 (System-assigned managed identity)
    • 使用者指派的託管主體 (User-assigned managed identity)

事先聲明:文章中若提到組織 (Organization)、目錄 (Directory)、租戶 (Tenant),都是相同的意思,都代表一個 Microsoft Entra ID 目錄。

若要開發一個「單租戶」(Single-teant)或「多租戶」(Multi-tenant)的應用程式,首先你要先在你的 Microsoft Entra ID 中使用「應用程式註冊」中建立一個「應用程式」物件,這個應用程式物件為了要在整個目錄中擁有一個「身分識別」(Identity),因此你在 Azure Portal 建立「應用程式」的時候,系統會自動幫你建立好一個相對應的「服務主體」(Service Principal)。如此一來你才能在 IAM 的管理介面中,找到這個「應用程式」來授權。

注意:你授權的對象其實是「服務主體」,而非「應用程式」。但是「服務主體」不能單獨存在,它一定要依附在一個「應用程式」上,所以你在 Azure Portal 上看到的「應用程式」其實就是「服務主體」的意思,因為你不能授權 IAM 給一個「應用程式」,而是「服務主體」。

看到上面的注意事項了嗎?你能說「服務主體」與「應用程式」這兩個東西一樣嗎?從概念上來說,他們是不一樣的!單單從 IAM 授權的角度上來看,他們兩者是分不開的,有依附關係存在。

有趣的地方就是,這兩個東西還真的是可以分開的。你可以利用 PowerShell 建立一個「應用程式」,但是不建立「服務主體」,這樣這個「應用程式」就只是一個「應用程式」而已,只能拿來透過 OAuth 2.0 與 Microsoft Entra ID 進行單一簽入與身分驗證,不能存取任何 Azure 資源,也不能進行任何 Azure 資源的 IAM 授權 (你會找不到這個應用程式來授權)。但是如果你建立了「服務主體」,這個「應用程式」就擁有了一個「服務主體」,這個「服務主體」就可以進行 IAM 的授權了。

注意:你透過 Azure Portal 建立「應用程式」的時候,系統會一定會自動幫你建立「服務主體」,但是透過 PowerShell 建立「應用程式」的時候,你必須額外建立「服務主體」才會有「服務主體」可以用。

以下是透過 PowerShell 建立「應用程式」與「服務主體」的範例:

$app = New-AzADApplication -DisplayName "MyNewApplication"

$passwordCredential = New-Object -TypeName 'Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential'
$passwordCredential.DisplayName = 'Created from PowerShell'
$passwordCredential.EndDateTime = Get-Date "2090-12-31"

# 應用程式密鑰 (Client Secret) 只有當下查的到,之後是不能查的!
$appcred = $app | New-AzADAppCredential -PasswordCredentials $passwordCredential
$appcred.SecretText # 應用程式密鑰

Get-AzADApplication -DisplayName "MyNewApplication"
Get-AzADAppCredential -DisplayName "MyNewApplication"

什麼是企業應用程式 (Enterprise applications)

先說結論:

企業應用程式 (Enterprise applications) 就是一個「服務主體」(Service Principal)!

我記得多年前,微軟就是這樣告訴我的,但是我當時是完全無法理解的。

企業應用程式這個概念是這樣的,當你要整合一個「第三方的應用程式」(例如 Salesforce、ServiceNow、Slack、GitHub、Jira、... 等等) 到你的 Microsoft Entra ID 目錄中,你就需要建立一個「企業應用程式」(Enterprise applications) 物件。事實上,你找不到可以直接建立「企業應用程式」的地方,因為「企業應用程式」這個物件其實是在使用這個「第三方的應用程式」時,在進行 OAuth 2.0 的驗證流程過程中,自動建立的。

你可以在 Microsoft Entra ID > Enterprise applications > Consent and permissions > User consent settings 找到如下圖的設定:

Microsoft Entra ID > Enterprise applications > Consent and permissions > User consent settings

你有三個選項可以設定:

  1. Do not allow user consent

    不允許使用者同意建立企業應用程式,只有管理者可以建立

  2. Allow user consent for apps from verified publishers, for selected permissions (Recommended)

    只有「低度影響」的權限,且來自「已驗證的發行者」的應用程式,或是這個組織中註冊的應用程式,才能允許使用者同意。

  3. Allow user consent for apps

    允許所有使用者同意任何第三方應用程式註冊到 Microsoft Entra ID 之中。

你可以在 Microsoft Entra ID > Enterprise applications > Consent and permissions > Admin consent settings 找到如下圖的設定:

Microsoft Entra ID > Enterprise applications > Consent and permissions > Admin consent settings

建議將 Admin consent requestsUsers can request admin consent to apps they are unable to consent to 選項開啟,讓組織內的使用者在在無法同意的應用程式時,可以向管理者請求同意。記得至少選取一個使用者、群組或角色來接收這些請求。

我以 Microsoft Graph Explorer 為例,這是一個「多租戶」的應用程式,而且是微軟驗證的發行者,所以在 Allow user consent for apps from verified publishers, for selected permissions 的設定下,當使用者第一次使用這個應用程式時,會看到如下圖的畫面,你必須填寫一個理由給管理者,說服他們同意放行這個「第三方應用程式」或「企業應用程式」或「服務主體」:

Approval required

管理者則會收到以下郵件:

Please review the admin consent request for Graph Explorer

然你你可以點擊郵件中的 Review request 按鈕,進入 Admin consent requests 頁面,這時你可以看到這個請求的詳細資訊,包括請求的應用程式、請求的權限、請求的理由、請求的使用者等等:

Admin consent requests

點進去之後,就可以點擊 Review permission and consent 進行同意,同意之後就會在 Enterprise applications 中看到這個物件了!

Review permission and consent

如果你在上述 User consent settings 的設定中選擇了 Allow user consent for apps,那麼組織內任意「使用者」都可以同意這個「企業應用程式」在使用者所屬的 Microsoft Entra ID 中建立,並且你將會在 Enterprise applications 中看到這個物件。然而,這個物件其實並不是一個「應用程式」物件,而是一個「服務主體」物件而已。

我在本文稍早有提到「服務主體」物件是不能單獨存在的,他必須「依附」於某一個「應用程式」物件。沒錯,在「多租戶」的應用程式中,本身他就是一個「應用程式」物件,只是他只會建立在該應用程式所屬的那個目錄下,當你在你想使用這個「多租戶」應用程式時,這個「應用程式」物件就會自動在你所屬的目錄中建立一個「服務主體」物件,這個「服務主體」物件就是你在 Enterprise applications 中看到的那個物件。

這時我們回到本小節一開始的結論:

企業應用程式 (Enterprise applications) 就是一個「服務主體」(Service Principal)!

沒錯,你就算建立的是「單租戶」的應用程式,你在你的 Microsoft Entra ID 目錄中也可以看到同名的「企業應用程式」物件,但這其實就是一個「服務主體」物件而已。

所以我要再次強調:

企業應用程式 (Enterprise applications) 就是一個「服務主體」(Service Principal)!

「企業應用程式」與「服務主體」的關係是這樣的:

  • 你看他是一個「應用程式」的時候,他就是一個「企業應用程式」
  • 你看他是一個「身分識別」的時候,他就是一個「服務主體」

因為「企業應用程式」來自於外部,另一個 Microsoft Entra ID 目錄下的「應用程式」,而該應用程式會需要讀取到我們這個 Microsoft Entra ID 目錄下的資料,因此會有一些安全議題需要考量。你要是身為一個 Microsoft Entra ID 管理員,你應該會想要保護組織的資料安全,不能讓使用者任意同意這些「企業應用程式」的存取權限。也因此你應該要在 User consent settings 中設定 Do not allow user consentAllow user consent for apps from verified publishers, for selected permissions 才對,這樣就可以避免使用者自行同意這些「企業應用程式」的存取權限。

當這個「企業應用程式」來存取我們 Microsoft Entra ID 目錄下的資料時,到底是誰存取的?那就需要一個「身分」了是吧!此時你就可以稱他為一個「服務主體」了。

換句話說,對「使用者」來講,他們用的是一個「企業應用程式」,這個程式抓了我什麼資料我不管,我只管這個第三方應用程式可以正常執行就好。但是對「管理者」來說,他們看到的是「服務主體」來我的目錄索取資料,這個「企業應用程式」可以信任嗎?不能信任的話,我可以直接從 Enterprise applications 直接將「服務主體」刪除,我的使用者就安全了,因為這個「企業應用程式」再也不能持續向 Microsoft Entra ID 拿資料了。

這樣你明白了嗎?這是我能想到最淺顯的解釋了!這個觀念這麼繞,真的是卡了我數年時間,直到今日我才徹底理解這之間的關係!我真是佩服微軟可以想出這麼複雜的概念,但是這樣的設計確實有其意義,只是很少人可以講清楚!

總結

今天這篇文章我們可以很好的理解到三個不同的物件:

  1. 應用程式 (Application)

    如果你要自行開發應用程式,而且需要跟 Microsoft Entra 進行整合 (單一簽入),就可以建立一個新的應用程式註冊。

    建立好的「應用程式註冊」可以輕鬆透過 OAuth 2.0 與 OIDC 實現單一簽入。

    當你想用 App registraions > Expose an API 建立「應用程式」的「授權範圍」(Scope),就必須要設定 Application ID URI 參數,這個參數就是你的 API 的唯一識別碼,在 Single-tenant applications (單租戶應用程式) 通常會設定成 api://myexample 格式,只要不跟其他人重複就好,你可以把 myexample 改成 GUID 以避免重複,範例如下:

    $app = New-AzADApplication -DisplayName "MyNewApplication" -IdentifierUri "api://myexample"
    

    這裡的 -IdentifierUri 參數,隨時都可以在 Microsoft Entra IDApp registrations 中修改。

    如果你想要開發 Multi-tenant applications (多租戶應用程式) 的話,在建立時 -IdentifierUri 參數需要設定為 https://abc.domain.com,這樣才能讓其他租戶的使用者進行授權,不過這個域名必須先驗證過,否則會出現以下錯誤訊息:

    Values of identifierUris property must use a verified domain of the organization or its subdomain: 'http://www.example.com'
    

    這個 Client Secret 金鑰是一個密碼,所以要妥善保管

    這個 Client Secret 金鑰是有時效性的,通常是 6 個月,透過 Azure Portal 建立最長是 2 年,透過 PowerShell 建立最長則無限制!

    這個 Client Secret 金鑰過期後,就需要重新建立一個新的 Client Secret 金鑰

  2. 服務主體 (Service Principal)

    在 Azure 上面的所有資源,如果要授權一個「服務」來存取資源,就需要一個 Service Principal (服務主體)

    Service Principal (服務主體) 是一個安全的身份 (Securable),可以用來存取資源。就跟 User 或 Group 一樣,都是一個安全的身份。

  3. 企業應用程式 (Enterprise applications)

    針對「多租戶」的第三方應用程式,你需要建立一個「企業應用程式」物件,這個物件其實就是一個「服務主體」物件。

    任何想要存取 Microsoft Entra ID 目錄中的資料,都需要一個「服務主體」的身分!

    透過 Azure Portal 建立應用程式後,預設會自動建立一個「服務主體」,這個「服務主體」就是你在 Enterprise applications 中看到的那個物件。

這三個物件之間的關係是這樣的:

  • 一個「應用程式」可以建立多組「應用程式密鑰」(Client Secret),這個密鑰是用來進行 OAuth 2.0 的驗證流程的。

    $app = New-AzADApplication -DisplayName "MyNewApplication"
    
    $passwordCredential = New-Object -TypeName 'Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential'
    $passwordCredential.DisplayName = 'Created from PowerShell'
    $passwordCredential.EndDateTime = Get-Date "2090-12-31"
    
    # 應用程式密鑰 (Client Secret) 只有當下查的到,之後是不能查的!
    $appcred = $app | New-AzADAppCredential -PasswordCredentials $passwordCredential
    $appcred.SecretText # 應用程式密鑰
    
    Get-AzADApplication -DisplayName "MyNewApplication"
    Get-AzADAppCredential -DisplayName "MyNewApplication"
    
    # 取得應用程式與密鑰
    $ap = Get-AzADApplication -DisplayName "MyNewApplication"
    $apCredential = Get-AzADAppCredential -DisplayName "MyNewApplication"
    

    你可以用 az login --service-principal 登入為「服務主體」身分,登入密碼可以是「應用程式註冊」或「服務主體」的任何一組 Client secrets 金鑰。

    az login --service-principal -u "api://myexample" -p "1Zu8Q~38PLY2eMvldtR544_nZ4NmLLFhCNnoYciD" --tenant "miniasp.onmicrosoft.com"
    
  • 一個「服務主體」可以建立多組「應用程式密鑰」(Client Secret),但是幾乎沒有人會這麼用,連微軟的人也不知道為什麼有這種設計,他們從來沒看過有人這樣用。

    你只能透過 PowerShell 建立「服務主體」的「應用程式密鑰」(Client Secret),而且在 Azure Portal 是完全看不到的。

    $app = New-AzADApplication -DisplayName "MyNewApplication"
    
    $sp = New-AzADServicePrincipal -AppId $app.AppId
    
    $passwordCredential = New-Object -TypeName 'Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential'
    $passwordCredential.DisplayName = 'Created from PowerShell'
    $passwordCredential.EndDateTime = Get-Date "2090-12-31"
    
    # 密碼只有當下查的到,之後是不能查的!
    $credential = New-AzADServicePrincipalCredential -ObjectId $sp.Id -PasswordCredentials $passwordCredential
    Write-Output $credential
    
    Get-AzADServicePrincipalCredential -DisplayName "MyNewApplication"
    
    # 取得服務主體(企業應用程式)與密鑰
    $sp = Get-AzADServicePrincipal -DisplayName "MyNewApplication"
    $spCredential = Get-AzADServicePrincipalCredential -DisplayName "MyNewApplication"
    
  • 一個「企業應用程式」就是一個「服務主體」

    刪除「企業應用程式」的意思就是刪除「服務主體」,此舉會讓組織內所有人都無法再使用該「企業應用程式」,因為失去了「身分識別」將無法存取組織內的任何資料。

  • 一個「企業應用程式」來自於「應用程式」

    對「單租戶」應用程式而言,「應用程式」只會存在於他所屬的目錄下,其目錄也會自動建立一個「企業應用程式」

    對「多租戶」應用程式而言,「應用程式」只會存在於他所屬的目錄下,其他目錄要用就會在其目錄中建立一個「企業應用程式」

  • 一個「應用程式」可以有一個「服務主體」,也可以完全沒有「服務主體」,沒有服務主體的狀況比較少見!

    建立「應用程式」不一定要建立「服務主體」

    建立「服務主體」就一定要建立「應用程式」

    # 列出應用程式
    Get-AzADApplication -DisplayName 'MyNewApplication'
    
    # 列出企業應用程式或服務主體
    Get-AzADServicePrincipal -DisplayName 'MyNewApplication'
    

詭異的問題整理

我在觀念不清晰的時候,寫了好幾個問題,現在看起來會覺得有點蠢,但是我還是想把這些問題列出來,當作是一個學習的過程,也許有人會有同樣的疑問,我希望這些問題能幫助你理解這個觀念!

Q: 何謂 Enterprise applications?如何使用?

A: 企業應用程式 (Enterprise applications) 是一個「服務主體」(Service Principal),用來存取自己 Microsoft Entra ID 目錄下的資料。你可以透過使用企業應用程式的過程中,使用 OAuth 2.0 登入並授權,第一次使用的時候需要使用者或管理者同意才能開始用 (看你權限如何設定),同意後,會在 Enterprise applications 中看到這個物件。

Q: Enterprise applications 與 Service principal 到底有何關聯性?

A: 企業應用程式 (Enterprise applications) 就是一個「服務主體」(Service Principal),全看你用什麼角度看這個東西!基本上在 PowerShell 找不到可以管理「企業應用程式」的 Cmdlet,因為本質上他就是 Service Principal 而已。

Q: 建立 Enterprise applications 是否一定要有 Service Principal?

A: 使用者在使用「應用程式」時,就需要有個「服務主體」才能存取資料,這個「服務主體」就是「企業應用程式」。

Q: 整合第三方應用程式的 Enterprise applications 也會自動建立一個 Service Principal 嗎?

A: 是的,一定會建立。但是管理者可以設定權限,可以不讓使用者自行同意這些「企業應用程式」的存取權限。

Q: 如何透過 Azure PowerShell 建立一個 Enterprise applications?好像沒有找到任何 Cmdlet 可用?

A: 沒辦法,因為企業應用程式 (Enterprise applications) 就是一個「服務主體」(Service Principal),你只能透過建立「應用程式」來建立「服務主體」。如果是多租戶應用程式(第三方應用程式),第一次使用者會顯示使用者同意頁面,同意後就會自動在你的目錄下建立一個「企業應用程式」。

相關連結

留言評論