您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

使用 Azure PowerShell 创建服务主体来访问资源Use Azure PowerShell to create a service principal to access resources

当有应用或脚本需访问资源时,可以为应用设置一个标识,并使用其自己的凭据对应用进行身份验证。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 PowerShell 为应用程序进行一切所需设置,使之能够使用自己的凭据和标识运行。This topic shows you how to use Azure PowerShell to set up everything you need for an application to run under its own credentials and identity.

所需的权限Required permissions

若要完成本主题,必须在 Azure Active Directory 和 Azure 订阅中均具有足够的权限。To complete this topic, you must have sufficient permissions in both your Azure Active Directory and your Azure subscription. 具体而言,必须能够在 Azure Active Directory 中创建应用并向角色分配服务主体。Specifically, you must be able to create an app in the Azure Active Directory, 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.

现在,继续完成进行身份验证的部分:Now, proceed to a section for authenticating with:

PowerShell 命令PowerShell commands

若要设置服务主体,请使用:To set up a service principal, you use:

命令Command 说明Description
New-AzureRmADServicePrincipalNew-AzureRmADServicePrincipal 创建 Azure Active Directory 服务主体Creates an Azure Active Directory service principal
New-AzureRmRoleAssignmentNew-AzureRmRoleAssignment 在指定范围内将指定的 RBAC 角色分配给指定的主体。Assigns the specified RBAC role to the specified principal, at the specified scope.

使用密码创建服务主体Create service principal with password

若要使用订阅的参与者角色创建服务主体,请使用:To create a service principal with the Contributor role for your subscription, use:

Login-AzureRmAccount
$password = convertto-securestring {provide-password} -asplaintext -force
$sp = New-AzureRmADServicePrincipal -DisplayName exampleapp -Password $password
Sleep 20
New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $sp.ApplicationId

该示例休眠 20 秒,让新的服务主体有时间传遍 Azure Active Directory。The example sleeps for 20 seconds to allow some time for the new service principal to propagate throughout Azure Active Directory. 如果脚本等待时长不足,会显示错误:“PrincipalNotFound: 主体 {ID} 不存在于目录中”。If your script does not wait long enough, you see an error stating: "PrincipalNotFound: Principal {ID} does not exist in the directory."

使用以下脚本可以指定默认订阅以外的范围,并在出错时重试角色分配:The following script enables you to specify a scope other than the default subscription, and retries the role assignment if an error occurs:

Param (

 # Use to set scope to resource group. If no value is provided, scope is set to subscription.
 [Parameter(Mandatory=$false)]
 [String] $ResourceGroup,

 # Use to set subscription. If no value is provided, default subscription is used. 
 [Parameter(Mandatory=$false)]
 [String] $SubscriptionId,

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

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

 Login-AzureRmAccount
 Import-Module AzureRM.Resources

 if ($SubscriptionId -eq "") 
 {
    $SubscriptionId = (Get-AzureRmContext).Subscription.Id
 }
 else
 {
    Set-AzureRmContext -SubscriptionId $SubscriptionId
 }

 if ($ResourceGroup -eq "")
 {
    $Scope = "/subscriptions/" + $SubscriptionId
 }
 else
 {
    $Scope = (Get-AzureRmResourceGroup -Name $ResourceGroup -ErrorAction Stop).ResourceId
 }


 # Create Service Principal for the AD app
 $ServicePrincipal = New-AzureRMADServicePrincipal -DisplayName $ApplicationDisplayName -Password $Password
 Get-AzureRmADServicePrincipal -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-AzureRMRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $ServicePrincipal.ApplicationId -Scope $Scope | Write-Verbose -ErrorAction SilentlyContinue
    $NewRole = Get-AzureRMRoleAssignment -ObjectId $ServicePrincipal.Id -ErrorAction SilentlyContinue
    $Retries++;
 }

