在 Microsoft Entra ID 中,有兩個很重要卻又有點抽象的物件,那就是「企業應用程式」(Enterprise applications) 與「服務主體」(Service Principal) 這兩項,這個應該有困擾我好幾年的時間,一直沒機會可以摸透這兩個物件的關聯性,這次終於在 Microsoft 的技術支援工程師的幫助下釐清了多年以來模糊的觀念,今天這篇文章我就來好好談談這個概念。
基本觀念
首先,你必須知道一件事,Microsoft Entra ID
的前身是 Azure Active Directory
,它本質上是一個 Identity and Access Management
(IAM) (身分識別與存取管理) 的解決方案,所以在這個目錄中,只要牽涉到「身分識別」(Identity),就需要給他一個「主體」(Principal),有了這個「主體」,你才能對這個「主體」進行「存取權管理」(Access Management)。換句話說,就是你在 Azure 進行 IAM 授權設定時,你必須選定一個「目標主體」才能授予權限給他們。
在 Microsoft Entra ID 稍微有點複雜,所有的「主體」物件大概分成以下幾種:
-
一般主體物件 (Normal identity)
- 使用者 (User) (也可以稱呼為 User Principal)
- 群組 (Group)
- 服務帳戶 (Service Principal)
-
託管主體物件 (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
找到如下圖的設定:
你有三個選項可以設定:
-
Do not allow user consent
不允許使用者同意建立企業應用程式,只有管理者可以建立
-
Allow user consent for apps from verified publishers, for selected permissions
(Recommended)
只有「低度影響」的權限,且來自「已驗證的發行者」的應用程式,或是這個組織中註冊的應用程式,才能允許使用者同意。
-
Allow user consent for apps
允許所有使用者同意任何第三方應用程式註冊到 Microsoft Entra ID 之中。
你可以在 Microsoft Entra ID
> Enterprise applications
> Consent and permissions
> Admin consent settings
找到如下圖的設定:
建議將 Admin consent requests
的 Users 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
的設定下,當使用者第一次使用這個應用程式時,會看到如下圖的畫面,你必須填寫一個理由給管理者,說服他們同意放行這個「第三方應用程式」或「企業應用程式」或「服務主體」:
管理者則會收到以下郵件:
然你你可以點擊郵件中的 Review request
按鈕,進入 Admin consent requests
頁面,這時你可以看到這個請求的詳細資訊,包括請求的應用程式、請求的權限、請求的理由、請求的使用者等等:
點進去之後,就可以點擊 Review permission and consent
進行同意,同意之後就會在 Enterprise applications
中看到這個物件了!
如果你在上述 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 consent
或 Allow user consent for apps from verified publishers, for selected permissions
才對,這樣就可以避免使用者自行同意這些「企業應用程式」的存取權限。
當這個「企業應用程式」來存取我們 Microsoft Entra ID 目錄下的資料時,到底是誰存取的?那就需要一個「身分」了是吧!此時你就可以稱他為一個「服務主體」了。
換句話說,對「使用者」來講,他們用的是一個「企業應用程式」,這個程式抓了我什麼資料我不管,我只管這個第三方應用程式可以正常執行就好。但是對「管理者」來說,他們看到的是「服務主體」來我的目錄索取資料,這個「企業應用程式」可以信任嗎?不能信任的話,我可以直接從 Enterprise applications 直接將「服務主體」刪除,我的使用者就安全了,因為這個「企業應用程式」再也不能持續向 Microsoft Entra ID 拿資料了。
這樣你明白了嗎?這是我能想到最淺顯的解釋了!這個觀念這麼繞,真的是卡了我數年時間,直到今日我才徹底理解這之間的關係!我真是佩服微軟可以想出這麼複雜的概念,但是這樣的設計確實有其意義,只是很少人可以講清楚!
總結
今天這篇文章我們可以很好的理解到三個不同的物件:
-
應用程式 (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 ID
的 App 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 金鑰
-
服務主體 (Service Principal)
在 Azure 上面的所有資源,如果要授權一個「服務」來存取資源,就需要一個 Service Principal (服務主體)
Service Principal (服務主體) 是一個安全的身份 (Securable),可以用來存取資源。就跟 User 或 Group 一樣,都是一個安全的身份。
-
企業應用程式 (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),你只能透過建立「應用程式」來建立「服務主體」。如果是多租戶應用程式(第三方應用程式),第一次使用者會顯示使用者同意頁面,同意後就會自動在你的目錄下建立一個「企業應用程式」。
相關連結