教程:使用 Microsoft Entra 应用程序创建 Microsoft Entra 用户

适用于: Azure SQL 数据库

本文介绍如何配置服务主体,以便其可以在 Azure SQL 数据库中创建 Microsoft Entra 用户。 此功能支持以编程方式配置 Microsoft Entra 租户中的用户和应用程序对 Azure SQL 资源的访问管理。

注意

Microsoft Entra ID 以前称为 Azure Active Directory (Azure AD)。

有关 Azure SQL 的 Microsoft Entra 身份验证的详细信息,请参阅使用 Microsoft Entra 身份验证

本教程介绍如何执行下列操作:

  • 将标识分配给逻辑服务器
  • 将目录读取者角色分配给服务器标识
  • 在 Microsoft Entra ID 中注册应用程序
  • 在 Azure SQL 数据库中为该应用程序的服务主体创建数据库用户
  • 使用服务主体创建 Microsoft Entra 数据库用户

先决条件

  • 现有 Azure SQL 数据库部署。 在本教程中,我们假设你有一个正常运行的 SQL 数据库。
  • SQL 数据库所在租户中的 Microsoft Entra Global AdministratorPrivileged Role Administrator 权限。
  • 最新版本的 Az.Sql PowerShell 模块。
  • 最新版本的 Microsoft Graph PowerShell 模块。

将标识分配给逻辑服务器

  1. 连接到 Azure,指定托管 SQL 数据库的 Microsoft Entra 租户。 可在 Azure 门户中“Microsoft Entra ID”资源的“概述”页面找到租户 ID。 复制该“租户 ID”,然后运行以下 PowerShell 命令:

    • 使用租户 ID 替换 <TenantId>
    Connect-AzAccount -Tenant <TenantId> -Environment AzureChinaCloud
    

    记录 TenantId 以便将来在本教程中使用。

  2. 生成系统分配的托管标识并将其分配给 Azure 中的逻辑服务器。 执行以下 PowerShell 命令:

    • 使用 Set-AzSqlServer 命令中的资源替换 <ResourceGroupName><ServerName>。 如果服务器名称为 myserver.database.chinacloudapi.cn,请将 <ServerName> 替换为 myserver
    Set-AzSqlServer -ResourceGroupName <ResourceGroupName> -ServerName <ServerName> -AssignIdentity
    
  3. 检查是否已成功分配服务器标识。 执行以下 PowerShell 命令:

    • <ResourceGroupName><ServerName> 替换为你的资源。 如果服务器名称为 myserver.database.chinacloudapi.cn,请将 <ServerName> 替换为 myserver
    $xyz = Get-AzSqlServer -ResourceGroupName <ResourceGroupName> -ServerName <ServerName>
    $xyz.identity
    

    你的输出应显示 PrincipalIdTypeTenantId。 分配的标识是 PrincipalId

  4. 还可以通过转到 Azure 门户检查标识。

    • 在“Microsoft Entra ID”资源中,转到“企业应用程序”。 键入逻辑服务器的名称。 资源上显示的“对象 ID”是主服务器标识的 ID。

    显示在何处查找企业应用程序的对象 ID 的屏幕截图。

将服务器标识添加到目录读取者角色

服务器标识需要有权查询 Microsoft Entra ID 以获取管理功能,其中包括创建 Microsoft Entra 用户和登录,以及执行组扩展以根据其 Microsoft Entra 组成员身份应用用户权限。 如果撤销了用于查询 Microsoft Entra ID 的服务器标识权限,或者删除了服务器标识,则 Microsoft Entra 身份验证将停止工作。

添加服务器标识到目录读取者角色或分配以下较低级别的 Microsoft Graph 权限,可将 Microsoft Entra 查询权限分配给服务器标识:

注意

此脚本必须由 Microsoft Entra ID Global AdministratorPrivileged Role Administrator 执行。

以下脚本向表示 Azure SQL 数据库逻辑服务器的标识授予 Microsoft Entra“目录读取者”权限。

  • <TenantId> 替换为之前收集的 TenantId
  • <ServerName> 替换为你的逻辑服务器名称。 如果服务器名称为 myserver.database.chinacloudapi.cn,请将 <ServerName> 替换为 myserver
# This script grants "Directory Readers" permission to a service principal representing a logical server for Azure SQL Database
# It can be executed only by a user who is a member of the **Global Administrator** or **Privileged Role Administrator** role.
# To check if the "Directory Readers" role was granted, re-execute this script

Import-Module Microsoft.Graph.Authentication
$ServerIdentityName = "<ServerName>"    # Enter your logical server name
$TenantId = "<TenantId>"                # Enter your tenant ID

