如何:通过 Azure PowerShell 使用证书创建服务主体How to: Use Azure PowerShell to create a service principal with a certificate

当某个应用或脚本需要访问资源时,用户可以为该应用设置一个标识,并使用其自身的凭据进行身份验证。When you have an app or script that needs to access resources, you can set up an identity for the app and authenticate the app with its own credentials. 此标识称为服务主体。This identity is known as a service principal. 使用此方法可实现以下目的:This approach enables you to:

  • 将不同于自己的权限的权限分配给应用标识。Assign permissions to the app identity that are different than your own permissions. 通常情况下,这些权限仅限于应用需执行的操作。Typically, these permissions are restricted to exactly what the app needs to do.
  • 执行无人参与的脚本时,使用证书进行身份验证。Use a certificate for authentication when executing an unattended script.

重要

请考虑使用 Azure 资源的托管标识作为应用程序标识,而不是创建服务主体。Instead of creating a service principal, consider using managed identities for Azure resources for your application identity. 如果代码在支持托管标识的服务上运行并访问支持 Azure Active Directory (Azure AD) 身份验证的资源,则托管标识是更好的选择。If your code runs on a service that supports managed identities and accesses resources that support Azure Active Directory (Azure AD) authentication, managed identities are a better option for you. 若要详细了解 Azure 资源的托管标识(包括当前支持它的服务),请参阅什么是 Azure 资源的托管标识?To learn more about managed identities for Azure resources, including which services currently support it, see What is managed identities for Azure resources?.

本文演示如何创建使用证书进行身份验证的服务主体。This article shows you how to create a service principal that authenticates with a certificate. 若要使用密码设置服务主体,请参阅使用 Azure PowerShell 创建 Azure 服务主体To set up a service principal with password, see Create an Azure service principal with Azure PowerShell.

必须拥有最新版本 PowerShell 才能演练本文中的示例。You must have the latest version of PowerShell for this article.

备注

本文进行了更新,以便使用新的 Azure PowerShell Az 模块。This article has been updated to use the new Azure PowerShell Az module. 你仍然可以使用 AzureRM 模块,至少在 2020 年 12 月之前,它将继续接收 bug 修补程序。You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. 若要详细了解新的 Az 模块和 AzureRM 兼容性,请参阅新 Azure Powershell Az 模块简介To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. 有关 Az 模块安装说明,请参阅安装 Azure PowerShellFor Az module installation instructions, see Install Azure PowerShell.

所需的权限Required permissions

若要完成本文,必须在 Azure AD 和 Azure 订阅中均有足够的权限。To complete this article, you must have sufficient permissions in both your Azure AD and Azure subscription. 具体而言,必须能够在 Azure AD 中创建应用并向角色分配服务主体。Specifically, you must be able to create an app in the Azure AD, and assign the service principal to a role.

检查帐户是否有足够权限的最简方法是使用门户。The easiest way to check whether your account has adequate permissions is through the portal. 请参阅检查所需的权限See Check required permission.

将应用程序分配给角色Assign the application to a role

要访问订阅中的资源,必须将应用程序分配到角色。To access resources in your subscription, you must assign the application to a role. 判定哪个角色能为应用程序提供适当的权限。Decide which role offers the right permissions for the application. 若要了解可用角色,请参阅 Azure 内置角色To learn about the available roles, see Azure built-in roles.

可将作用域设置为订阅、资源组或资源级别。You can set the scope at the level of the subscription, resource group, or resource. 较低级别的作用域会继承权限。Permissions are inherited to lower levels of scope. 例如,将某个应用程序添加到资源组的“读者” 角色意味着该应用程序可以读取该资源组及其包含的所有资源。For example, adding an application to the Reader role for a resource group means it can read the resource group and any resources it contains. 若要允许应用程序执行诸如“重新启动”、“启动”和“停止”实例之类的操作,请选择“参与者”角色 。To allow the application to execute actions like reboot, start and stop instances, select the Contributor role.

使用自签名证书创建服务主体Create service principal with self-signed certificate

下面的示例介绍了简单的方案。The following example covers a simple scenario. 它使用 New-AzADServicePrincipal 创建具有自签名证书的服务主体,并使用 New-AzRoleAssignment读者角色分配给该服务主体。It uses New-AzADServicePrincipal to create a service principal with a self-signed certificate, and uses New-AzRoleAssignment to assign the Reader role to the service principal. 角色分配的范围限定为当前所选 Azure 订阅。The role assignment is scoped to your currently selected Azure subscription. 若要选择其他订阅,请使用 Set-AzContextTo select a different subscription, use Set-AzContext.

备注

