从 Azure Batch 访问 Azure Key Vault

Accessing Azure Key Vault from Azure Batch

我正在尝试从我的 Azure Batch 节点池中的 VM 运行访问我的 Azure Key Vault 中的机密。

不过,我一直运行宁入异常:

异常消息:已尝试 1 个证书。无法获取访问令牌。

带有指纹 MY-THUMBPRINT 的证书 #1 异常:密钥集不存在

到目前为止,我一直在按照此处列出的说明进行操作: https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

文章概述了 Azure Batch 的场景,并指出我应该使用服务主体。我想确保版本控制中没有秘密或密钥,所以我使用本地密钥库中证书的第一种方法登录 Azure AD。

运行 以下所有本地可执行文件工作正常,但在 Azure Batch 池节点上 运行 时失败。

到目前为止,我执行上述操作的步骤是:

  1. 在密钥库中创建服务主体和关联证书: az ad sp create-for-rbac --name myserviceprincipal --create-cert --cert mycertname --keyvault mykeyvaultname。保留服务主体应用程序 ID 和租户 ID,以便在 AzureServicesAuthConnectionString 中使用。

  2. 为创建的服务主体创建密钥保管库访问策略(在 Azure 门户 UI 中完成)。

  3. 以 PFX/PEM 格式下载创建的证书(在 Azure 门户 UI 中完成)。

  4. 确保证书上有 PFX 密码(我这样做是因为在第 6 步中将证书上传到 azure batch 需要关联的密码):https://coombes.nz/blog/azure-keyvault-export-certificate/