关于该脚本的几个注意事项:A few items to note about the script:

  • 若要授予对默认订阅的标识访问权限,不必提供 ResourceGroup 或 SubscriptionId 参数。To grant the identity access to the default subscription, you do not need to provide either ResourceGroup or SubscriptionId parameters.
  • 仅当希望将角色分配范围限定为某个资源组时指定 ResourceGroup 参数。Specify the ResourceGroup parameter only when you want to limit the scope of the role assignment to a resource group.
  • 在此示例中,将服务主体添加到“参与者”角色。In this example, you add the service principal to the Contributor role. 对于其他角色,请参阅 RBAC:内置角色For other roles, see RBAC: Built-in roles.
  • 该脚本休眠 15 秒,让新的服务主体有时间传遍 Azure Active Directory。The script sleeps for 15 seconds to allow some time for the new service principal to propagate throughout Azure Active Directory. 如果脚本等待时长不足,会显示错误:“PrincipalNotFound: 主体 {ID} 不存在于目录中”。If your script does not wait long enough, you see an error stating: "PrincipalNotFound: Principal {ID} does not exist in the directory."
  • 如果需要授予对更多订阅或资源组的服务主体访问权限,则再次针对不同的作用域运行 New-AzureRMRoleAssignment cmdlet。If you need to grant the service principal access to more subscriptions or resource groups, run the New-AzureRMRoleAssignment cmdlet again with different scopes.

通过 PowerShell 提供凭据Provide credentials through PowerShell

现在,需要以应用程序方式登录以执行相应操作。Now, you need to log in as the application to perform operations. 对于用户名,请使用为应用程序创建的 ApplicationIdFor the user name, use the ApplicationId that you created for the application. 对于密码,请使用在创建帐户时指定的密码。For the password, use the one you specified when creating the account.

$creds = Get-Credential
Login-AzureRmAccount -Credential $creds -ServicePrincipal -TenantId {tenant-ID}

租户 ID 不敏感,因此可以直接将其嵌入脚本中。The tenant ID is not sensitive, so you can embed it directly in your script. 如果需要检索租户 ID,请使用:If you need to retrieve the tenant ID, use:

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

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

若要使用自签名证书和订阅的参与者角色创建服务主体,请使用:To create a service principal with a self-signed certificate and the Contributor role for your subscription, use:

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

$sp = New-AzureRMADServicePrincipal -DisplayName exampleapp -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore
Sleep 20
New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $sp.ApplicationId

该示例休眠 20 秒,让新的服务主体有时间传遍 Azure Active Directory。The example sleeps for 20 seconds to allow some time for the new service principal to propagate throughout Azure Active Directory. 如果脚本等待时长不足,会显示错误:“PrincipalNotFound: 主体 {ID} 不存在于目录中”。If your script does not wait long enough, you see an error stating: "PrincipalNotFound: Principal {ID} does not exist in the directory."

使用以下脚本可以指定默认订阅以外的范围,并在出错时重试角色分配。The following script enables you to specify a scope other than the default subscription, and retries the role assignment if an error occurs. 必须在 Windows 10 或 Windows Server 2016 上使用 Azure PowerShell 2.0。You must have Azure PowerShell 2.0 on Windows 10 or Windows Server 2016.

