Мой веб-API Azure загружает сертификат, хранящийся как секрет в Key Vault, а затем пытается создать новый сертификат из массива байтов. Выполняется локально все работает, но при развертывании в Azure мы получаем Доступ запрещен или Система не может найти указанный файл в зависимости от KeyStorageFlags, переданных конструктору. Веб-API использует .Net Core 2.2.
Я занимался этим некоторое время, читая много информации, связанной с этим, но не с этим конкретным сценарием.
Использование флага MachineKeySet:
certificate = new X509Certificate2(pfxBytes, "",
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.Exportable);
Исключение
ex=Access denied, 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=The system cannot find the file specified, 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)
Я следил за сертификатом загрузки как секретом, используя эту статью [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;
}
}
В коде вы можете видеть, что мы пытались использовать метод .import класса X509Certificate2Collection, чтобы обойти это, но результаты те же. Мы активно создаем резервные копии .Net Core 2.1 и 2.0, чтобы узнать, является ли это новой ошибкой, и ищем другие ответы.
Как заставить это работать?
Обновлено: на основе предложения в комментариях ниже попробовал флаг EphemeralKeySet, но стек исключений почти такой же, как и другие:
certificate = new X509Certificate2(pfxBytes, "",
X509KeyStorageFlags.EphemeralKeySet |
X509KeyStorageFlags.Exportable);
ex=The system cannot find the file specified, 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?
@bartonjs, ДА! использование EmphemeralKeySet действительно сработало!! Почему это нигде не задокументировано, я понятия не имею.
@bartonjs, НЕТ! Я не уверен, что я сделал, когда я думал, что это работает, но это не работает. Ошибка стека очень похожа на другие. Я отредактирую пост, чтобы показать это. Любые другие идеи, что происходит?


В API, размещенном в Azure, добавление параметра приложения: WEBSITE_LOAD_USER_PROFILE=1 решило проблему. Мы остановились на EphemeralKeySet, но подозреваю, что флаги UserKeySet тоже сработают.
после того, как попробовал много решений, например, строковый файл = Path.Combine(Directory.GetCurrentDirectory(), PrivateKey_Path);, предоставил доступ к IIS_IUser для файла, ничего не работает, но ваше решение работает.
Похоже, проблема с закрытыми ключами... github.com/projectkudu/kudu/wiki/…
Для MachineKeySet: вы должны быть администратором. Для UserKeySet (или обычного неявного): вам нужен загруженный профиль пользователя. Для EphemeralKeySet: все должно работать. stackoverflow.com/questions/52750160/…