New-SelfSignedCertificate cmdlet 和 PKI 模块目前在 PowerShell Core 中不受支持。The New-SelfSignedCertificate cmdlet and the PKI module are currently not supported in PowerShell Core.

$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" `
  -Subject "CN=exampleappScriptCert" `
  -KeySpec KeyExchange
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())

$sp = New-AzADServicePrincipal -DisplayName exampleapp `
  -CertValue $keyValue `
  -EndDate $cert.NotAfter `
  -StartDate $cert.NotBefore
Sleep 20
New-AzRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $sp.ApplicationId

该示例休眠 20 秒,让新的服务主体有时间传遍 Azure AD。The example sleeps for 20 seconds to allow some time for the new service principal to propagate throughout Azure AD. 如果脚本没有等待足够长的时间,则会显示一个错误,指出:“主体 {ID} 不存在于目录 {DIR-ID} 中”。If your script doesn't wait long enough, you'll see an error stating: "Principal {ID} does not exist in the directory {DIR-ID}." 若要解决此错误,请等待片刻,然后重新运行 New-AzRoleAssignment 命令。To resolve this error, wait a moment then run the New-AzRoleAssignment command again.

可以使用 ResourceGroupName 参数将角色分配范围限制为特定资源组。You can scope the role assignment to a specific resource group by using the ResourceGroupName parameter. 还可以使用 ResourceTypeResourceName 参数将范围限制为特定资源。You can scope to a specific resource by also using the ResourceType and ResourceName parameters.

如果未使用 Windows 10 或 Windows Server 2016,需要从 Microsoft 脚本中心下载自签名证书生成器If you do not have Windows 10 or Windows Server 2016, you need to download the Self-signed certificate generator from Microsoft Script Center. 解压其内容,并导入所需的 cmdlet。Extract its contents and import the cmdlet you need.

# Only run if you could not use New-SelfSignedCertificate
Import-Module -Name c:\ExtractedModule\New-SelfSignedCertificateEx.ps1

在脚本中替换以下两行代码以生成证书。In the script, substitute the following two lines to generate the certificate.

