azure - 使用服务主体对 Azure 函数应用进行身份验证的正确方法是什么?

标签 azure

我有一些代码想要使用 Azure 函数应用程序实现自动化。该代码用于云治理目的,仅供治理团队内部使用。该代码的目的是检索有关公共(public) IP 地址的信息并将其写入 blob。它每天都会自动执行此操作。

我想使用专用的云治理服务主体而不是用户帐户来执行操作。如何验证该功能的服务主体?我是否需要使用 Key Vault 并在代码中进行身份验证?如果是这样,我如何授予该函数使用 Key Vault 的权限?

最佳答案

高级步骤是:

  1. 创建 AAD 应用程序(服务主体)。为其分配您想要的任何权限。
  2. 创建 key 保管库
  3. 在 Key Vault 中创建证书(请参阅下面的 CreateKVSPNertificate.ps1)
  4. 将该证书添加到 AAD 应用程序(请参阅下面的 CreateKVSPNertificate.ps1)
  5. 为 Azure Function 应用创建托管标识
  6. 向 Function 应用的托管身份授予 Key Vault 上的“获取 secret ”权限
  7. 在您的 Functions 代码中,使用 AzureServiceTokenProvider 以及 KeyVault 的连接字符串来将您的 Functions 代码验证为步骤 #1 中的服务主体。 (请参阅下面的 GetAuthCredsFromKeyVault)

创建KVSPNertificate.ps1

# This script will have Key Vault create a certificate and associate the certificate with an Azure AD Application.  
# This allows applications to get the private key (secret) from Key Vault to authenticate as the service principal associated with the Azure AD app.

[CmdletBinding()]
param(
  [Parameter(Mandatory = $true)]
  [String]$keyVaultName,
  [Parameter(Mandatory = $true)]
  [String]$appId,
  [Parameter()]
  [int]$validityInMonths = 12
)

# Key Vault will create a certificate, returning the cert from this function so the public key can be added to the AAD Application
function New-KeyVaultSelfSignedCert {
    param($keyVault, $certificateName, $subjectName, $validityInMonths, $renewDaysBefore)

    # Define the configuration for how the certificate will be created
    $policy = New-AzKeyVaultCertificatePolicy `
                -SubjectName $subjectName `
                -ReuseKeyOnRenewal `
                -IssuerName 'Self' `
                -ValidityInMonths $validityInMonths `
                -RenewAtNumberOfDaysBeforeExpiry $renewDaysBefore

    # Have Key Vault create the certificate.  This returns an operation status that needs to be waited on until it is complete
    $op = Add-AzKeyVaultCertificate `
                -VaultName $keyVault `
                -CertificatePolicy $policy `
                -Name $certificateName

    if ($op -eq $null)
    {
        # Certificate may have been soft-deleted which means the name is still reserved.
        if ((Get-AzKeyVaultCertificate -VaultName $keyvault -InRemovedState).Count -gt 0)
        {
            # Purge the soft deleted key and try adding the new one again
            # If the Purge fails with "Operation returned an invalid status code 'Forbidden'", then make sure your account explicitly has the Purge feature enabled in the Key Vault Access Policies (this access is not automatically granted)
            Write-Host "Previous certificate with same name $certificateName was in soft-delete state.  Attempting to Purge previous certificate and create new one.  Purge may take some time, in case of failure retry after a couple minutes."
            Remove-AzKeyVaultCertificate -VaultName $keyVault -Name $certificateName -InRemovedState -Force
            Start-Sleep -Seconds 15
            $op = Add-AzKeyVaultCertificate `
                -VaultName $keyVault `
                -CertificatePolicy $policy `
                -Name $certificateName
        }
    }

    while ( $op.Status -eq 'inProgress' ) 
    {
        Start-Sleep -Seconds 1
        $op = Get-AzKeyVaultCertificateOperation -VaultName $keyVault -Name $certificateName
    }
    if ($op.Status -ne 'completed')
    {
        Write-Error "Add-AzKeyVaultCertificate failed to complete"
        Write-Error $op
        return $null
    }

    # Get the certificate that was just created and return it.  This gets the public cert, not the private cert
    (Get-AzKeyVaultCertificate -VaultName $keyVault -Name $certificateName).Certificate
}

# Get the Azure AD Application in order to get the display name
$existingApp = Get-AzADApplication -ApplicationId $appId
$appName = $existingApp.DisplayName

if ($existingApp = $null)
{
    Write-Error "Couldn't find existing AAD Application $appId"
    break
}

# Have Key Vault create a certificate
$certName = "SPCert-" + $appName
$cert = New-KeyVaultSelfSignedCert -keyVault $keyVaultName `
                                   -certificateName $certName `
                                   -subjectName "CN=$appName" `
                                   -validityInMonths $validityInMonths `
                                   -renewDaysBefore 1

if ($cert -eq $null) { break }

Write-Output ""
Write-Output "Certificate generated with:"
Write-Output "   Thumbprint = $($cert.Thumbprint)"
Write-Output "   Secret Name = $certName"
$certString = [Convert]::ToBase64String($cert.GetRawCertData())
# Associate the public key with the Azure AD Application
New-AzADAppCredential -ApplicationId $appId -CertValue $certString -EndDate $cert.NotAfter.AddDays(-1)

在函数代码中,使用 Key Vault 证书进行身份验证

        private AzureCredentials GetAuthCredsFromKeyVault()
        {
            string AuthVaultName = System.Environment.GetEnvironmentVariable("AuthVaultName");
            string AuthAppId = System.Environment.GetEnvironmentVariable("AuthAppId");
            string AuthSecretName = System.Environment.GetEnvironmentVariable("AuthSecretName");
            string connectionString = string.Format("RunAs = App; AppId = {0}; KeyVaultCertificateSecretIdentifier = https://{1}.vault.azure.net/secrets/{2}", AuthAppId, AuthVaultName, AuthSecretName);

            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(connectionString);
            string accessTokenARM = azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com").Result;
            string accessTokenGraph = azureServiceTokenProvider.GetAccessTokenAsync("https://graph.windows.net").Result;
            AzureCredentials creds = new AzureCredentials(new TokenCredentials(accessTokenARM), new TokenCredentials(accessTokenGraph), Constants.TenantId, AzureEnvironment.AzureGlobalCloud);

            return creds;
        }

关于azure - 使用服务主体对 Azure 函数应用进行身份验证的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60441870/

相关文章:

azure - 如何针对特定 LUIS 意图开始对话?

azure - 在 Terraform 中创建和链接 Azure 资源

java - 在 java 中使用 log4j 进行 Application Insights 日志记录

c# - 如何将 azure 排队消息发送到 azure sql 数据库

javascript - 如何在 JavaScript 中定义本地文件的路径

c# - Azure AD OAuth2 访问 token 请求错误 - 400 错误请求

python - 如何使用 Prefect 在 AKS 上部署 Kubernetes 作业

c# - 使用字符串方法查询Iothub设备孪生标签

c# - 使用 Python SDK 按 RowKey 和 StartsWith 筛选 Azure 表存储

Azure-函数应用程序的 zip 推送部署不起作用