升级至Abp.io 9.0.3与.NET9后Azure App Service中PFX证书加载失败
问题背景
在.NET 8 + Abp.io环境中,使用以下代码可正常加载PFX证书:
if (!File.Exists(fileName)) { throw new FileNotFoundException($"Signing certificate couldn't be found: {fileName}"); } var certificate = new X509Certificate2(fileName, passPhrase, X509KeyStorageFlags.MachineKeySet); builder.AddSigningCertificate(certificate); builder.AddEncryptionCertificate(certificate);
升级至Abp.io 9.0.3与.NET 9后,因原X509Certificate2构造函数过时,改用X509CertificateLoader.LoadPkcs12FromFile方法,但在Azure App Service中运行报错:
System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
确认文件路径正确后,添加环境变量WEBSITE_LOAD_USER_PROFILE=1,错误变为:
System.Security.Cryptography.CryptographicException: Keyset does not exist
无论使用旧构造函数还是新加载方法均失败,证书由流水线通过dotnet dev-certs https -v -ep openiddict.pfx -p $(passPhrase)生成并随产物部署至App Service。
解决方案
1. 替换密钥存储标志为EphemeralKeySet
X509KeyStorageFlags.MachineKeySet需要写入机器级密钥存储,而Azure App Service沙箱环境没有该权限。改用EphemeralKeySet将密钥存储在临时内存中,无需写入磁盘,完全适配云环境:
var path = Path.Combine(AppContext.BaseDirectory, fileName); if (!File.Exists(path)) { throw new FileNotFoundException($"Signing certificate couldn't be found: {fileName}"); } var certificate = X509CertificateLoader.LoadPkcs12FromFile( path, passPhrase, X509KeyStorageFlags.EphemeralKeySet ); builder.AddSigningCertificate(certificate); builder.AddEncryptionCertificate(certificate);
2. 修改证书生成命令,确保私钥可导出
原dotnet dev-certs命令生成的证书私钥默认不可导出,导致Azure环境无法正常加载。添加--exportable参数生成可导出私钥的证书:
dotnet dev-certs https -v -ep openiddict.pfx -p $(passPhrase) --exportable
3. 移除WEBSITE_LOAD_USER_PROFILE环境变量
该变量会强制加载用户配置文件,在.NET 9的权限模型下反而会引发密钥集权限冲突,移除后配合EphemeralKeySet可解决权限问题。
4. 用AppContext.BaseDirectory替代AppDomain路径
AppDomain.CurrentDomain.BaseDirectory在.NET 9中可能存在路径解析问题,改用AppContext.BaseDirectory能更可靠地获取程序运行目录。
原因说明
.NET 9对加密API的权限控制进行了严格升级,原.NET 8中允许的机器级密钥存储操作在沙箱环境中被限制。同时,Abp.io 9.0.3依赖的OpenIddict等组件对证书加载的要求也更严格,导致旧代码无法兼容。
内容的提问来源于stack exchange,提问作者thibsc