New-SelfSignedCertificateEx -StoreLocation CurrentUser `
  -Subject "CN=exampleapp" `
  -KeySpec "Exchange" `
  -FriendlyName "exampleapp"
$cert = Get-ChildItem -path Cert:\CurrentUser\my | where {$PSitem.Subject -eq 'CN=exampleapp' }

通过自动执行的 PowerShell 脚本提供证书Provide certificate through automated PowerShell script

以服务主体方式登录时,需提供 AD 应用所在目录的租户 ID。Whenever you sign in as a service principal, you need to provide the tenant ID of the directory for your AD app. 租户是 Azure AD 的实例。A tenant is an instance of Azure AD.

$TenantId = (Get-AzSubscription -SubscriptionName "Contoso Default").TenantId
$ApplicationId = (Get-AzADApplication -DisplayNameStartWith exampleapp).ApplicationId

 $Thumbprint = (Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -eq "CN=exampleappScriptCert" }).Thumbprint
 Connect-AzAccount -ServicePrincipal `
  -CertificateThumbprint $Thumbprint `
  -ApplicationId $ApplicationId `
  -TenantId $TenantId `
  -Environment AzureChinaCloud

使用证书颁发机构提供的证书创建服务主体Create service principal with certificate from Certificate Authority

以下示例使用证书颁发机构颁发的证书创建服务主体。The following example uses a certificate issued from a Certificate Authority to create service principal. 分配的范围限定为指定的 Azure 订阅。The assignment is scoped to the specified Azure subscription. 它将服务主体添加到读者角色。It adds the service principal to the Reader role. 如果在角色分配过程中发生错误,它会重试分配。If an error occurs during the role assignment, it retries the assignment.

Param (
 [Parameter(Mandatory=$true)]
 [String] $ApplicationDisplayName,

 [Parameter(Mandatory=$true)]
 [String] $SubscriptionId,

 [Parameter(Mandatory=$true)]
 [String] $CertPath,

 [Parameter(Mandatory=$true)]
 [String] $CertPlainPassword
 )

 Connect-AzAccount -Environment AzureChinaCloud
 Import-Module Az.Resources
 Set-AzContext -Subscription $SubscriptionId
 
 $CertPassword = ConvertTo-SecureString $CertPlainPassword -AsPlainText -Force

 $PFXCert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @($CertPath, $CertPassword)
 $KeyValue = [System.Convert]::ToBase64String($PFXCert.GetRawCertData())

 $ServicePrincipal = New-AzADServicePrincipal -DisplayName $ApplicationDisplayName
 New-AzADSpCredential -ObjectId $ServicePrincipal.Id -CertValue $KeyValue -StartDate $PFXCert.NotBefore -EndDate $PFXCert.NotAfter
 Get-AzADServicePrincipal -ObjectId $ServicePrincipal.Id 

 $NewRole = $null
 $Retries = 0;
 While ($NewRole -eq $null -and $Retries -le 6)
 {
    # Sleep here for a few seconds to allow the service principal application to become active (should only take a couple of seconds normally)
    Sleep 15
    New-AzRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $ServicePrincipal.ApplicationId | Write-Verbose -ErrorAction SilentlyContinue
    $NewRole = Get-AzRoleAssignment -ObjectId $ServicePrincipal.Id -ErrorAction SilentlyContinue
    $Retries++;
 }
 
 $NewRole

通过自动执行的 PowerShell 脚本提供证书Provide certificate through automated PowerShell script

以服务主体方式登录时,需提供 AD 应用所在目录的租户 ID。Whenever you sign in as a service principal, you need to provide the tenant ID of the directory for your AD app. 租户是 Azure AD 的实例。A tenant is an instance of Azure AD.

Param (
 
 [Parameter(Mandatory=$true)]
 [String] $CertPath,

 [Parameter(Mandatory=$true)]
 [String] $CertPlainPassword,
 
 [Parameter(Mandatory=$true)]
 [String] $ApplicationId,

 [Parameter(Mandatory=$true)]
 [String] $TenantId
 )

 $CertPassword = ConvertTo-SecureString $CertPlainPassword -AsPlainText -Force
 $PFXCert = New-Object `
  -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 `
  -ArgumentList @($CertPath, $CertPassword)
 $Thumbprint = $PFXCert.Thumbprint

 Connect-AzAccount -ServicePrincipal `
  -CertificateThumbprint $Thumbprint `
  -ApplicationId $ApplicationId `
  -TenantId $TenantId `
  -Environment AzureChinaCloud

应用程序 ID 和租户 ID 不敏感,因此可以直接将它们嵌入脚本中。The application ID and tenant ID aren't sensitive, so you can embed them directly in your script. 如果需要检索租户 ID,请使用:If you need to retrieve the tenant ID, use:

(Get-AzSubscription -SubscriptionName "Contoso Default").TenantId

如果需要检索应用程序 ID,请使用:If you need to retrieve the application ID, use:

(Get-AzADApplication -DisplayNameStartWith {display-name}).ApplicationId

更改凭据Change credentials

若要更改 AD 应用的凭据(由于安全性损害或凭据过期),请使用 Remove-AzADAppCredentialNew-AzADAppCredential cmdlet。To change the credentials for an AD app, either because of a security compromise or a credential expiration, use the Remove-AzADAppCredential and New-AzADAppCredential cmdlets.

若要删除应用程序的所有凭据,请使用:To remove all the credentials for an application, use:

Get-AzADApplication -DisplayName exampleapp | Remove-AzADAppCredential

要添加证书值,请按本文所示创建自签名证书。To add a certificate value, create a self-signed certificate as shown in this article. 然后,使用:Then, use:

Get-AzADApplication -DisplayName exampleapp | New-AzADAppCredential `
  -CertValue $keyValue `
  -EndDate $cert.NotAfter `
  -StartDate $cert.NotBefore

调试Debug

创建服务主体时,可能会收到以下错误:You may get the following errors when creating a service principal:

  • “Authentication_Unauthorized”或“在上下文中找不到订阅”。 "Authentication_Unauthorized" or "No subscription found in the context." - 如果帐户不具有在 Azure AD 上注册应用所需的权限,会看到此错误。- You see this error when your account doesn't have the required permissions on the Azure AD to register an app. 通常,当只有 Azure Active Directory 中的管理员用户可注册应用且帐户不是管理员帐户时,会看到此错误。可要求管理员分配管理员角色,或者允许用户注册应用。Typically, you see this error when only admin users in your Azure Active Directory can register apps, and your account isn't an admin. Ask your administrator to either assign you to an administrator role, or to enable users to register apps.

  • 帐户“不具有对作用域‘/subscriptions/{guid}’执行操作‘Microsoft.Authorization/roleAssignments/write’的权限”。 - 当帐户不具有足够权限将角色分配给标识时,会看到此错误。Your account "does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/write' over scope '/subscriptions/{guid}'." - You see this error when your account doesn't have sufficient permissions to assign a role to an identity. 可要求订阅管理员将你添加到“用户访问管理员”角色。Ask your subscription administrator to add you to User Access Administrator role.

后续步骤Next steps