我正在尝试从Azure批处理节点池中运行的VM访问Azure密钥保管库中的机密。
但是,我不断遇到异常:
异常消息:尝试过1个证书。无法获取访问令牌。
带有指纹MY-THUMBPRINT的证书#1的异常:密钥集不存在
到目前为止,我一直在遵循此处概述的说明: https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication
本文概述了Azure Batch的方案,并指示我应使用服务主体。我想确保版本控制中没有秘密或密钥,因此我正在使用本地密钥库中证书的第一种方法登录Azure AD。
以可执行文件本地方式运行以下所有程序,但在Azure批处理池节点上运行时失败。
到目前为止,我要做的步骤是:
在密钥库中创建服务主体和相关证书:
az ad sp create-for-rbac --name myserviceprincipal --create-cert --cert mycertname --keyvault mykeyvaultname
。保留要在AzureServicesAuthConnectionString中使用的服务主体应用ID和租户ID。
为创建的服务主体创建密钥库访问策略(在azure门户UI中完成)。
以PFX / PEM格式下载创建的证书(在Azure Portal UI中完成)。
确保证书上的PFX密码(我正在执行此操作,因为在步骤6中将证书上传到天蓝色的批次需要关联的密码):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)
将证书本地安装到计算机的LocalMachine存储中(用于本地测试)。
将证书上传到Azure Batch(使用Azure Portal UI上传)。
将证书与适当的节点池关联并重新启动节点(暂时使用Azure Portal UI)。
我在Azure Batch上运行的应用程序包是一个简单的控制台可执行文件。 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节点,并看到已经为本地计算机安装了证书。
我想知道如何解决我的错误,或者上述步骤是否在某种程度上是错误的?
答案 0 :(得分:0)
除上述内容外,我还按照此处的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
我的复制步骤是:
C:\Program Files (x86)\Windows Kits\10\bin\x64> .\makecert.exe -sv batchcertificate6.pvk -n "cn=andybatch6.cert.mydomain.org" batchcertificate6.cer -r -pe -a sha256 -len 2048
C:\Program Files (x86)\Windows Kits\10\bin\x64> .\pvk2pfx.exe -pvk batchcertificate6.pvk -spc batchcertificate6.cer -pfx batchcertificate7.pfx -po <MyPassword> -pi <MyPassword>
#Point the script at the cer file you created
$cerCertificateFilePath = 'C:\Program Files (x86)\Windows Kits\10\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
Set-AzureRmKeyVaultAccessPolicy -VaultName 'myvaultname' -ServicePrincipalName '<my url>' -PermissionsToSecrets 'Get'
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上运行时具有上述异常。
答案 1 :(得分:0)
为了访问证书,必须将其与“当前用户”关联并安装。可能是LocalMachine没有适当级别的权限?
在Azure Batch上,确保上载的证书与以下内容关联:
商店名称:“我的” 商店位置:“ CurrentUser”
此帖子很有帮助:https://github.com/nabhishek/customactivity_sample/tree/linkedservice
该帖子也是如此: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);