我正在尝试从Azure Keyvault获得证书,然后使用它来调用需要证书进行身份验证的REST API。
我尝试在本地执行此操作-我在磁盘上有.pfx
文件,将其加载到字节数组中,然后从中创建证书:
X509Certificate2 x509 = new X509Certificate2(File.ReadAllBytes(path), password);
然后在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
}
像魅力一样工作。
现在,我尝试执行相同的操作,但是要从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();
[这也可行-我可以使用我的应用程序身份访问密钥仓库,并且可以从密钥仓库获取证书,并且X.509指纹有效-但这现在是CertificateBundle
名称空间中的Microsoft.Azure.KeyVault.Models
-如何将其“转换”为“常规” X509Certificate2
对象,以便可以将其用于REST调用?
例如,我尝试过几件事
X509Certificate2 x509 = new X509Certificate2(vaultCertificate.Cer);
但没有任何效果-当我发起REST调用时,我收到HTTP 403-禁止错误返回...。
我想念什么?如何从Azure Keyvault中获取可用于在后续REST调用中进行身份验证的格式的证书?
当然-在发布此问题后,我偶然发现了解决方案...。
此blog post by Matt Small对其进行了详尽的解释(并提供了非常不错的[代码示例)。
基本上,为了使用证书进行身份验证,您也需要具有私钥-并且当您执行GetCertificateAsync
时,您只获取证书的公共信息。您需要获取证书
作为秘密,然后对base64进行解码-然后,您将获得所有必需的位,并且REST调用起作用。
哎呀!为什么这真是令人费解?为什么在includePrivate: bool
调用中不能仅存在一个GetCertificateAsync
参数来告诉Keyvault,您是否只需要证书的公共部分或公共和
私有部分? 您存储证书-但是要获取证书,您需要获取一个秘密....那完全是错误的,并且违反了[最不惊讶的基本原理!
] MS,如果您正在监听-此API确实需要做更多的工作才能使新手Azure开发人员更易于使用!和PS:当然,这也意味着您用来访问密钥库的用户/身份现在需要权限
来读取机密-不仅仅是证书.....var cert = kvc.GetCertificateAsync(baseUrl, "Demo").ConfigureAwait(false).GetAwaiter().GetResult();
var cert_content = cert.Cer;
X509Certificate2 x509 = new X509Certificate2(cert_content);
您可以轻松地从CertificateBundle
获取证书的原始字节,然后使用原始字节创建X509Certificate2实例。