当通过 IKeyVaultClient.GetCertificateAsync 检索 Azure Key Vault 证书时,证书不包含私钥。

19

我有两种方法可以做同一件事情,但Azure已弃用了可以工作的那个方法,而另一个方法则不起作用。

仍然有效但已弃用的方法:

我将我的PFX存储在Azure Key Vault Secrets中。(当我创建密钥时,我会看到一个警告说明该功能已被弃用)

并使用以下代码检索它以创建我的证书:

        SecretBundle secret = await keyVaultClient.GetSecretAsync(keyVaultUrl, "MyCert-Secret");
        X509Certificate2Collection exportedCertCollection = new X509Certificate2Collection();
        exportedCertCollection.Import(Convert.FromBase64String(secret.Value));
        X509Certificate2 certFromSecret = exportedCertCollection.Cast<X509Certificate2>().Single(s => s.HasPrivateKey);

致谢此答案

我能够使用此证书成功地托管和访问我的应用程序。

不起作用但我应该使用的方法:

我将证书存储在Azure密钥保管库证书中,并使用以下代码检索它并创建X509Certificate2:

        CertificateBundle certificateBundle = await keyVaultClient.GetCertificateAsync(keyVaultUrl, "MyCert-Certificate");
        X509Certificate2 certFromCertificate = new X509Certificate2(certificateBundle.Cer);

这种方法的问题在于证书不包含私钥,即 certFromCertificate.HasPrivateKey 为 false。

我的问题

为什么 certFromSecret 具有 PrivateKey,而 certFromCertificate 没有?

我该如何从密钥保管库中检索证书,在那里我可以创建一个 X509Certificate2 对象以在 Kestrel 中使用 UseHttps 主机我的应用程序。


1
@Adriano 谢谢。你回答的后半部分帮助我解决了问题。关键点在于AKV证书有3个组成部分 - 密钥、秘密和证书,以及你对每个部分存储的内容的详细说明。我将我代码的更改发布出来供其他人参考。 - Nandun
你是否找到了合适的解决方案? - Davy
@Davy 发布的答案是我所采用的方法。 - Nandun
2
虽然建议的重复问题https://dev59.com/XVcP5IYBdhLWcg3wyc7W有很好的细节说明为什么它不起作用,但它实际上并没有展示如何使用C#代码。看起来这个问题实际上是关于C#版本的 - 因此重新标记并投票重新打开。 - Alexei Levenkov
2个回答

35
@Adrian的答案的第二部分非常清晰地解释了Azure KV证书的概念,我已经按照下面的代码更改了我的代码以获取包括私钥在内的完整证书:
        SecretBundle secret = await kv.GetSecretAsync(keyVaultUrl, certName);
        X509Certificate2 certificate = 
                 new X509Certificate2(Convert.FromBase64String(secret.Value));

关键是要使用GetSecretAsync而不是GetCertificateAsync。请参考Adrian的SO回答,了解为什么必须使用密钥来获取具有私钥的完整证书。

请注意,您应该从Azure证书属性页面中使用“证书标识符”属性(带有“/secrets/”的URL)。


5
非常感谢您在这里发布回答。您所提到的答案只包含PowerShell代码,而这里需要的是干净的C#代码。微软必须在文档中明确说明GetCertificateAsync()方法不会从保险库中检索有用的证书。 - Michael Chudinov
我投票支持重新开放这个问题,因为“重复”是关于PowerShell的,而这个问题是关于C#的。然而,由于我无法发布新答案,我在这里提供了一个更完整的工作方法来检索所有带有私钥的证书。 - Tobias J
你可能想提及这篇文章,其中包含有关如何解决运行上述代码时可能遇到的异常的提示:https://dotnetcoretutorials.com/2020/11/19/loading-certificates-from-azure-key-vault-in-net-and-getting-it-working-in-azure-app-service/ - Claus Appel
当检索私钥时,此方法会抛出错误。 “PrivateKey = 'x509Certificate.PrivateKey'引发了'System.Security.Cryptography.CryptographicException'类型的异常” - Kurkula

9

SDK的最新版本 (Azure.Security.KeyVault.Certificates 4.2.0) 现在提供了DownloadCertificateAsync方法,该方法可以轻松地获取完整的证书(即包括私钥)。

文档说明如下:

因为Cer文件只包含公钥,所以此方法将尝试下载包含完整证书的托管密钥。

X509Certificate2 cert = await certificateClient.DownloadCertificateAsync(certName);


2
托管标识需要哪些RBAC权限才能调用该方法?我可以使用“Key Vault Certificates Officer”使其正常工作,但我有点不愿意让我的托管标识具有证书的写入访问权限。您知道是否可以使用任何级别的只读访问权限来使其正常工作吗?(“Reader”不够用。) - Claus Appel
在检索私钥时,该方法会抛出不对称异常。 - Kurkula
对我来说完美运行-版本4.5.0,谢谢! - Dany

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接