从Identity Server 4升级到Duende IS6后登录抛出密钥不存在异常
关于Keys SQL表的疑问
不需要将密钥持久化到Keys SQL表——你已经通过options.KeyManagement.Enabled = false禁用了Duende IdentityServer的密钥管理功能,此时系统会直接使用你手动提供的签名凭据,不会依赖内置的密钥存储机制。
报错根源
你当前代码中keyResponse.Value.Key.ToRSA()返回的是RSACng实例,它依赖Windows CNG(加密下一代技术)的本地密钥句柄。本地开发环境中这个句柄可以正常工作,但部署后(比如IIS应用池场景),会因为进程隔离、权限限制或远程密钥引用失效等问题,导致签名时找不到对应的密钥,从而抛出WindowsCryptographicException: Key does not exist。
另外,Azure Key Vault的密钥默认是不可导出的,ToRSA()并没有真正将私钥下载到本地,只是创建了一个指向远程KV的CNG密钥引用,这种引用在部署环境中往往无法正常完成签名操作。
具体解决方案
方案1:使用Azure Key Vault CryptographyClient完成签名(推荐)
这种方式无需将密钥下载到本地,所有签名操作直接通过Azure Key Vault服务完成,彻底避免本地密钥句柄问题。
修改代码如下:
var identityServiceBuild = services.AddIdentityServer(options => { options.KeyManagement.Enabled = false; }); string keyVaultName = "mykeyvault"; var kvUri = new Uri($"https://{keyVaultName}.vault.azure.net"); // 创建KeyClient与CryptographyClient var keyClient = new KeyClient(kvUri, new DefaultAzureCredential()); var keyResponse = await keyClient.GetKeyAsync("devidentityserver"); var cryptoClient = new CryptographyClient(keyResponse.Value.Id, new DefaultAzureCredential()); // 创建基于Azure KV的签名凭据 var signingCredentials = new SigningCredentials( new AzureSecurityKey(cryptoClient), IdentityServerConstants.RsaSigningAlgorithm.RS256) { KeyId = keyResponse.Value.Properties.Version }; identityServiceBuild.AddSigningCredential(signingCredentials);
注意事项:
- 需要安装
Azure.Security.KeyVault.CryptographyNuGet包 - 确保部署环境使用的身份(如应用服务托管身份)拥有Azure Key Vault的
Key Sign权限
方案2:导出密钥并创建本地RSA实例(仅适用于可导出密钥)
如果你的Azure Key Vault密钥创建时设置了KeyExportPolicy.AllowExport(允许导出私钥),可以将密钥参数导出到本地内存中初始化RSA实例:
var identityServiceBuild = services.AddIdentityServer(options => { options.KeyManagement.Enabled = false; }); string keyVaultName = "mykeyvault"; var kvUri = new Uri($"https://{keyVaultName}.vault.azure.net"); var keyClient = new KeyClient(kvUri, new DefaultAzureCredential()); var keyResponse = await keyClient.GetKeyAsync("devidentityserver"); // 导出私钥参数并初始化本地RSA var rsaParams = keyResponse.Value.Key.ToRSA().ExportParameters(true); var rsa = RSA.Create(); rsa.ImportParameters(rsaParams); var key = new RsaSecurityKey(rsa) { KeyId = keyResponse.Value.Properties.Version }; identityServiceBuild.AddSigningCredential(key, IdentityServerConstants.RsaSigningAlgorithm.RS256);
⚠️ 风险提示:此方式会将私钥加载到应用内存中,存在安全泄露风险,仅在必要场景下使用,同时需严格控制Key Vault的访问权限。
额外排查点
- 确认部署环境的身份拥有对应Key Vault权限(方案1需
Key Sign,方案2需Key Get+Key Export) - 检查Azure Key Vault的网络配置,确保部署环境(如应用服务、虚拟机)可以访问KV(正确配置防火墙、虚拟网络对等)
- IIS部署场景下,确认应用池身份拥有访问Windows CNG资源的权限(方案2适用)
内容的提问来源于stack exchange,提问作者Andrew Duffy

