.NET Core 2.2,Azure Web API新X509Certificate2 "系统找不到指定的文件"和"访问被拒绝"

8
我的Azure Web API从Key Vault中加载存储为密钥的证书,然后尝试从字节数组创建新的证书。在本地运行时一切正常,但是当部署到Azure时,根据传递给构造函数的KeyStorageFlags,我们会得到“拒绝访问”或“系统找不到指定的文件”错误。Web API使用.Net Core 2.2。
我已经阅读了很多相关信息,但没有涉及到这种特定情况。
使用MachineKeySet标志: certificate = new X509Certificate2(pfxBytes, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable); 异常:
ex=拒绝访问,stack= at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)

使用UserKeySet标志:

certificate = new X509Certificate2(pfxBytes, "", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.Exportable);

异常:

ex=系统找不到指定的文件,stack= 在 Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) 在 Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) 在 System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)

我按照这篇文章将证书作为秘密进行了加载: [https://www.rahulpnath.com/blog/pfx-certificate-in-azure-key-vault/][1] 这似乎与密钥保管库无关,因为在本地可以很好地从密钥保管库中加载秘密,并且异常并不是在Azure中抛出的。但这可能与证书的存储方式有关吗?
以下是我们正在使用的完整代码:
private async Task<X509Certificate2> GetSecretCertificateFromKVAPI()
        {
            try
            {
                var keyVaultName = _configuration["Secrets:KeyVaultName"];

                var keyVaultEndpoint = $"https://{keyVaultName}.vault.azure.net:443/secrets/";
                var provider = new AzureServiceTokenProvider();
                var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback));
                SecretBundle secretRetrieved;

                secretRetrieved = await client.GetSecretAsync($"{keyVaultEndpoint}OdysseyCA");

                var pfxBytes = Convert.FromBase64String(secretRetrieved?.Value);

                //note, must pass an empty password when loading from keyvault in Azure
                X509Certificate2 certificate;
                try
                {
                    // or recreate the certificate directly
                    certificate = new X509Certificate2(pfxBytes, "",
                            X509KeyStorageFlags.MachineKeySet |
                            X509KeyStorageFlags.PersistKeySet |
                            X509KeyStorageFlags.Exportable);

                    // alternative, try using import
                    //var coll = new X509Certificate2Collection();
                    //coll.Import(pfxBytes, null, X509KeyStorageFlags.Exportable);
                    //certificate = coll[0];
                }
                catch (Exception ex)
                {
                    _logger.Trace($"create new X509 failed, ex={ex.Message}, stack={ex.StackTrace}");
                    throw;
                }

                return certificate;
            }
            catch (Exception ex)
            {
                _logger.Trace($"GetSecretCertificateFromKVAPI threw an exception, ex={ex.Message}, stack = {ex.StackTrace}");
                throw;
            }
        }

在代码中,你可以看到我们尝试使用X509Certificate2Collection类的.import方法来解决这个问题,但结果是相同的。我们正在积极备份到.NET Core 2.1和2.0,以查看是否存在新的错误,并寻找其他答案。
我们如何让它工作?
编辑:根据下面评论中的建议尝试了EphemeralKeySet标志,但异常堆栈与其他人基本相同:
certificate = new X509Certificate2(pfxBytes, "", X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable);
ex=系统找不到指定的文件,stack = at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags) at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
有人能证实这个适用于任何版本的 .Net 吗?可能是核心或 2.2 的 bug?

1
对于MachineKeySet:您需要成为管理员。对于UserKeySet(或普通隐式):您需要加载用户配置文件。对于EphemeralKeySet:应该可以正常工作。https://dev59.com/S1QJ5IYBdhLWcg3w8qtf#52840537 - bartonjs
1
@bartonjs,是的!使用EmphemeralKeySet确实起作用了!为什么其他地方没有记录这一点,我不知道。 - user2503078
@bartonjs,不!我不确定当时我做了什么,但它现在不起作用。堆栈错误与其他错误非常相似。我将编辑帖子以显示此内容。还有其他想法吗? - user2503078
1个回答

14

在托管在Azure中的API中,添加应用程序设置:WEBSITE_LOAD_USER_PROFILE=1解决了问题。我们仍然使用EphemeralKeySet,但我怀疑UserKeySet标志也可以起作用。


尝试了许多解决方案,例如 string file = Path.Combine(Directory.GetCurrentDirectory(), PrivateKey_Path);,为文件提供 IIS_IUser 访问权限等,但都没有起作用,而您的解决方案却奏效了。 - Somnath Kadam
似乎是私钥的问题...https://github.com/projectkudu/kudu/wiki/Configurable-settings#the-system-cannot-find-the-file-specified-issue-with-x509certificate2 - Marty

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