如何在 Azure Key Vault 中序列化和反序列化 PFX 证书?

Posted

技术标签:

【中文标题】如何在 Azure Key Vault 中序列化和反序列化 PFX 证书?【英文标题】:How to serialize and deserialize a PFX certificate in Azure Key Vault? 【发布时间】:2016-02-17 03:04:54 【问题描述】:

我有一堆字符串和 pfx 证书,我想将它们存储在 Azure Key Vault 中,只有允许的用户/应用程序才能获取它们。将字符串存储为 Secret 并不难,但我如何序列化证书以便我可以检索它并反序列化为 C# 中的 X509Certificate2 对象?

我尝试将其存储为密钥。这是 Azure PowerShell 代码

$securepfxpwd = ConvertTo-SecureString -String 'superSecurePassword' -AsPlainText -Force
$key = Add-AzureKeyVaultKey -VaultName 'UltraVault' -Name 'MyCertificate' -KeyFilePath 'D:\Certificates\BlaBla.pfx' -KeyFilePassword $securepfxpwd

但是当我尝试用 GetKeyAsync 方法获取它时,我无法使用它。

【问题讨论】:

【参考方案1】:

这是为您准备的 PowerShell 脚本。替换文件路径、密码、保管库名称、机密名称。

$pfxFilePath = 'C:\mycert.pfx'
$pwd = '123'
$flag = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection 
$collection.Import($pfxFilePath, $pwd, $flag)
$pkcs12ContentType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12
$clearBytes = $collection.Export($pkcs12ContentType)
$fileContentEncoded = [System.Convert]::ToBase64String($clearBytes)
$secret = ConvertTo-SecureString -String $fileContentEncoded -AsPlainText –Force
$secretContentType = 'application/x-pkcs12'
Set-AzureKeyVaultSecret -VaultName 'myVaultName' -Name 'mySecretName' -SecretValue $Secret -ContentType $secretContentType

这是一个常见问题,因此我们将对其进行完善并作为助手发布。

上面的脚本去掉了密码,因为有一个受密码保护的 PFX 然后将密码存储在它旁边没有任何价值。

【讨论】:

$clearBytes = $collection.Export($pkcs12ContentType) 似乎没有导出私钥。使用 $collection.Export($pkcs12ContentType, $pwd) 方法允许我使用密码将证书作为 X509Certificate2 (c#) 导入。 @Sumedh 您指的助手是新的 Key Vault 证书功能吗? docs.microsoft.com/en-us/rest/api/keyvault/…谢谢 @HBoyce 确实如此。这是证书功能的教程。现在比上面的脚本更简洁,并且您的证书也会自动更新。 blogs.technet.microsoft.com/kv/2016/09/26/…(感谢您恢复此线程。) 投反对票,在不演示检索的情况下向某人展示如何存储东西并没有多大意义。另外问题是关于 C# 和检索为 x509Certificate2 对象,前面的 cmets 显示并不简单。 如果来这里的人跟我一样困惑。事实证明,您需要将 .pfx 上传到 Keyvault 的 secrets 部分,而不是 keys 部分【参考方案2】:

最初的问题询问如何将存储的 PFX 检索为 X509Certificate2 对象。使用类似于上面 Sumedh Barde 发布的 Base64 进程(具有剥离密码的优点),以下代码将返回 X509 对象。在实际应用中,如果您要检索多个机密,则应缓存KeyVaultClient,并且还应缓存各个机密。

public static async Task<X509Certificate2> GetSecretCertificateAsync(string secretName)

    string baseUri = @"https://xxxxxxxx.vault.azure.net/secrets/";

    var provider = new AzureServiceTokenProvider();
    var client =  new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback));
    var secretBundle = await client.GetSecretAsync($"baseUrisecretName").ConfigureAwait(false);
    string pfx = secretBundle.Value;

    var bytes = Convert.FromBase64String(pfx);
    var coll = new X509Certificate2Collection();
    coll.Import(bytes, "certificatePassword", X509KeyStorageFlags.Exportable);
    return coll[0];

【讨论】:

这完全正确。请记住,您需要将密钥保存在密钥库的 secrets 部分而不是密钥库的 keys 部分 他们真的应该将密钥部分命名为更好地阐明它是用于自动公钥共享和轮换的东西,而不是通用密钥存储...... 想要使用此解决方案和类似解决方案,但使用 .Net Core 2.1、VS 2017 + Azure SDK 获取:'KeyVaultClient' does not contain a definition for 'GetSecretAsync' @McGuireV10,找到Azure Key Vault configuration provider in ASP.NET Core引用的扩展包 其实代码不正确,我现在修好了。您应该使用 client 对象进行异步调用。【参考方案3】:

这是我解决这个问题的方法。首先,将您的 PFX 文件转换为 base64 字符串。您可以使用以下两个简单的 PowerShell 命令来做到这一点:

$fileContentBytes = get-content 'certificate.pfx' -Encoding Byte
[System.Convert]::ToBase64String($fileContentBytes) | Out-File 'certificate_base64.txt'

通过Azure Portal 在 Azure Key Vault 中创建一个机密。复制您之前创建的证书 base64 字符串,并通过 Azure Portal 将其粘贴到 Azure Key Vault 的密钥值字段中。然后只需从代码中调用 Azure Key Vault 以获取 base64 字符串值并将其转换为 X509Certificate2

private async Task<X509Certificate2> GetCertificateAsync()

    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
    var secret = await keyVaultClient.GetSecretAsync("https://path/to/key/vault").ConfigureAwait(false);
    var pfxBase64 = secret.Value;
    var bytes = Convert.FromBase64String(pfxBase64);
    var coll = new X509Certificate2Collection();
    coll.Import(bytes, "certificatePassword", X509KeyStorageFlags.Exportable);
    return coll[0];

【讨论】:

【参考方案4】:

请参阅以下答案,其中描述了如何使用最新的 .NET Azure SDK 客户端库执行此操作:

How can I create an X509Certificate2 object from an Azure Key Vault KeyBundle

【讨论】:

【参考方案5】:

这是在python中使用azure cli上传pfx证书的脚本

azure keyvault secret set --vault-name <Valut name> --secret-name <Secret Name> --value <Content of PFX file>

在python中获取PFX文件的内容

fh = open(self.getPfxFilePath(), 'rb')
    try:
        ba = bytearray(fh.read())
        cert_base64_str = base64.b64encode(ba)
        password = self.getPassword()
        json_blob = 
            'data': cert_base64_str,
            'dataType': 'pfx',
            'password': password
        
        blob_data= json.dumps(json_blob)
        content_bytes= bytearray(blob_data)
        content = base64.b64encode(content_bytes)
        return content
    finally:
        fh.close
    fh.close()

【讨论】:

投反对票。问题是关于使用 C# 检索为 x509Certificate2 对象。

以上是关于如何在 Azure Key Vault 中序列化和反序列化 PFX 证书?的主要内容,如果未能解决你的问题,请参考以下文章

您如何在功能应用程序中从Azure Key Vault引用密钥?

如何在函数应用中引用 Azure Key Vault 中的密钥?

部署期间如何使用 Azure Key Vault 传递安全参数值?

如何通过服务主体通过 Azure Key Vault 访问 Azure 存储帐户

自动重新生成反映在 Azure Key Vault Secret 中的密钥

在 C# 中使用 azure key vault 解密和下载“加密的 azure blob”