Connect-MgGraph -Environment China -TenantId "<TenantId>" -Scopes "RoleManagement.ReadWrite.Directory,Application.Read.All"

# Get Microsoft Entra "Directory Readers" role and create if it doesn't exist
$roleName = "Directory Readers"
$role = Get-MgDirectoryRole -Filter "DisplayName eq '$roleName'"
if ($role -eq $null) {
    # Instantiate an instance of the role template
    $roleTemplate = Get-MgDirectoryRoleTemplate -Filter "DisplayName eq '$roleName'"
    New-MgDirectoryRoleTemplate -RoleTemplateId $roleTemplate.Id
    $role = Get-MgDirectoryRole -Filter "DisplayName eq '$roleName'"
}

# Get service principal for server
$roleMember = Get-MgServicePrincipal -Filter "DisplayName eq '$ServerIdentityName'"
$roleMember.Count
if ($roleMember -eq $null) {
    Write-Output "Error: No service principal with name '$($ServerIdentityName)' found, make sure that ServerIdentityName parameter was entered correctly."
    exit
}
if (-not ($roleMember.Count -eq 1)) {
    Write-Output "Error: Multiple service principals with name '$($ServerIdentityName)'"
    Write-Output $roleMember | Format-List DisplayName, Id, AppId
    exit
}

# Check if service principal is already member of Directory Readers role
$isDirReader = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -Filter "Id eq '$($roleMember.Id)'"

if ($isDirReader -eq $null) {
    # Add principal to Directory Readers role
    Write-Output "Adding service principal '$($ServerIdentityName)' to 'Directory Readers' role'..."
    $body = @{
        "@odata.id"= "https://microsoftgraph.chinacloudapi.cn/v1.0/directoryObjects/{$($roleMember.Id)}"
    }
    New-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id -BodyParameter $body
    Write-Output "'$($ServerIdentityName)' service principal added to 'Directory Readers' role'."
} else {
    Write-Output "Service principal '$($ServerIdentityName)' is already member of 'Directory Readers' role'."
}

注意

此脚本的输出指示标识是否已分配给“目录读取者”角色。 如果不确定是否已授予权限,可以重新运行该脚本。

有关如何为 SQL 托管实例分配“目录读取者”权限的类似方法,请参阅预配 Microsoft Entra 管理员(SQL 托管实例)

在生产环境中,常见的管理实践是将“目录读取者”角色分配给 Microsoft Entra ID 中可分配角色的组。 然后,组所有者可以将托管标识添加到该组。 这样做维护了最小特权原则,并且无需全局管理员或特权角色管理员向每个 SQL 实例单独授予“目录读取者”角色。 有关此功能的详细信息,请参阅 Azure SQL 的 Microsoft Entra ID 中的目录读取者角色

在 Microsoft Entra ID 中创建应用程序

注册应用程序。 要注册应用,至少需要 Microsoft Entra ID“应用程序开发人员”角色。 有关如何分配角色的更多信息,请参阅在 Microsoft Entra ID 中分配用户角色

本教程使用了两个服务主体。 第一个服务主体 DBOwnerApp 用于在数据库中创建其他用户。 第二个服务主体 myapp 是 DBOwnerApp 为本教程的后面部分创建数据库用户的应用程序。

要注册应用程序,请执行以下操作:

  1. 在 Azure 门户中,选择“Microsoft Entra ID”>“应用注册”>“新建注册”。

    显示“注册应用程序”页的屏幕截图。

    创建应用注册后,会生成并显示“应用程序(客户端)ID”值。 记录此值以供将来在本教程中使用。

    显示应用 ID 的 Azure 门户的屏幕截图。

  2. 为应用程序创建要登录的客户端密码。 请按照上传证书或创建登录密码进行操作。 记录 DBOwnerApp 的客户端密码,以供将来在本教程中使用。

有关更多信息,请参阅使用门户创建可访问资源的 Microsoft Entra 应用程序和服务主体

创建服务主体用户

将新创建的服务主体 DBOwnerApp 添加为 SQL 数据库中的用户,并向其分配权限。

使用有权创建其他用户的 Microsoft Entra 标识连接到 SQL 数据库。

重要