Param (

 # Use to set scope to resource group. If no value is provided, scope is set to subscription.
 [Parameter(Mandatory=$false)]
 [String] $ResourceGroup,

 # Use to set subscription. If no value is provided, default subscription is used. 
 [Parameter(Mandatory=$false)]
 [String] $SubscriptionId,

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

 Login-AzureRmAccount
 Import-Module AzureRM.Resources

 if ($SubscriptionId -eq "") 
 {
    $SubscriptionId = (Get-AzureRmContext).Subscription.Id
 }
 else
 {
    Set-AzureRmContext -SubscriptionId $SubscriptionId
 }

 if ($ResourceGroup -eq "")
 {
    $Scope = "/subscriptions/" + $SubscriptionId
 }
 else
 {
    $Scope = (Get-AzureRmResourceGroup -Name $ResourceGroup -ErrorAction Stop).ResourceId
 }

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

 $ServicePrincipal = New-AzureRMADServicePrincipal -DisplayName $ApplicationDisplayName -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore
 Get-AzureRmADServicePrincipal -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-AzureRMRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $ServicePrincipal.ApplicationId -Scope $Scope | Write-Verbose -ErrorAction SilentlyContinue
    $NewRole = Get-AzureRMRoleAssignment -ObjectId $ServicePrincipal.Id -ErrorAction SilentlyContinue
    $Retries++;
 }

关于该脚本的几个注意事项:A few items to note about the script:

  • 若要授予对默认订阅的标识访问权限,不必提供 ResourceGroup 或 SubscriptionId 参数。To grant the identity access to the default subscription, you do not need to provide either ResourceGroup or SubscriptionId parameters.
  • 仅当希望将角色分配范围限定为某个资源组时指定 ResourceGroup 参数。Specify the ResourceGroup parameter only when you want to limit the scope of the role assignment to a resource group.
  • 在此示例中,将服务主体添加到“参与者”角色。In this example, you add the service principal to the Contributor role. 对于其他角色,请参阅 RBAC:内置角色For other roles, see RBAC: Built-in roles.
  • 该脚本休眠 15 秒,让新的服务主体有时间传遍 Azure Active Directory。The script sleeps for 15 seconds to allow some time for the new service principal to propagate throughout Azure Active Directory. 如果脚本等待时长不足,会显示错误:“PrincipalNotFound: 主体 {ID} 不存在于目录中”。If your script does not wait long enough, you see an error stating: "PrincipalNotFound: Principal {ID} does not exist in the directory."
  • 如果需要授予对更多订阅或资源组的服务主体访问权限,则再次针对不同的作用域运行 New-AzureRMRoleAssignment cmdlet。If you need to grant the service principal access to more subscriptions or resource groups, run the New-AzureRMRoleAssignment cmdlet again with different scopes.

如果未使用 Windows 10 或 Windows Server 2016 Technical Preview,需要从 Microsoft 脚本中心下载自签名证书生成器If you do not have Windows 10 or Windows Server 2016 Technical Preview, 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 -StoreName My -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 Active Directory 的实例。A tenant is an instance of Azure Active Directory. 如果只有一个订阅,可以使用:If you only have one subscription, you can use:

Param (

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

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

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

 $Thumbprint = (Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -match $CertSubject }).Thumbprint
 Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $Thumbprint -ApplicationId $ApplicationId -TenantId $TenantId

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

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

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

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

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

若要使用证书颁发机构颁发的证书创建服务主体,请使用以下脚本:To use a certificate issued from a Certificate Authority to create service principal, use the following script:

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

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

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

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

 Login-AzureRmAccount
 Import-Module AzureRM.Resources
 Set-AzureRmContext -SubscriptionId $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-AzureRMADServicePrincipal -DisplayName $ApplicationDisplayName
 New-AzureRmADSpCredential -ObjectId $ServicePrincipal.Id -CertValue $KeyValue -StartDate $PFXCert.NotBefore -EndDate $PFXCert.NotAfter
 Get-AzureRmADServicePrincipal -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-AzureRMRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $ServicePrincipal.ApplicationId | Write-Verbose -ErrorAction SilentlyContinue
    $NewRole = Get-AzureRMRoleAssignment -ObjectId $ServicePrincipal.Id -ErrorAction SilentlyContinue
    $Retries++;
 }

 $NewRole

