教學課程:使用自動化來設定適用於 SQL Server 的 Microsoft Entra 管理員
- 發行項
適用於: SQL Server 2022 (16.x)
注意
此功能適用於 SQL Server 2022 (16.x) 或更新版本,且僅支援 Windows 和 Linux 主機的內部部署 SQL Server,以及 Windows Azure VM 上的 SQL Server 2022。
在本文中,我們將探討如何設定 Microsoft Entra 管理員,以允許使用 Azure 入口網站及下列 API,對 SQL Server 進行 Microsoft Entra ID (之前稱為 Azure Active Directory) 驗證:
- PowerShell
- Azure CLI
- ARM 範本
我們也將探討在 Azure 入口網站中為 SQL Server 設定 Microsoft Entra 管理員的新功能,可自動化憑證建立和應用程式註冊。 先前,為 SQL Server 設定 Microsoft Entra 驗證時,必須使用 Azure 憑證和應用程式註冊,手動設定 Microsoft Entra 管理員。
注意
雖然 Microsoft Entra ID 是 Azure Active Directory(Azure AD)的新名稱,但為了防止破壞現有的環境,Azure AD 仍會保留在某些硬式編碼元素中,例如 UI 字段、連線提供者、錯誤碼和 Cmdlet。 在本文中,這兩個名稱是可互換的。
必要條件
- 已安裝 SQL Server 2022 (16.x) 或更新版本。
- 已連線到 Azure 雲端的 SQL Server。 如需詳細資料,請參閱將 SQL Server 連線到 Azure Arc。
- Microsoft Entra ID 已設定為在與 Azure Arc 執行個體相同的租用戶中進行驗證。
- 需要 Azure Key Vault。
設定 Microsoft Entra 管理員之前的準備
您必須具備下列權限,才能在 SQL Server – Azure Arc 和 Key Vault 資源中設定 Microsoft Entra 管理員。
設定 Azure Arc 的權限
請遵循指南,確定 SQL Server 已連線到 Azure Arc。為 SQL Server - Azure Arc 資源設定 Microsoft Entra 管理員的使用者應該具備伺服器的參與者角色。
- 移至 Azure 入口網站
- 選取 [SQL Server – Azure Arc],然後選取您 SQL Server 主機的執行個體。
- 選取 [存取控制 (IAM)]。
- 選取 [新增]>[新增角色指派],將參與者角色新增至設定 Microsoft Entra 管理員的使用者。
設定 Azure Key Vault 的權限
建立 Azure Key Vault (如果您尚未建立)。 設定 Microsoft Entra 管理員的使用者應該具有 Azure Key Vault 的參與者角色。 若要在 Azure Key Vault 中將角色新增的使用者:
- 移至 Azure 入口網站
- 移至您的 Key Vault 資源。
- 選取 [存取控制 (IAM)]。
- 選取 [新增]>[新增角色指派],將參與者角色新增至設定 Microsoft Entra 管理員的使用者。
設定 SQL Server 主機的存取原則
在 Azure 入口網站中,瀏覽至您的 Azure Key Vault 執行個體,並選取 [存取原則]。
選取 [新增存取原則]。
針對 [金鑰權限],請使用 [簽署]。
針對 [秘密權限],選取 [取得] 和 [清單]。
針對 [憑證權限],選取 [取得] 和 [清單]。
選取 [下一步]。
在 [主體] 頁面,搜尋 [機器 - Azure Arc] 執行個體的名稱,它是 SQL Server 主機的主機名稱。
透過選取 [下一步] 兩次,或選取 [檢閱 + 建立],略過 [應用程式 (選用)] 頁面。
確認主體的「物件 ID」符合指派至執行個體之受控識別的主體 ID。
若要確認,請移至資源頁面,然後選取 [概觀] 頁面上 [基本資料] 方塊右上方的 [JSON 檢視]。 在 [身分識別] 底下,您將發現 principalId。
選取 建立。
必須選取 [建立],以確保權限已套用。 若要確保權限已儲存,請重新整理瀏覽器視窗,並檢查 Azure Arc 執行個體的資料列是否仍然存在。
設定 Microsoft Entra 使用者的存取原則
- 在 Azure 入口網站中,瀏覽至您的 Azure Key Vault 執行個體,並選取 [存取原則]。
- 選取 [新增存取原則]。
- 針對 [金鑰權限],選取 [Get]、[List] 和 [Create]。
- 針對 [密碼權限],選取 [Get]、[List] 和 [Set]。
- 針對 [憑證權限],選取 [Get]、[List] 和 [Create]。
- 針對 [選取主體],新增您想要用來連線到 SQL Server 的 Microsoft Entra 使用者。
- 選取 [新增],然後選取 [儲存]。
設定適用於 SQL Server 的 Microsoft Entra 管理員
新的 API 和入口網站功能可讓使用者為 SQL Server 設定 Microsoft Entra 管理員,而不需要單獨建立 Azure 憑證和 Microsoft Entra 應用程式。 選取索引標籤,了解如何為連線至 Azure Arc 的 SQL Server 設定 Microsoft Entra 管理員,並自動建立憑證和應用程式。
注意
ARM 範本仍然需要在設定 Microsoft Entra 管理員之前,先建立 Azure Key Vault 憑證和 Microsoft Entra 應用程式。如需此流程的詳細資訊,請參閱教學課程:設定適用於 SQL Server 的 Microsoft Entra 驗證。
使用 Azure 入口網站來設定 Microsoft Entra 管理員,在同一個程序中建立 Azure Key Vault 認證和 Microsoft Entra 應用程式。 這是搭配 SQL Server 使用 Microsoft Entra 驗證的必要條件。
注意
先前,在設定 Microsoft Entra 管理員之前,需要 Azure Key Vault 認證和 Microsoft Entra 應用程式註冊。 這已不再需要,但使用者仍然可以選擇提供自己的認證和應用程式來設定 Microsoft Entra 管理員。
使用 Azure 入口網站來設定 Microsoft Entra 管理員
移至 Azure 入口網站,然後選取 [SQL Server – Azure Arc]。請選取您 SQL Server 主機的執行個體。
檢查 SQL Server - Azure Arc 資源的狀態,並前往 [屬性] 功能表查看是否已連線。 如需詳細資訊,請參閱驗證已啟用 Arc 的 SQL Server 資源。
從資源功能表中選取 [設定] 下的 [Microsoft Entra ID 和 Purview]。
選取 [設定管理員] 以開啟 Microsoft Entra ID,然後選擇將作為系統管理員登入名新增至 SQL Server 的帳戶。
選取 [受控服務的憑證]。
選取 [變更金鑰保存庫],然後選取您目前的 Azure Key Vault 資源。
選取 [服務管理的應用程式註冊]。
選取 [儲存]。 這會將要求傳送至 Arc 伺服器代理,以設定該 SQL Server 執行個體的 Microsoft Entra 驗證。 操作可能需要幾分鐘的時間才能完成;在嘗試 Microsoft Entra 登入之前,請等待
Saved successfully
來確認儲存過程。服務受管應用程式註冊會為您執行下列動作:
- 在金鑰保存庫中建立證書,其名稱格式為
<hostname>-<instanceName><uniqueNumber>
。 - 建立 Microsoft Entra 應用程式,其名稱類似於
<hostname>-<instanceName><uniqueNumber>
,並指派該應用程式的必要權限。 如需詳細資訊,請參閱授與應用程式權限 - 將 Azure Key Vault 中的新證書指派給應用程式。
- 將這些設定儲存至 Azure Arc。
- 在金鑰保存庫中建立證書,其名稱格式為
注意
為 Microsoft Entra 所建立的證書不會自動輪替。 客戶可以選擇為 Microsoft Entra 管理員設定提供自己的證書和應用程式。 如需詳細資訊,請參閱教學課程:設定適用於 SQL Server 的 Microsoft Entra 驗證。
下列 Azure CLI 指令碼會設定 Microsoft Entra 管理員,建立 Azure Key Vault 證書,並建立 Microsoft Entra 應用程式。 如需在證書和應用程式已經存在時,設定 Microsoft Entra 管理員的指令碼範例,我們提供了一個額外的章節供參考。
注意
為 Microsoft Entra 設定所建立的證書不會自動輪替。
- 需要 Azure CLI 2.37.0 版或更新版本
- 需要 Az.ConnectedMachine 0.5.1 或更新版本
若要安裝 Az.ConnectedMachine
模組,請使用 az extension add --name ConnectedMachine
。 若要檢查安裝了哪個版本的 Azure CLI,請使用 az version
。
下列是 Azure CLI 指令碼中使用的輸入參數:
<applicationName>
:將建立的應用程式名稱<certSubjectName>
:將建立的憑證名稱<keyVaultName>
:您的金鑰保存庫名稱。 執行指令碼之前,必須先建立此金鑰保存庫<machineName>
:您 SQL Server 主機的機器名稱<resourceGroupName>
:包含您 SQL Server – Azure Arc 執行個體的資源群組名稱<adminAccountName>
- 您想要為 SQL Server 設定的 Microsoft Entra 管理帳戶<instanceName>
:SQL Server 具名執行個體的參數 (選擇性)。 當您有具名的執行個體時,請使用此參數。 如果省略,則會使用MSSQLSERVER
為預設名稱<tenantId>
:適用於租用戶識別碼的選擇性參數。 前往 Azure 入口網站,然後前往您的 Microsoft Entra ID 資源,即可找到此租用戶識別碼。 在 [概觀] 窗格中,應該會看到您的租用戶識別碼。 如果省略,則會使用預設租用戶識別碼作為參數<subscriptionId>
:訂用帳戶識別碼的選擇性參數。 您可以在 Azure 入口網站中找到訂用帳戶識別碼。 如果省略,則會使用預設訂用帳戶識別碼
若要使用下列 Azure CLI 指令碼,請將指令碼儲存為 .ps1
檔案,然後執行下列命令:
./aadAzCliSetup.ps1 -applicationName "<applicationName>" -certSubjectName "<certSubjectName>" -keyVaultName "<keyVaultName>" -machineName "<machineName>" -resourceGroupName "<resourceGroupName>" -adminAccountName "<adminAccountName>" -instanceName "<instanceName>" -tenantId "<tenantId>" -subscriptionId "<subscriptionId>"
Azure CLI 指令碼
注意
針對 Linux 主機機器上的 SQL Server,請將指令碼中的 WindowsAgent.SqlServer
取代為 LinuxAgent.SqlServer
。
# AZ CLI and AZ CLI's connected machine extension must be installed before running this script
param (
[Parameter(mandatory=$true)] $applicationName,
[Parameter(mandatory=$true)] $certSubjectName,
[Parameter(mandatory=$true)] $keyVaultName,
[Parameter(mandatory=$true)] $machineName,
[Parameter(mandatory=$true)] $resourceGroupName,
[Parameter(mandatory=$true)] $adminAccountName,
$instanceName,
$tenantId,
$subscriptionId
)
# Constants
#
$NUMRETRIES = 60
# Helper functions
#
function ConvertFrom-StringArray {
param (
[string[]] $stringArray
)
if (!$stringArray)
{
return $null
}
else
{
return ConvertFrom-JSON ($stringArray -join "`n")
}
}
# Check parameters
#
if ([string]::IsNullOrEmpty($instanceName))
{
Write-Host "Warning: SQL Instance name (-instanceName) not provided. Default of MSSQLSERVER will be used"
$instanceName = "MSSQLSERVER"
}
$tenantIdArgument = ""
if ([string]::IsNullOrEmpty($tenantId))
{
Write-Host "Warning: Tenant ID (-tenantId) not supplied to the script, so default tenant is being used"
}
else
{
$tenantIdArgument = "-TenantId '" + $tenantId + "'"
}
$subscriptionIdArgument = ""
if ([string]::IsNullOrEmpty($subscriptionId))
{
Write-Host "Warning: Subscription ID (-subscriptionId) not supplied to the script, so default subscription is being used"
}
else
{
$subscriptionIdArgument = "-SubscriptionId '" + $subscriptionId + "'"
}
# Login and select subscription
#
$login = az login --tenant $tenantId --use-device-code
if (!$login)
{
Write-Error "Login to Azure AD failed. Exiting."
exit 1
}
if ($subscriptionId)
{
az account set -s $subscriptionId
}
$accountInfo = ConvertFrom-StringArray (az account show)
if (!$accountInfo)
{
Write-Error "Cannot query logged in Azure AD account. Check that 'az login' and 'az account set' succeeded"
exit 1
}
if ($subscriptionId)
{
if ($subscriptionId.ToLower() -ne $accountInfo.id.ToLower())
{
Write-Error "Could not select the desired subscription"
exit 1
}
}
else
{
$subscriptionId = $accountInfo.id
}
# Check AKV path exists
#
$keyVault = ConvertFrom-StringArray (az keyvault show --name $keyVaultName)
if (!$keyVault)
{
Write-Error "Azure key vault '$keyVaultName' does not exist"
exit 1
}
# Check certificate doesn't exist
#
$cert = ConvertFrom-StringArray (az keyvault certificate show --name $certSubjectName --vault-name $keyVaultName 2>$null)
if ($cert)
{
Write-Error "Certificate '$certSubjectName' already exists in key vault '$keyVaultName'"
exit 1
}
# Check app registration doesn't exist
#
$applications = ConvertFrom-StringArray (az ad app list --display-name $applicationName --only-show-errors)
if ($applications.length -gt 0)
{
Write-Error "App registration with name '$applicationName' already exists"
exit 1
}
# Check Arc SQL instance is valid
#
$extension = ConvertFrom-StringArray (az connectedmachine extension show --machine-name $machineName --name "WindowsAgent.SqlServer" --resource-group $resourceGroupName)
if (!$extension)
{
Write-Error "SQL Server Arc Server not found for machine '$machineName' in resource group '$resourceGroupName'"
exit 1
}
$arcServicePrincipals = ConvertFrom-StringArray(az ad sp list --display-name $machineName --only-show-errors)
if (!$arcServicePrincipals -or $arcServicePrincipals.length -eq 0)
{
Write-Error "Could not find a service principal account with the name '$machineName'"
exit 1
}
else
{
$principalFound = $false
for ($i = 0; $i -lt $arcServicePrincipals.length; $i++)
{
if ($arcServicePrincipals[$i].displayName.toLower() -eq $machineName.toLower()) {
if ($principalFound) {
Write-Error "Could not find exactly one service principal account with the name '$machineName'"
exit 1
}
$arcServicePrincipal = $arcServicePrincipals[$i]
$principalFound = $true
}
}
if (!$principalFound) {
Write-Error "Could not find a service principal account with the name '$machineName'"
exit 1
}
}
# Check if admin account exists
#
$adminAccount = ConvertFrom-StringArray (az ad user show --id $adminAccountName --only-show-errors 2>$null)
$adminAccountType = 0
if (!$adminAccount)
{
$adminAccounts = ConvertFrom-StringArray (az ad user list --filter "mail eq '$adminAccountName'" --only-show-errors 2>$null)
if ($adminAccounts -and $adminAccounts.length -gt 0)
{
if ($adminAccounts.length -eq 1)
{
$adminAccount = $adminAccounts[0]
}
else
{
Write-Error "Multiple Azure AD accounts found with identifier '$adminAccountName'"
exit 1
}
}
else
{
$adminAccount = ConvertFrom-StringArray (az ad group show --group $adminAccountName --only-show-errors 2>$null)
if (!$adminAccount)
{
$adminAccounts = ConvertFrom-StringArray (az ad app list --display-name $adminAccountName --only-show-errors 2>$null)
if ($adminAccounts -and $adminAccounts.length -gt 0)
{
if ($adminAccounts.length -eq 1)
{
$adminAccount = $adminAccounts[0]
}
else
{
Write-Error "Multiple Azure AD applications found with identifier '$adminAccountName'"
exit 1
}
}
else
{
Write-Error "Admin account not found"
exit 1
}
}
else
{
$adminAccountType = 1
}
}
}
if ($adminAccount)
{
$adminAccountSid = $adminAccount.id
}
else
{
Write-Error "Admin account not found"
exit 1
}
# Create certificate in AKV
#
$keyVaultPolicy = ConvertFrom-StringArray (az keyvault certificate get-default-policy)
if (!$keyVaultPolicy)
{
Write-Error "Could not get default key vault policy"
exit 1
}
$keyVaultPolicy.x509CertificateProperties.subject = "CN=" + $certSubjectName
$policyString = (ConvertTo-JSON -Depth 8 $keyVaultPolicy).replace("`r`n", "")
$escapedPolicyString = $policyString.replace("`"", "\`"")
$cert = ConvertFrom-StringArray (az keyvault certificate create --vault-name $keyVaultName --name $certSubjectName --policy $escapedPolicyString)
if (!$cert)
{
Write-Error "Failed to create certificate '$certSubjectName'"
exit 1
}
# Wait until cert is created?
#
$cert = ConvertFrom-StringArray (az keyvault certificate show --vault-name $keyVaultName --name $certSubjectName)
for (($i = 0); $i -lt $NUMRETRIES -and (!$cert -or !$cert.attributes.enabled); $i++)
{
$cert = ConvertFrom-StringArray (az keyvault certificate show --vault-name $keyVaultName --name $certSubjectName)
if (!$cert -or !$cert.attributes.enabled)
{
Start-Sleep -Seconds 5
}
}
# Allow Arc to access AKV
#
$newPerms = ConvertFrom-StringArray (az keyvault set-policy --name $keyVaultName --secret-permissions get list --certificate-permissions get list --object-id $arcServicePrincipal.id)
if (!$newPerms)
{
Write-Host "Warning: Unable to add permissions to key vault '$keyVaultName' for Arc's service principal's identity '$($arcServicePrincipal.id)'. Arc may not be able to configure Azure AD authentication"
}
# Create an Azure AD application
#
$application = ConvertFrom-StringArray (az ad app create --display-name $applicationName --only-show-errors)
if (!$application)
{
Write-Error "Unable to create the app registration '$applicationName'"
exit 1
}
# Set perms on app registration
#
az ad app permission add --id $application.id --api 00000003-0000-0000-c000-000000000000 --api-permissions c79f8feb-a9db-4090-85f9-90d820caa0eb=Scope --only-show-errors # Delegated Application.Read.All
az ad app permission add --id $application.id --api 00000003-0000-0000-c000-000000000000 --api-permissions 0e263e50-5827-48a4-b97c-d940288653c7=Scope --only-show-errors # Delegated Directory.AccessAsUser.All
az ad app permission add --id $application.id --api 00000003-0000-0000-c000-000000000000 --api-permissions 7ab1d382-f21e-4acd-a863-ba3e13f7da61=Role --only-show-errors # Application Directory.Read.All
az ad app permission add --id $application.id --api 00000003-0000-0000-c000-000000000000 --api-permissions 5f8c59db-677d-491f-a6b8-5f174b11ec1d=Scope --only-show-errors # Delegated Group.Read.All
az ad app permission add --id $application.id --api 00000003-0000-0000-c000-000000000000 --api-permissions a154be20-db9c-4678-8ab7-66f6cc099a59=Scope --only-show-errors # Delegated User.Read.All
# Upload cert to Azure AD
#
$certUploadRes = ConvertFrom-StringArray (az ad app credential reset --id $application.id --cert $certSubjectName --keyvault $keyVaultName --append --only-show-errors)
if (!$certUploadRes)
{
Write-Error "Failed to set certificate '$certSubjectName' as a credential for app registration '$applicationName'"
exit 1
}
# Remove the version from the secret ID if present
#
$secretId = $cert.sid
if ($secretId -Match "(https:\/\/[^\/]+\/secrets\/[^\/]+)(\/.*){0,1}$") {
if ($Matches[1]) {
$secretId = $Matches[1]
}
}
# Create the settings object to write to the Azure extension for SQL Server
#
$instanceSettings = @{
instanceName = $instanceName
adminLoginName = $adminAccountName
adminLoginSid = $adminAccountSid
azureCertSecretId = $secretId
azureCertUri = $cert.id
azureKeyVaultResourceUID = $keyVault.id
managedCertSetting = "CUSTOMER MANAGED CERT"
managedAppSetting = "CUSTOMER MANAGED APP"
appRegistrationName = $application.displayName
appRegistrationSid = $application.appId
tenantId = $tenantId
aadCertSubjectName = $certSubjectName
adminLoginType = $adminAccountType
}
$extension = ConvertFrom-StringArray (az connectedmachine extension show --machine-name $machineName --name "WindowsAgent.SqlServer" --resource-group $resourceGroupName)
if ($extension.properties.Settings.AzureAD)
{
$aadSettings = $extension.properties.Settings.AzureAD
$instanceFound = $false
$instanceNameLower = $instanceName.ToLower()
$instanceIndex = 0
for (($i = 0); $i -lt $aadSettings.Length; $i++)
{
if ($aadSettings[$i].instanceName.ToLower() -eq $instanceNameLower)
{
$instanceIndex = $i
$instanceFound = $true
break
}
}
if ($instanceFound)
{
$aadSettings[$instanceIndex] = $instanceSettings
}
else
{
$aadSettings += $instanceSettings
}
$extension.properties.Settings.AzureAD = $aadSettings
}
else
{
$aadSettings = , $instanceSettings
$extension.properties.Settings | Add-Member -Name 'AzureAD' -Value $aadSettings -MemberType NoteProperty
}
$settingsString = (ConvertTo-Json $extension.properties.Settings).replace("`"", "\`"").replace("`r`n", "")
# Push settings to Arc
#
Write-Host "Writing Azure AD setting to Azure extension for SQL Server. This may take several minutes..."
$updateRes = az connectedmachine extension update --machine-name $machineName --name "WindowsAgent.SqlServer" --resource-group $resourceGroupName --settings $settingsString
if (!$updateRes)
{
Write-Error "Failed to update Azure extension for SQL Server with Azure AD settings"
exit 1
}
Write-Output "Success"
指令碼可能需要幾分鐘的時間來完成執行。 當流程完成時,系統會出現類似下列內容的訊息:
Name Location ProvisioningState
---- -------- -----------------
WindowsAgent.SqlServer westus2 Succeeded
Success
使用 Azure CLI,以現有的證書和應用程式來設定 Microsoft Entra 管理員
如果您已有想用來設定 Microsoft Entra 管理員的現有 Azure Key Vault 證書及 Azure 應用程式,可以使用下列 CLI 指令碼:
# Set up Microsoft Entra admin for user's existing key vault, certificate, and application
# Requires input parameters indicated below
# Connect statement
AZ Login
#Input parameters
$subscriptionId="<subscriptionId>"
$tenantId="<tenantId>"
$machineName="<machineName>" # hostname
$instanceName="<instanceName>" # SQL Server is define as `machine_name\instance_name`
$resourceGroupName="<resourceGroupName>"
$keyVaultName="<keyVaultName>"
$certSubjectName="<certSubjectName>" # Your existing certificate name
$applicationName="<applicationName>" # Your existing application name
$adminAccountName="<adminAccountName>"
$adminAccountSid="<adminID>" # Use object ID for the Azure AD user and group, or client ID for the Azure AD application
$adminAccountType= 0 # 0 – for Azure AD user and application, 1 for Azure AD group
# Helper function
#
function ConvertFrom-StringArray {
param (
[string[]] $stringArray
)
if (!$stringArray)
{
return $null
}
else
{
return ConvertFrom-JSON ($stringArray -join "`n")
}
}
$keyVault = ConvertFrom-StringArray (az keyvault show --name $keyVaultName)
if (!$keyVault)
{
Write-Error "Azure key vault '$keyVaultName' does not exist"
exit 1
}
$cert = ConvertFrom-StringArray (az keyvault certificate show --name $certSubjectName --vault-name $keyVaultName 2>$null)
if (!$cert)
{
Write-Error "Supplied certificate $certSubjectName was not found for this key vault. Please specify an existing certificate"
exit 1
}
$secretId = $cert.sid
if ($secretId -Match "(https:\/\/[^\/]+\/secrets\/[^\/]+)(\/.*){0,1}$") {
if ($Matches[1]) {
$secretId = $Matches[1]
}
}
$application = ConvertFrom-StringArray (az ad app list --display-name $applicationName --only-show-errors)
if (!$application)
{
Write-Error "Supplied application was not found in the subscription. Please specify an existing application"
exit 1
}
# Create the settings object to write to the Arc extension
#
$instanceSettings = @{
instanceName = $instanceName
adminLoginName = $adminAccountName
adminLoginSid = $adminAccountSid
azureCertSecretId = $secretId
azureCertUri = $cert.id
azureKeyVaultResourceUID = $keyVault.id
managedCertSetting = "CUSTOMER MANAGED CERT"
managedAppSetting = "CUSTOMER MANAGED APP"
appRegistrationName = $application.displayName
appRegistrationSid = $application.appId
tenantId = $tenantId
aadCertSubjectName = $certSubjectName
adminLoginType = $adminAccountType
}
$extension = ConvertFrom-StringArray (az connectedmachine extension show --machine-name $machineName --name "WindowsAgent.SqlServer" --resource-group $resourceGroupName)
if ($extension.properties.Settings.AzureAD)
{
$aadSettings = $extension.properties.Settings.AzureAD
$instanceFound = $false
$instanceNameLower = $instanceName.ToLower()
$instanceIndex = 0
for (($i = 0); $i -lt $aadSettings.Length; $i++)
{
if ($aadSettings[$i].instanceName.ToLower() -eq $instanceNameLower)
{
$instanceIndex = $i
$instanceFound = $true
break
}
}
if ($instanceFound)
{
$aadSettings[$instanceIndex] = $instanceSettings
}
else
{
$aadSettings += $instanceSettings
}
$extension.properties.Settings.AzureAD = $aadSettings
}
else
{
$aadSettings = , $instanceSettings
$extension.properties.Settings | Add-Member -Name 'AzureAD' -Value $aadSettings -MemberType NoteProperty
}
$settingsString = (ConvertTo-Json $extension.properties.Settings).replace("`"", "\`"").replace("`r`n", "")
# Push settings to Arc
#
Write-Host "Writing Azure AD setting to SQL Server Arc Extension. This may take several minutes..."
$updateRes = az connectedmachine extension update --machine-name $machineName --name "WindowsAgent.SqlServer" --resource-group $resourceGroupName --settings $settingsString
if (!$updateRes)
{
Write-Error "Failed to update SQL Arc Extension with Azure AD settings"
exit 1
}
Write-Output "Success"
下列 PowerShell 指令碼會設定 Microsoft Entra 管理員,建立 Azure Key Vault 證書,以及建立 Microsoft Entra 應用程式。 如需在證書和應用程式已經存在時,設定 Microsoft Entra 管理員的指令碼範例,我們提供了一個額外的章節供參考。
注意
為 AMicrosoft Entra 設定所建立的證書不會自動輪替。
本教學課程需要下列模組。 安裝最新版的模組或高於下列所述的版本:
- Az.Accounts 3.37.0
- Az.ConnectedMachine 0.5.0
- Az.KeyVault 4.5.0
- Az.Resources 6.0.0
下列是 PowerShell 指令碼中使用的輸入參數:
<applicationName>
:將建立的應用程式名稱<certSubjectName>
:將建立的憑證名稱<keyVaultName>
:您的金鑰保存庫名稱。 執行指令碼之前,必須先建立此金鑰保存庫<machineName>
:您 SQL Server 主機的機器名稱<resourceGroupName>
:包含您 SQL Server – Azure Arc 執行個體的資源群組名稱<adminAccountName>
- 您想要為 SQL Server 設定的 Microsoft Entra 管理帳戶<instanceName>
:SQL Server 具名執行個體的參數 (選擇性)。 當您有具名的執行個體時,請使用此參數。 如果省略,則會使用MSSQLSERVER
為預設名稱<tenantId>
:適用於租用戶識別碼的選擇性參數。 前往 Azure 入口網站,然後前往您的 Microsoft Entra ID 資源,即可找到此租用戶識別碼。 在 [概觀] 窗格中,應該會看到您的租用戶識別碼。 如果省略,則會使用預設租用戶識別碼作為參數<subscriptionId>
:訂用帳戶識別碼的選擇性參數。 您可以在 Azure 入口網站中找到訂用帳戶識別碼。 如果省略,則會使用預設訂用帳戶識別碼
若要使用下列 PowerShell 指令碼,請將指令碼儲存為 .ps1
檔案,然後執行下列命令:
./aadPowerShellsetup.ps1 -applicationName "<applicationName>" -certSubjectName "<certSubjectName>" -keyVaultName "<keyVaultName>" -machineName "<machineName>" -resourceGroupName "<resourceGroupName>" -adminAccountName "<adminAccountName>" -instanceName "<instanceName>" -tenantId "<tenantId>" -subscriptionId "<subscriptionId>"
PowerShell 指令碼
針對 Linux 主機機器上的 SQL Server,請將指令碼中的 WindowsAgent.SqlServer
取代為 LinuxAgent.SqlServer
。
param (
[Parameter(mandatory=$true)] $applicationName,
[Parameter(mandatory=$true)] $certSubjectName,
[Parameter(mandatory=$true)] $keyVaultName,
[Parameter(mandatory=$true)] $machineName,
[Parameter(mandatory=$true)] $resourceGroupName,
[Parameter(mandatory=$true)] $adminAccountName,
$instanceName,
$tenantId,
$subscriptionId
)
Import-Module Az.Accounts
Import-Module Az.ConnectedMachine
Import-Module Az.KeyVault
Import-Module Az.Resources
# Constants
#
$NUMRETRIES = 60
# Check parameters
#
if ([string]::IsNullOrEmpty($instanceName))
{
Write-Host "Warning: SQL Instance name (-instanceName) not provided. Default of MSSQLSERVER will be used"
$instanceName = "MSSQLSERVER"
}
$tenantIdArgument = ""
if ([string]::IsNullOrEmpty($tenantId))
{
Write-Host "Warning: Tenant ID (-tenantId) not supplied to the script, so default tenant is being used"
}
else
{
$tenantIdArgument = "-TenantId '" + $tenantId + "'"
}
$subscriptionIdArgument = ""
if ([string]::IsNullOrEmpty($subscriptionId))
{
Write-Host "Warning: Subscription ID (-subscriptionId) not supplied to the script, so default subscription is being used"
}
else
{
$subscriptionIdArgument = "-SubscriptionId '" + $subscriptionId + "'"
}
# Login
#
try
{
$loginRes = Invoke-Expression -Command ("Connect-AzAccount " + $tenantIdArgument + " " + $subscriptionIdArgument + " -ErrorAction stop -UseDeviceAuthentication")
}
catch
{
Write-Error $_
Write-Error "Failed to login to Azure. Script can not continue"
exit 1
}
# Get subscription ID
#
if ([string]::IsNullOrEmpty($subscriptionId))
{
$context = Get-AzContext
if ($context)
{
if ($context.Name -Match "[^(]+\(([^)]{36})\)")
{
if ($Matches[1])
{
$subscriptionId = $Matches[1]
}
}
}
}
if ([string]::IsNullOrEmpty($subscriptionId))
{
Write-Error "Failed to find default subscription"
exit 1
}
# Check AKV path exists
#
$keyVault = Get-AzKeyVault -VaultName $keyVaultName
if (!$keyVault)
{
Write-Error "Supplied key vault was not found in the subscription. Please specify an existing key vault"
exit 1
}
# Check certificate doesn't exist
#
$cert = Get-AzKeyVaultCertificate -VaultName $keyVaultName -Name $certSubjectName
if ($cert)
{
Write-Error "Certificate $certSubjectName already exists"
exit 1
}
# Check app registration doesn't exist
#
$application = Get-AzADApplication -DisplayName $applicationName
if ($application)
{
Write-Error "Application $applicationName already exists"
exit 1
}
# Check Arc SQL instance is valid
#
$arcInstance = Get-AzConnectedMachineExtension -SubscriptionId $subscriptionId -MachineName $machineName -ResourceGroupName $resourceGroupName -Name "WindowsAgent.SqlServer"
if (!$arcInstance)
{
Write-Error "Could not find a SQL Server Arc instance in subscription '$subscriptionId' and resource group '$resourceGroupName' with name '$machineName'"
exit 1
}
# Check if admin account exists
#
$adminAccount = Get-AzADUser -UserPrincipalName $adminAccountName
$adminAccountType = 0
if (!$adminAccount)
{
# Check for guest user
#
$adminAccount = Get-AzADUser -Mail $adminAccountName
if (!$adminAccount)
{
$adminAccount = Get-AzADGroup -DisplayName $adminAccountName
if (!$adminAccount)
{
$adminAccount = Get-AzADServicePrincipal -DisplayName $adminAccountName
}
else
{
$adminAccountType = 1
}
}
}
if ($adminAccount)
{
if ($adminAccount.Length -gt 1)
{
Write-Error "Multiple accounts with found with name $adminAccountName"
exit 1
}
$adminAccountSid = $adminAccount.Id
}
else
{
Write-Error "Could not find an account with name $adminAccountName"
exit 1
}
# Create certificate in AKV
#
$Policy = New-AzKeyVaultCertificatePolicy -SecretContentType "application/x-pkcs12" -SubjectName "CN=$certSubjectName" -IssuerName "Self" -ValidityInMonths 12 -ReuseKeyOnRenewal
try
{
$addCertRes = Add-AzKeyVaultCertificate -VaultName $keyVaultName -Name $certSubjectName -CertificatePolicy $Policy -ErrorAction stop
}
catch
{
Write-Error $_
Write-Error "Certificate $certSubjectName could not be created"
exit 1
}
for (($i = 0); $i -lt $NUMRETRIES -and (!$cert -or !$cert.enabled); $i++)
{
$cert = Get-AzKeyVaultCertificate -VaultName $keyVaultName -Name $certSubjectName
if (!$cert -or !$cert.enabled)
{
Start-Sleep -Seconds 5
}
}
if (!$cert)
{
Write-Error "Certificate $certSubjectName could not be created"
exit 1
}
# Allow Arc to access AKV
#
$arcServicePrincipal = Get-AzADServicePrincipal -DisplayName $machineName
if ($arcServicePrincipal -and ![string]::IsNullOrEmpty($arcServicePrincipal.Id))
{
try
{
Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ObjectId $arcServicePrincipal.Id -PermissionsToSecrets Get,List -PermissionsToCertificates Get,List
}
catch
{
Write-Error $_
Write-Host "Warning: Could not find the identity of the Azure extension for SQL Server and thus, could not add permissions for the Arc process to read from AKV. Ensure the Arc identity has the required permissions to read from AKV."
}
}
else
{
Write-Host "Warning: Could not find the identity of the Azure extension for SQL Server and thus, could not add permissions for the Arc process to read from AKV. Ensure the Arc identity has the required permissions to read from AKV."
}
# Create an Azure AD application
#
$application = New-AzADApplication -DisplayName $applicationName
if (!$application)
{
Write-Error "Application could not be created"
exit 1
}
# Set perms on app registration
#
Add-AzADAppPermission -ObjectId $application.Id -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId c79f8feb-a9db-4090-85f9-90d820caa0eb # Delegated Application.Read.All
Add-AzADAppPermission -ObjectId $application.Id -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId 0e263e50-5827-48a4-b97c-d940288653c7 # Delegated Directory.AccessAsUser.All
Add-AzADAppPermission -ObjectId $application.Id -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId 7ab1d382-f21e-4acd-a863-ba3e13f7da61 -Type Role # Application Directory.Read.All
Add-AzADAppPermission -ObjectId $application.Id -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId 5f8c59db-677d-491f-a6b8-5f174b11ec1d # Delegated Group.Read.All
Add-AzADAppPermission -ObjectId $application.Id -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId a154be20-db9c-4678-8ab7-66f6cc099a59 # Delegated User.Read.All
# Upload cert to Azure AD
#
try
{
$base64Cert = [System.Convert]::ToBase64String($cert.Certificate.GetRawCertData())
New-AzADAppCredential -ApplicationObject $application -CertValue $base64Cert -EndDate $cert.Certificate.NotAfter -StartDate $cert.Certificate.NotBefore -ErrorAction stop
}
catch
{
Write-Error $_
Write-Error "Failed to add certificate to app registration"
exit 1
}
# Remove the version from the secret ID if present
#
$secretId = $cert.SecretId
if ($secretId -Match "(https:\/\/[^\/]+\/secrets\/[^\/]+)(\/.*){0,1}$") {
if ($Matches[1]) {
$secretId = $Matches[1]
}
}
# Create the settings object to write to the Azure extension for SQL Server
#
$instanceSettings = @{
instanceName = $instanceName
adminLoginName = $adminAccountName
adminLoginSid = $adminAccountSid
azureCertSecretId = $secretId.replace(":443", "")
azureCertUri = $cert.Id.replace(":443", "")
azureKeyVaultResourceUID = $keyVault.ResourceId
managedCertSetting = "CUSTOMER MANAGED CERT"
managedAppSetting = "CUSTOMER MANAGED APP"
appRegistrationName = $application.DisplayName
appRegistrationSid = $application.AppId
tenantId = $tenantId
aadCertSubjectName = $certSubjectName
adminLoginType = $adminAccountType
}
$arcInstance = Get-AzConnectedMachineExtension -SubscriptionId $subscriptionId -MachineName $machineName -ResourceGroupName $resourceGroupName -Name "WindowsAgent.SqlServer"
if ($arcInstance.Setting.AdditionalProperties.AzureAD)
{
$aadSettings = $arcInstance.Setting.AdditionalProperties.AzureAD
$instanceFound = $false
$instanceNameLower = $instanceName.ToLower()
$instanceIndex = 0
for (($i = 0); $i -lt $aadSettings.Length; $i++)
{
if ($aadSettings[$i].instanceName.ToLower() -eq $instanceNameLower)
{
$instanceIndex = $i
$instanceFound = $true
break
}
}
if ($instanceFound)
{
$aadSettings[$instanceIndex] = $instanceSettings
}
else
{
$aadSettings += $instanceSettings
}
$arcInstance.Setting.AdditionalProperties.AzureAD = $aadSettings
}
else
{
$aadSettings = , $instanceSettings
$arcInstance.Setting.AdditionalProperties | Add-Member -Name 'AzureAD' -Value $aadSettings -MemberType NoteProperty
}
Write-Host "Writing Microsoft Entra setting to SQL Server Arc Extension. This may take several minutes..."
# Push settings to Arc
#
try
{
Update-AzConnectedMachineExtension -MachineName $machineName -Name "WindowsAgent.SqlServer" -ResourceGroupName $resourceGroupName -Setting $arcInstance.Setting
}
catch
{
Write-Error $_
Write-Error "Failed to write settings to Arc host"
exit 1
}
Write-Output "Success"
使用 PowerShell,以現有的證書和應用程式來設定 Microsoft Entra 管理員
如果您已有想用來設定 Microsoft Entra 管理員的現有 Azure Key Vault 證書及 Azure 應用程式,可以使用下列 PowerShell 指令碼:
# Connect statement
Connect-AzAccount
#Input parameters
$subscriptionId="<subscriptionId>"
$tenantId="<tenantId>"
$machineName="<machineName>" # hostname
$instanceName="<instanceName>" # SQL Server is define as `machine_name\instance_name`
$resourceGroupName="<resourceGroupName>"
$keyVaultName="<keyVaultName>"
$certSubjectName="<certSubjectName>" # Your existing certificate name
$applicationName="<applicationName>" # Your existing application name
$adminAccountName="<adminAccountName>"
$adminAccountSid="<adminID>" # Use object ID for the Microsoft Entra user and group, or client ID for the Microsoft Entra application
$adminAccountType= 0 # 0 – for Microsoft Entra user and application, 1 for Microsoft Entra group
$keyVault = Get-AzKeyVault -VaultName $keyVaultName
if (!$keyVault)
{
Write-Error "Supplied key vault was not found in the subscription. Please specify an existing key vault"
exit 1
}
$cert = Get-AzKeyVaultCertificate -VaultName $keyVaultName -Name $certSubjectName
if (!$cert)
{
Write-Error "Supplied certificate $certSubjectName was not found for this key vault. Please specify an existing certificate"
exit 1
}
$secretId = $cert.SecretId
if ($secretId -Match "(https:\/\/[^\/]+\/secrets\/[^\/]+)(\/.*){0,1}$") {
if ($Matches[1]) {
$secretId = $Matches[1]
}
}
$application = Get-AzADApplication -DisplayName $applicationName
if (!$application)
{
Write-Error "Supplied application was not found in the subscription. Please specify an existing application"
exit 1
}
# Create the settings object to write to the Arc extension
#
$instanceSettings = @{
instanceName = $instanceName
adminLoginName = $adminAccountName
adminLoginSid = $adminAccountSid
azureCertSecretId = $secretId.replace(":443", "")
azureCertUri = $cert.Id.replace(":443", "")
azureKeyVaultResourceUID = $keyVault.ResourceId
managedCertSetting = "CUSTOMER MANAGED CERT"
managedAppSetting = "CUSTOMER MANAGED APP"
appRegistrationName = $application.DisplayName
appRegistrationSid = $application.AppId
tenantId = $tenantId
aadCertSubjectName = $certSubjectName
adminLoginType = $adminAccountType
}
$arcInstance = Get-AzConnectedMachineExtension -SubscriptionId $subscriptionId -MachineName $machineName -ResourceGroupName $resourceGroupName -Name "WindowsAgent.SqlServer"
if ($arcInstance.Setting.AdditionalProperties.AzureAD)
{
$aadSettings = $arcInstance.Setting.AdditionalProperties.AzureAD
$instanceFound = $false
$instanceNameLower = $instanceName.ToLower()
$instanceIndex = 0
for (($i = 0); $i -lt $aadSettings.Length; $i++)
{
if ($aadSettings[$i].instanceName.ToLower() -eq $instanceNameLower)
{
$instanceIndex = $i
$instanceFound = $true
break
}
}
if ($instanceFound)
{
$aadSettings[$instanceIndex] = $instanceSettings
}
else
{
$aadSettings += $instanceSettings
}
$arcInstance.Setting.AdditionalProperties.AzureAD = $aadSettings
}
else
{
$aadSettings = , $instanceSettings
$arcInstance.Setting.AdditionalProperties | Add-Member -Name 'AzureAD' -Value $aadSettings -MemberType NoteProperty
}
Write-Host "Writing Microsoft Entra setting to SQL Server Arc Extension. This may take several minutes..."
# Push settings to Arc
#
try
{
Update-AzConnectedMachineExtension -MachineName $machineName -Name "WindowsAgent.SqlServer" -ResourceGroupName $resourceGroupName -Setting $arcInstance.Setting
}
catch
{
Write-Error $_
Write-Error "Failed to write settings to Arc host"
exit 1
}
Write-Output "Success"
下列 ARM 範本會使用現有的 Azure Key Vault 證書和 Microsoft Entra 應用程式來設定 Microsoft Entra 管理員。
下列是 ARM 範本中使用的輸入參數:
<machineName>
:您 SQL Server 主機的機器名稱<Location>
:SQL Server – Azure Arc 資源群組的位置,例如West US
或Central US
<tenantId>
- 前往 Azure 入口網站,然後前往您的 Microsoft Entra ID 資源,即可找到租用戶識別碼。 在 [概觀] 窗格中,應該會看到您的租用戶識別碼<instanceName>
:SQL Server 執行個體名稱。 SQL Server 的預設執行個體名稱為MSSQLSERVER
<certSubjectName>
:您所建立的憑證名稱<subscriptionId>
:訂用帳戶識別碼。 您可以在 Azure 入口網站中找到訂閱識別碼<resourceGroupName>
:包含金鑰保存庫的資源群組名稱。 若要找到完整的 azureKeyVaultResourceUID 值,請移至您的 [金鑰保存庫] 資源,選取 [屬性] 並複製 [資源識別碼]<keyVaultName>
:您的金鑰保存庫名稱<certIdentifier>
:Azure Key Vault 憑證的憑證識別碼。 若要取得憑證識別碼,請移至您的 [金鑰保存庫] 資源,然後選取 [設定] 下的 [憑證]。 選取您建立的憑證目前版本,然後複製 [憑證識別碼] 的值。 如需詳細資訊,請參閱將憑證新增至 Key Vault<certSecret>
:憑證的祕密識別碼,可以在與憑證識別碼相同的功能表中找到<applicationName>
- 您建立的 Microsoft Entra 應用程式名稱<appID>
- 您可以在應用程式的 [概觀] 功能表上找到 Microsoft Entra 應用程式的應用程式 (用戶端) 識別碼<adminAccountName>
- 您想要為 SQL Server 設定的 Microsoft Entra 管理帳戶<adminID>
- 如果打算使用另一個應用程式作為 Microsoft Entra 管理員帳戶,則為 Microsoft Entra 使用者或群組的物件識別碼,或應用程式 (用戶端) 識別碼。 如需詳細資訊,請參閱《教學課程:使用 Microsoft Entra 應用程式建立 Microsoft Entra 使用者》<adminType>
- 將0
用於 Microsoft Entra 使用者和應用程式,將1
用於 Microsoft Entra 群組
使用 Azure 入口網站中的自訂部署,然後在編輯器中建置您自己的範本。 接下來,將設定貼進範例之後,加以儲存。
注意
針對 Linux 主機機器上的 SQL Server,請將指令碼中的 WindowsAgent.SqlServer
取代為 LinuxAgent.SqlServer
。
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"resources": [
{
"type": "Microsoft.HybridCompute/machines/extensions",
"apiVersion": "2022-03-10",
"name": "<machineName>/WindowsAgent.SqlServer",
"location": "<Location>",
"properties": {
"publisher": "Microsoft.AzureData",
"type": "WindowsAgent.SqlServer",
"settings": {
"AzureAD": [
{
"tenantId": "<tenantId>",
"instanceName": "<instanceName>",
"managedCertSetting": "CUSTOMER MANAGED CERT",
"aadCertSubjectName": "<certSubjectName>",
"azureKeyVaultResourceUID": "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>",
"azureCertUri": "<certIdentifier>",
"azureCertSecretId": "<certSecret>",
"managedAppSetting": "CUSTOMER MANAGED APP",
"appRegistrationName": "<applicationName>",
"appRegistrationSid": "<appID>",
"adminLoginName": "<adminAccountName>",
"adminLoginSid" : "<adminID>",
"adminLoginType": 0
}
]
}
}
}
]
}
為應用程式授與管理員同意
設定 Microsoft Entra 管理員之後,使用 Microsoft Entra 管理員認證便可連線至 SQL Server。 不過,任何涉及建立新 Microsoft Entra 登入和使用者的進一步資料庫活動都會失敗,直到將管理員同意授與 Microsoft Entra 應用程式為止。
注意
若要為應用程式授與管理員同意,授與同意的帳戶需要具有 Microsoft Entra ID 全域管理員或特殊權限角色管理員的角色。 這些角色是授與應用程式管理員同意的必要角色,但設定 Microsoft Entra 管理員時則非必要。
在 Azure 入口網站中,選取 [Microsoft Entra ID]>[應用程式註冊],然後選取新建立的應用程式。 應用程式的名稱應該類似
<hostname>-<instanceName><uniqueNumber>
。選取 [API 權限] 功能表。
選取 [授與管理員同意]。
若未對應用程式授與管理員同意,在 SQL Server 中建立 Microsoft Entra 登入或使用者將會導致下列錯誤:
Msg 37455, Level 16, State 1, Line 2
Server identity does not have permissions to access MS Graph.
使用 Microsoft Entra 驗證連線到 SQL Server
系統目前已為連線至 Azure Arc 的 SQL Server 建立 Microsoft Entra 驗證。在依照本文建立 Microsoft Entra 管理員後,請遵循教學課程:設定適用於 SQL Server 的 Microsoft Entra 驗證,以使用 Microsoft Entra 驗證連線至 SQL Server章節。
另請參閱
意見反應
此頁面對您有幫助嗎?