只有 Microsoft Entra 用户可以在 Azure SQL 数据库中创建其他 Microsoft Entra 用户。 所有基于 SQL 身份验证的用户(包括服务器管理员)均无法创建 Microsoft Entra 用户。 只有 Microsoft Entra 管理员可以在 SQL 数据库中初始创建其他 Microsoft Entra 用户。 Microsoft Entra 管理员创建其他用户后,任何具有适当权限的 Microsoft Entra 用户都可以创建其他 Microsoft Entra 用户。

  1. 使用以下 T-SQL 命令在 SQL 数据库中创建用户 DBOwnerApp

    CREATE USER [DBOwnerApp] FROM EXTERNAL PROVIDER
    GO
    
  2. 要创建其他 Microsoft Entra 用户,至少需要 ALTER ANY USER SQL 权限。 此权限也可以通过 db_owner 中的成员身份以及通过分配作为 Microsoft Entra 管理员进行继承。以下示例演示了向 DBOwnerApp 分配权限的三个不同选项,以允许其在数据库中创建其他 Microsoft Entra 用户。

    可以使用 sp_addrolemember 将 DBOwnerApp 添加到 db_owner 角色

    EXEC sp_addrolemember 'db_owner', [DBOwnerApp]
    GO
    

    可以将 ALTER ANY USER 权限分配给 DBOwnerApp,如以下 T-SQL 示例所示:

    GRANT ALTER ANY USER TO [DBOwnerApp]
    GO
    

    可以将 DBOwnerApp 设置为 Microsoft Entra 管理员。可以使用 Azure 门户、PowerShell 或 Azure CLI 命令来完成此操作。 有关详细信息,请参阅预配 Microsoft Entra 管理员(SQL 托管实例)

使用服务主体创建用户

  1. 使用以下脚本通过服务主体 DBOwnerApp 创建 Microsoft Entra 服务主体用户 myapp

    • <TenantId> 替换为之前收集的 TenantId
    • <ClientId> 替换为之前收集的 ClientId
    • <ClientSecret> 替换为之前创建的客户端密码。
    • <ServerName> 替换为你的逻辑服务器名称。 如果服务器名称为 myserver.database.chinacloudapi.cn,请将 <ServerName> 替换为 myserver
    • <database name> 替换为你的 SQL 数据库名称。
    # PowerShell script for creating a new SQL user called myapp using application DBOwnerApp with secret
    # DBOwnerApp is an admin for the server
    
    # Download latest  MSAL  - https://www.powershellgallery.com/packages/MSAL.PS
    Import-Module MSAL.PS
    
    $tenantId = "<TenantId>"   # Microsoft Entra tenant ID where DBOwnerApp resides
    $clientId = "<ClientId>"   # Application (client) ID recorded earlier for DBOwnerApp
    $clientSecret = "<ClientSecret>"   # Client secret for DBOwnerApp 
    $scopes = "https://database.chinacloudapi.cn/.default" # The endpoint
    
    $result = Get-MsalToken -RedirectUri $uri -ClientId $clientId -ClientSecret (ConvertTo-SecureString $clientSecret -AsPlainText -Force) -TenantId $tenantId -Scopes $scopes
    
    $Tok = $result.AccessToken
    #Write-host "token"
    $Tok
    
    $SQLServerName = "<ServerName>"    # Logical server name 
    $DatabaseName = "<database name>"   # Azure SQL database name
    
    Write-Host "Create SQL connection string"
    $conn = New-Object System.Data.SqlClient.SQLConnection 
    $conn.ConnectionString = "Data Source=$SQLServerName.database.chinacloudapi.cn;Initial Catalog=$DatabaseName;Connect Timeout=30"
    $conn.AccessToken = $Tok
    
    Write-host "Connect to database and execute SQL script"
    $conn.Open() 
    $ddlstmt = 'CREATE USER [myapp] FROM EXTERNAL PROVIDER;'
    Write-host " "
    Write-host "SQL DDL command"
    $ddlstmt
    $command = New-Object -TypeName System.Data.SqlClient.SqlCommand($ddlstmt, $conn)       
    
    Write-host "results"
    $command.ExecuteNonQuery()
    $conn.Close()
    

    或者,可以使用以下代码:Microsoft Entra 服务主体身份验证到 Azure SQL 数据库。 修改脚本以执行 DDL 语句 CREATE USER [myapp] FROM EXTERNAL PROVIDER。 相同的脚本可用于在数据库中创建 Microsoft Entra 用户或组。

  2. 通过执行以下命令,检查用户 myapp 是否存在于数据库中:

    SELECT name, type, type_desc, CAST(CAST(sid as varbinary(16)) as uniqueidentifier) as appId
    FROM sys.database_principals
    WHERE name = 'myapp'
    GO
    

    应看到如下类似输出:

    name	type	type_desc	appId
    myapp	E	EXTERNAL_USER	6d228f48-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    

后续步骤