关于该脚本的几个注意事项:A few items to note about the script:

  • 访问范围限定于订阅。Access is scoped to the subscription.
  • 在此示例中,将服务主体添加到“参与者”角色。In this example, you add the service principal to the Contributor role. 对于其他角色,请参阅 RBAC:内置角色For other roles, see RBAC: Built-in roles.
  • 该脚本休眠 15 秒,让新的服务主体有时间传遍 Azure Active Directory。The script sleeps for 15 seconds to allow some time for the new service principal to propagate throughout Azure Active Directory. 如果脚本等待时长不足,会显示错误:“PrincipalNotFound: 主体 {ID} 不存在于目录中”。If your script does not wait long enough, you see an error stating: "PrincipalNotFound: Principal {ID} does not exist in the directory."
  • 如果需要授予对更多订阅或资源组的服务主体访问权限,则再次针对不同的作用域运行 New-AzureRMRoleAssignment cmdlet。If you need to grant the service principal access to more subscriptions or resource groups, run the New-AzureRMRoleAssignment cmdlet again with different scopes.

通过自动执行的 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 Active Directory 的实例。A tenant is an instance of Azure Active Directory.

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

 Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $Thumbprint -ApplicationId $ApplicationId -TenantId $TenantId

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

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

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

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

更改凭据Change credentials

若要更改 AD 应用的凭据(为了保障安全或由于凭据过期的缘故),请使用 Remove-AzureRmADAppCredentialNew-AzureRmADAppCredential cmdlet。To change the credentials for an AD app, either because of a security compromise or a credential expiration, use the Remove-AzureRmADAppCredential and New-AzureRmADAppCredential cmdlets.

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

Remove-AzureRmADAppCredential -ApplicationId 8bc80782-a916-47c8-a47e-4d76ed755275 -All

若要添加密码,请使用:To add a password, use:

New-AzureRmADAppCredential -ApplicationId 8bc80782-a916-47c8-a47e-4d76ed755275 -Password p@ssword!

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

New-AzureRmADAppCredential -ApplicationId 8bc80782-a916-47c8-a47e-4d76ed755275 -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore

保存访问令牌来简化登录Save access token to simplify log in

若要避免每次登录时都需要提供服务主体凭据,可保存访问令牌。To avoid providing the service principal credentials every time it needs to log in, you can save the access token.

若要在以后的会话中使用当前访问令牌,请保存该配置文件。To use the current access token in a later session, save the profile.

Save-AzureRmProfile -Path c:\Users\exampleuser\profile\exampleSP.json

打开该配置文件,并检查其内容。Open the profile and examine its contents. 请注意,它包含访问令牌。Notice that it contains an access token. 无需再次手动登录,只需加载配置文件。Instead of manually logging in again, load the profile.

Select-AzureRmProfile -Path c:\Users\exampleuser\profile\exampleSP.json

备注

访问令牌会过期,因此使用保存的配置文件仅适合在令牌有效期间使用。The access token expires, so using a saved profile only works for as long as the token is valid.

也可从要登录的 PowerShell 调用 REST 操作。Alternatively, you can invoke REST operations from PowerShell to log in. 可以从身份验证响应中检索访问令牌,将其用于其他操作。From the authentication response, you can retrieve the access token for use with other operations. 若要通过示例来了解如何通过调用 REST 操作来检索访问令牌,请参阅生成访问令牌For an example of retrieving the access token by invoking REST operations, see Generating an Access Token.

调试Debug

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

  • “Authentication_Unauthorized”或“在上下文中找不到订阅”。"Authentication_Unauthorized" or "No subscription found in the context." - 如果帐户不具有在 Azure Active Directory 上注册应用所需的权限,会收到此错误。- You see this error when your account does not have the required permissions on the Azure Active Directory 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 is not 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 does not have sufficient permissions to assign a role to an identity. 请要求订阅管理员你将添加到用户访问管理员角色。Ask your subscription administrator to add you to User Access Administrator role.

示例应用程序Sample applications

有关在不同平台上通过应用程序登录的信息,请参阅:For information about logging in as the application through different platforms, see:

后续步骤Next steps