# Replace these variables with your own values
$vaultName = "YOUR-KEYVAULT-NAME"
$certificateName = "YOUR-CERTIFICATE-NAME"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "$certificateName.pfx"
$password = "YOUR-CERTIFICATE-PASSWORD"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
$pfx = New-Object Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($pfxUnprotectedBytes, $null, [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfxProtectedBytes = $pfx.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $password)
[IO.File]::WriteAllBytes($pfxPath, $pfxProtectedBytes)
  1. 正在将证书本地安装到我计算机的 LocalMachine 存储区(用于本地测试)。

  2. 正在将证书上传到 Azure Batch(使用 Azure 门户 UI 上传)。

  3. 将证书与适当的节点池相关联并重新启动节点(目前使用 Azure 门户 UI)。

我在 Azure Batch 上的应用程序包 运行ning 是一个简单的控制台可执行文件。 AzureServicesAuthConnectionString 设置为 RunAs=App;AppId={AppId};TenantId={TenantId};CertificateThumbprint={Thumbprint};CertificateStoreLocation={LocalMachine},用于检索秘密的其余密钥保管库代码如下所示:

Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString", "RunAs=App;AppId=<MY-APP-ID>;TenantId=<MY-TENANT>;CertificateThumbprint=<MY-THUMBPRINT>;CertificateStoreLocation=LocalMachine");

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("<MY-SECRET>").ConfigureAwait(false);
var message = secret.Value;
Console.WriteLine(message);

在本地一切正常,但在远程节点上失败。我能够通过 RDP 连接到 Azure Batch 节点并看到证书已安装到本地计算机。

我想知道如何解决我的错误,或者我的上述步骤是否在某些方面有误?

除上述内容外,我还遵循了 Sam Cogan 文章中的说明: https://samcogan.com/secure-credential-access-with-azure-batch-and-keyvault/

但是我收到了与原始问题相同的问题。我对 Sam Cogan 文章的错误和相关的重现步骤是:

Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: RunAs=App;AppId=<My Service Principal ID>;TenantId=<My Tenant ID>;CertificateThumbprint=<My cert thumbprint>;CertificateStoreLocation=LocalMachine, Resource: https://vault.azure.net, Authority: https://login.windows.net/<My Tenant ID>. Exception Message: Tried 1 certificate(s). Access token could not be acquired.
Exception for cert #1 with thumbprint <My cert thumbprint>: Keyset does not exist

我的重现步骤是:

  1. 创建证书(我添加了 -a sha256 -len 2048 部分,因为我在此处列出并解决了相同的错误:
C:\Program Files (x86)\Windows Kits\bin\x64> .\makecert.exe -sv batchcertificate6.pvk -n "cn=andybatch6.cert.mydomain.org" batchcertificate6.cer -r -pe -a sha256 -len 2048
  1. 将步骤 1 中的证书转换为 PFX 格式:
C:\Program Files (x86)\Windows Kits\bin\x64> .\pvk2pfx.exe -pvk batchcertificate6.pvk -spc batchcertificate6.cer -pfx batchcertificate7.pfx -po <MyPassword>  -pi <MyPassword>  
  1. 创建 ActiveDirectory 应用程序和服务主体并关联并上传创建的证书:
#Point the script at the cer file you created 

$cerCertificateFilePath = 'C:\Program Files (x86)\Windows Kits\bin\x64\batchcertificate6.cer' 
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 
$cer.Import($cerCertificateFilePath)

#Load the certificate into memory 
$credValue = [System.Convert]::ToBase64String($cer.GetRawCertData()) 

#Create a new AAD application that uses this certifcate 
$newADApplication = New-AzureRmADApplication -DisplayName "<My display name>" -HomePage "<my url>" -IdentifierUris " <my url>" -certValue $credValue 

#Create new AAD service principle that uses this application 
$newAzureAdPrincipal = New-AzureRmADServicePrincipal -ApplicationId $newADApplication.ApplicationId
  1. G运行t 服务主体的 Key Vault 访问权限(我在 UI 中添加了额外的权限,但也通过命令行添加了 运行):
Set-AzureRmKeyVaultAccessPolicy -VaultName 'myvaultname' -ServicePrincipalName '<my url>' -PermissionsToSecrets 'Get'
  1. 通过门户将证书 (pfx) 上传到 Azure Batch。将它作为 LocalMachine 与我的节点池相关联并重新启动节点。 运行 具有如下连接字符串的应用程序:
Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString",
                    "RunAs=App;" +
                    "AppId=<the app id of my active directory app registration> ;" +
                    "TenantId=<my subscription tenant id>;" +
                    "CertificateThumbprint=<the thumbprint of my cert>;" +
                    "CertificateStoreLocation=LocalMachine");

                AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
                KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                var secret = await keyVaultClient.GetSecretAsync("https://<my vault name>.vault.azure.net/secrets/<secret name>/<secret id>")
                        .ConfigureAwait(false);
                message = secret.Value;
                Console.WriteLine(message);

我的代码使用上述连接字符串在本地使用安装的证书,但在 Azure Batch 上 运行 时出现上述异常。

为了访问证书,必须为 'Current User.' 关联和安装它可能是 LocalMachine 没有适当级别的权限?

在 Azure Batch 上,确保上传的证书关联于:

店铺名称:'My' 店铺位置:'CurrentUser'

这个 post 很有帮助:https://github.com/nabhishek/customactivity_sample/tree/linkedservice

就像这样 post:X509Certificate - Keyset does not exist

C# exe 中的连接字符串如下所示:

Environment.SetEnvironmentVariable("AzureServicesAuthConnectionString",
                    "RunAs=App;" +
                    "AppId=<the app id of my active directory app registration> ;" +
                    "TenantId=<my subscription tenant id>;" +
                    "CertificateThumbprint=<the thumbprint of my cert>;" +
                    "CertificateStoreLocation=CurrentUser");

                AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(Environment.GetEnvironmentVariable("AzureServicesAuthConnectionString"));
                KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                var secret = await keyVaultClient.GetSecretAsync("https://<my vault name>.vault.azure.net/secrets/<secret name>/<secret id>")
                        .ConfigureAwait(false);
                message = secret.Value;
                Console.WriteLine(message);