从 Azure Keyvault 获取 X509 证书以在 REST 调用中使用

mar*_*c_s 1 rest x509certificate azure-keyvault

我正在尝试从 Azure Keyvault 获取证书,然后使用它来调用需要证书进行身份验证的 REST API。

我尝试在本地执行此操作 - 我将.pfx文件放在磁盘上,将其加载到字节数组中,然后从中创建我的证书:

X509Certificate2 x509 = new X509Certificate2(File.ReadAllBytes(path), password);
Run Code Online (Sandbox Code Playgroud)

然后在 RestSharp 中使用该证书来执行我的 REST 调用:

IRestClient client = new RestClient(url);
client.ClientCertificates = new X509CertificateCollection { x509 };

var request = new RestRequest(lastUrlPart, Method.GET);
request.AddHeader("Cache-Control", "no-cache");
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");

IRestResponse response = client.Execute(request);

if (response.IsSuccessful)
{
    // read out the response and process it
}
Run Code Online (Sandbox Code Playgroud)

奇迹般有效。

现在我正在尝试做同样的事情,但从 Azure Keyvault 获取证书。我在 Azure AD 中创建了一个应用注册,创建了我的密钥保管库,并授予了我的应用注册的服务标识访问密钥保管库的权限。我已将我的证书上传到密钥库中。到现在为止还挺好。

我找到了从 Keyvault 获取证书的代码:

var azureServiceTokenProvider = new AzureServiceTokenProvider();

var kv = new KeyVaultClient(async (authority, resource, scope) =>
                                        {
                                            var authContext = new AuthenticationContext(authority, TokenCache.DefaultShared);
                                            var clientCred = new ClientCredential(clientAppId, clientSecret);
                                            var result = await authContext.AcquireTokenAsync(resource, clientCred);

                                            if (result == null)
                                            {
                                                throw new InvalidOperationException("Failed to obtain the JWT token");
                                            }

                                            return result.AccessToken;
                                        });

string certIdentifier = "https://mykeyvault.vault.azure.net/certificates/Certificate-TEST/14753af7586445fe9d57efa136ac090c";

var vaultCertificate = kv.GetCertificateAsync(certIdentifier).GetAwaiter().GetResult();
Run Code Online (Sandbox Code Playgroud)

这也有效 - 我可以使用我的应用程序身份访问密钥库,我可以从密钥库中获取证书,并且 X.509 指纹是有效的 - 但现在这是CertificateBundle来自Microsoft.Azure.KeyVault.Models命名空间的 - 我如何将其“转换”为一个“常规”X509Certificate2对象,以便我可以将它用于 REST 调用?

我已经尝试了几件事,例如

X509Certificate2 x509 = new X509Certificate2(vaultCertificate.Cer);
Run Code Online (Sandbox Code Playgroud)

但没有任何效果 - 当我发出 REST 调用时,我收到一个 HTTP 403 - Forbidden 错误......

我错过了什么??如何以可用于在后续 REST 调用中进行身份验证的格式从 Azure Keyvault 获取证书?

mar*_*c_s 7

当然 - 在我发布这个问题之后,我偶然发现了解决方案......

Matt Small 的这篇博文非常详细地解释了它(并且还提供了非常好的和有效的代码示例)。

基本上,为了使用证书进行身份验证,您也需要拥有私钥 - 当您执行 a 时GetCertificateAsync,您只能取回证书的公共信息。

您需要获取证书作为秘密,然后对它进行 base64 解码 - 然后您获得所有必要的位并且 REST 调用工作。

天啊!!怎么这么纠结??如果您只需要证书的公共部分,或者公共部分私有部分,为什么不能includePrivate: boolGetCertificateAsync调用中只存在一个参数来告诉 Keyvault ?

你存储了一个证书——但要得到它,你需要获取一个秘密......这完全是错误的,并且违反了最小惊喜基本原则!MS,如果你在听——这个 API 真的需要做更多的工作才能让 Azure 开发新手更容易上手!!

PS:这当然也意味着您用来访问密钥库的用户/身份现在需要读取机密的权限- 不仅仅是证书.....

  • 嘿,太棒了。我自己也偶然发现了这个问题,并且可以跟随您了解这个 API。 (2认同)