KeyVault生成带有可导出私钥的证书

时间:2017-05-07 22:27:15

标签: powershell x509 private-key azure-powershell azure-keyvault

我尝试使用" Self"在 KeyVault中创建自签名证书。发行者。

$policy = New-AzureKeyVaultCertificatePolicy -SubjectName "CN=$($certificateName)" -IssuerName "Self" -ValidityInMonths 12 

$policy.Exportable = $true

Add-AzureKeyVaultCertificate -VaultName $vaultName -Name $certificateName -CertificatePolicy $policy

然而,当获得证书时,它似乎没有私钥。

直接在KeyVault中创建证书似乎并没有在线,在深入研究了PowerShell cmdlet的其余API文档和源代码之后,我很难解决。

我希望我能错过一些简单的事情,因为我希望避免在本地创建证书..

2 个答案:

答案 0 :(得分:22)

如果您想要检索证书及其私钥,则可以通过以下方式将其导出到磁盘上的PFX文件(使用空密码):

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
[IO.File]::WriteAllBytes($pfxPath, $pfxUnprotectedBytes)

如果您想在内存中查看私钥本身而不写入磁盘,请尝试:

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"

$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)
$pfx.PrivateKey.ExportParameters($true)

除了指数和模数外,还将显示私有参数。

如果您想使用自己的密码保护磁盘上的PFX文件(根据"检索pfx文件&添加密码" this blog post中的说明),则尝试:

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"
$password = "my-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)

如REST API文档herehere中所述,Azure Key Vault(AKV)通过三个相互关联的资源代表给定的X.509证书:AKV证书,AKV密钥,和一个AKV秘密。这三个将共享相同的名称和相同的版本 - 为了验证这一点,请检查来自Id的响应中的KeyIdSecretIdGet-AzureKeyVaultCertificate属性。

这三种资源中的每一种都为查看给定的X.509证书提供了不同的视角:

  • AKV证书提供X.509证书的公钥和证书元数据。它包含公钥的模数和指数(ne),以及其他证书元数据(指纹,有效期,主题名称等)。在PowerShell中,您可以通过以下方式获取此信息:
(Get-AzureKeyVaultCertificate -VaultName $vaultName -Name $certificateName).Certificate
  • AKV密钥提供X.509证书的私钥。如果相应的证书被标记为不可导出,则执行加密操作(如签名)非常有用。在PowerShell中,您只能通过以下方式获取此私钥的公开部分
(Get-AzureKeyVaultKey -VaultName $vaultName -Name $certificateName).Key
  • AKV-secret提供了一种导出完整X.509证书的方法,包括其私钥(如果其策略允许私钥导出)。如上所示,可以在PowerShell中通过以下方式获取当前的base64编码证书:
(Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName).SecretValueText

答案 1 :(得分:1)

以下是C#代码,可在给定证书名称和KeyVault连接信息的情况下,从最新到最旧检索证书的所有版本,包括其私钥。它使用新的Azure.CoreAzure.IdentityAzure.Security.KeyVault.[Certificates|Secrets] SDK软件包。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Azure.Core;
using Azure.Identity;
using Azure.Security.KeyVault.Certificates;
using Azure.Security.KeyVault.Secrets;

public static class CertTools
{
    public static void MyMethod(string tenantId, string clientId, string clientSecret, Uri keyVaultUri)
    {
        var cred = new ClientSecretCredential(tenantId, clientId, clientSecret); // or any other means of obtaining Azure credential
        var certs = GetAllCertificateVersions(keyVaultUri, cred, "MyCert");
    }

    public static List<X509Certificate2> GetAllCertificateVersions(Uri keyVaultUri, TokenCredential credential,
        string certificateName)
    {
        var certClient = new CertificateClient(keyVaultUri, credential);
        var secretClient = new SecretClient(keyVaultUri, credential);

        var now = DateTimeOffset.UtcNow;

        var certs = new List<X509Certificate2>();

        foreach (var cert in certClient.GetPropertiesOfCertificateVersions(certificateName)
            .OrderByDescending(x => x.CreatedOn)
            // fetch all enabled, non-expired certificates. adjust this predicate if desired.
            .Where(x => x.ExpiresOn >= now && (x.Enabled ?? false)))
        {
            var secret = secretClient.GetSecret(certificateName, cert.Version).Value;
            certs.Add(new X509Certificate2(Convert.FromBase64String(secret.Value)));
        }

        return certs;
    }
}

感谢@Nandun's answer here为我指明了使用SecretClient而不是CertificateClient的正确方向,但是该帖子被标记为重复,因此请在此处发布此扩展代码。