问题描述
我有一个 Azure 应用服务不是我创建的,但现在需要维护。应用服务通过指纹在 Key Vault 中找到证书,然后使用该证书获取令牌,以便通过夜间作业执行一些 sql 工作。
该证书似乎已设置为在其有效日期(12 个月)的 80% 后自动续订。证书更新我的夜间工作的那一天开始失败。我有理由确定新证书是问题的根源。
尽我所知,它的设计目的是这样的:
- 通过 Azure 逻辑应用触发作业
- 异常 POST 到报告处理 API(最终结果应该是为电子邮件附件创建的 .PDF 报告)
- API 具有包含当前证书指纹的 Appsetting.json
- 在下面的代码行中使用指纹在证书存储中查找证书
- Cert 用于获取访问令牌和执行工作
当我在本地机器上安装旧证书和新证书并运行整个过程时,它可以使用旧证书找到,但在使用新自动生成的证书的这一行上失败。我尝试在 Azure 中创建并从 Azure 导出并导入到我的开发机器的任何新证书也会失败。我已经对应用设置进行了两次/三次检查,以确保有问题的指纹正确且已更新。
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
一年前进行配置时,流程是进入应用服务、TLS/SSL 设置边栏选项卡、选择私钥证书 (.pfx),最后选择 + 导入 Key Vault 证书。
从那里您选择了 Key Vault 和证书,然后更改了 Appsettings.Json 以拥有新的指纹。
为什么它可以使用旧的(即将到期)证书和应用设置中的相应指纹条目,但无法使用任何新创建的证书和相应的正确指纹条目?
我查看了相关应用服务的配置,当我了解到应该让应用服务看到注册到它的所有证书时,它具有以下设置,对吗?
WEBSITE_LOAD_CERTIFICATES = *
编辑: 经过更多测试后,我发现我从 Azure 导出并在我的计算机上导入的任何证书都将成功迭代证书存储并找到我提供有效指纹的任何证书。它不会做的是使用该证书来获取访问令牌。完整代码如下。
即将到期的证书将获得正确的访问令牌,并通过从数据库中获取正确的数据来运行其余的过程。
我在所有其他证书中得到的例外表明了一些关于 base64 编码的信息,但我不太清楚。有什么想法吗?
除原始证书外的所有例外:
客户端断言包含无效签名
仅使用原始证书使用此代码成功访问令牌:
private async Task<string> GetDatabasetokenFromCert()
{
X509Certificate2 cert;
var store = new X509Store(StoreLocation.CurrentUser);
var authContext = new AuthenticationContext(_appSettings.AzureAD.AADInstance + _appSettings.AzureAD.TenantId);
try
{
store.Open(OpenFlags.ReadOnly);
var signingCert = store.Certificates.OfType<X509Certificate2>().FirstOrDefault(x => x.Thumbprint == _appSettings.AzureAD.CertificateThumbprint);
if (signingCert == null)
{
throw new FileNotFoundException("Cannot locate certificate for DB access!",_appSettings.AzureAD.CertificateThumbprint);
}
cert = signingCert;
}
finally
{
store.Close();
}
var certCred = new ClientAssertionCertificate(_appSettings.AzureAD.ClientId,cert);
var result = await Retry(() => authContext.AcquiretokenAsync(_appSettings.sqlConfig.ResourceId,certCred));
return result?.Accesstoken;
}
解决方法
事实证明,您还需要将新证书添加到应用程序注册中。显然,作为没有私钥的 .cer 文件。
因此,如果您收到错误消息:
AADSTS700027:客户端断言包含无效签名。 [原因 - 未找到密钥。,客户端使用的密钥指纹:'YourNewCert'
转到 Key Vault,将新证书导出为 .cer 文件并将其导入到尝试从 AcquireTokenAsync 获取访问令牌的应用服务中
就我而言,操作顺序是:
- 逻辑应用程序将匿名调用作为对 Web API 的 POST 触发
- Web API 通过 appsetting.json 使用相关证书的指纹
- 在 Web API 的应用注册中查找带有指纹的证书
- AcquireTokenAsync 获取 Azure 信息和证书并返回访问令牌
这将在这行原始帖子上工作或失败
var result = await Retry(() => authContext.AcquireTokenAsync(_appSettings.SqlConfig.ResourceId,certCred));