You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Data Protection配置异常及Azure SAS认证报错求助

ASP.NET Core Data Protection 密钥环与Azure存储认证问题解决

问题背景

频繁收到以下密钥找不到错误:

The key {51a0baee-87ce-4610-848c-383d4f58e3db} was not found in the key ring. For more information go to http://aka.ms/dataprotectionwarning
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)

尝试配置Azure Blob存储持久化密钥、Azure Key Vault加密密钥,但未生效,配置代码如下:

string trimmedContentRootPath = builder.Environment.ContentRootPath.TrimEnd(Path.DirectorySeparatorChar);
string keyVaultName = builder.Configuration.GetValue<string>("KeyVaultName");
AspNetCoreDataProtectionOptions aspNetCoreDataProtectionOptions = new AspNetCoreDataProtectionOptions() {
  BlobUriWithSasToken = "https://whatever.blob.core.windows.net/whatever-data-protection?sp=racwdl&st=2023-08-14T16:00:04Z&se=2023-08-15T00:00:04Z&spr=https&sv=2022-11-02&sr=c&sig=%2BDgq2xtgKuaI%2FclYM9AXbKIlLBdg4W%2FuQLBmc53fjR8%3D";;
    KeyIdentifier = "https://whatever-key-vault.vault.azure.net/keys/whatever-data-protection/4a1114f79ad94cceaf6761796668c712"
    };
builder.Services.AddDataProtection()
    .SetApplicationName(trimmedContentRootPath)
    .PersistKeysToAzureBlobStorage(new Uri(aspNetCoreDataProtectionOptions.BlobUriWithSasToken))
    .ProtectKeysWithAzureKeyVault(new Uri(aspNetCoreDataProtectionOptions.KeyIdentifier), new DefaultAzureCredential())
        ;

配置后先后出现两个403认证错误:

错误1:SAS令牌过期

RequestFailedException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:9820897c-f01e-0014-774c-cf1762000000 Time:2023-08-15T07:47:21.3783363Z Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.) ErrorCode: AuthenticationFailed Additional Information: AuthenticationErrorDetail: Signature not valid in the specified time frame: Start [Mon, 14 Aug 2023 16:00:04 GMT] - Expiry [Tue, 15 Aug 2023 00:00:04 GMT] - Current [Tue, 15 Aug 2023 07:47:21 GMT] Content: <?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:9820897c-f01e-0014-774c-cf1762000000 Time:2023-08-15T07:47:21.3783363Z</Message><AuthenticationErrorDetail>Signature not valid in the specified time frame: Start [Mon, 14 Aug 2023 16:00:04 GMT] - Expiry [Tue, 15 Aug 2023 00:00:04 GMT] - Current [Tue, 15 Aug 2023 07:47:21 GMT]</AuthenticationErrorDetail></Error> Headers: Server: Microsoft-HTTPAPI/2.0 x-ms-request-id: 9820897c-f01e-0014-774c-cf1762000000 x-ms-error-code: AuthenticationFailed Access-Control-Allow-Origin: * Date: Tue, 15 Aug 2023 07:47:20 GMT Content-Length: 544 Content-Type: application/xml

    Azure.Storage.Blobs.BlobRestClient.DownloadAsync(string snapshot, string versionId, Nullable<int> timeout, string range, string leaseId, Nullable<bool> rangeGetContentMD5, Nullable<bool> rangeGetContentCRC64, string encryptionKey, string encryptionKeySha256, Nullable<EncryptionAlgorithmTypeInternal> encryptionAlgorithm, Nullable<DateTimeOffset> ifModifiedSince, Nullable<DateTimeOffset> ifUnmodifiedSince, string ifMatch, string ifNoneMatch, string ifTags, CancellationToken cancellationToken)
    Azure.Storage.Blobs.Specialized.BlobBaseClient.StartDownloadAsync(HttpRange range, BlobRequestConditions conditions, bool rangeGetContentHash, long startOffset, bool async, CancellationToken cancellationToken)
    Azure.Storage.Blobs.Specialized.BlobBaseClient.DownloadStreamingInternal(HttpRange range, BlobRequestConditions conditions, bool rangeGetContentHash, IProgress<long> progressHandler, string operationName, bool async, CancellationToken cancellationToken)
    Azure.Storage.Blobs.PartitionedDownloader.DownloadToAsync(Stream destination, BlobRequestConditions conditions, CancellationToken cancellationToken)
    Azure.Storage.Blobs.Specialized.BlobBaseClient.StagedDownloadAsync(Stream destination, BlobRequestConditions conditions, IProgress<long> progressHandler, StorageTransferOptions transferOptions, bool async, CancellationToken cancellationToken)
    Azure.Storage.Blobs.Specialized.BlobBaseClient.DownloadToAsync(Stream destination, BlobRequestConditions conditions, StorageTransferOptions transferOptions, CancellationToken cancellationToken)
    Azure.Extensions.AspNetCore.DataProtection.Blobs.AzureBlobXmlRepository.GetLatestDataAsync()
    Azure.Extensions.AspNetCore.DataProtection.Blobs.AzureBlobXmlRepository.GetAllElementsAsync()
    Azure.Extensions.AspNetCore.DataProtection.Blobs.AzureBlobXmlRepository.GetAllElements()
    Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.GetAllKeys()
    Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.CreateCacheableKeyRingCore(DateTimeOffset now, IKey keyJustAdded)
    Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider.GetCurrentKeyRingCore(DateTime utcNow, bool forceRefresh)
    Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(byte[] plaintext)

错误2:SAS签名不匹配

调整SAS有效期后,出现新错误:

RequestFailedException: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:766d3595-101e-00a5-084e-cf0977000000
Time:2023-08-15T07:56:41.0260938Z
Status: 403 (Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.)
ErrorCode: AuthenticationFailed

Additional Information:
AuthenticationErrorDetail: Signature did not match. String to sign used was racwdl
2023-08-15T07:55:37Z
2029-08-15T15:55:37Z
/blob/whatever/$root


https
2022-11-02
c

错误原因分析

  1. SAS令牌过期:错误信息明确显示当前时间已超过SAS的过期时间,导致Azure存储拒绝请求,应用无法读取密钥环,进而触发密钥找不到的错误。
  2. SAS签名不匹配:从错误的String to sign可以看到,签名计算的路径是/blob/whatever/$root,但代码中配置的是容器whatever-data-protection,说明生成SAS的对象错误——是给存储账户的**根容器($root)**生成的SAS,而非目标容器,导致请求路径与签名计算的路径不一致,签名验证失败。另外代码中SAS URI末尾有多余的双分号;;,会干扰参数解析,也可能引发异常。
  3. 应用名称不固定:使用ContentRootPath作为SetApplicationName的值,不同部署环境的路径可能不同,导致Data Protection将不同环境视为独立应用,无法共享密钥环。

解决方案

1. 正确生成容器级SAS令牌

  • 登录Azure门户,进入目标存储账户的容器页面,选择你创建的whatever-data-protection容器。
  • 右键选择「生成SAS」,配置:
    • 权限:勾选racwdl(读、添加、创建、写入、删除、列表)
    • 开始时间:设置为当前时间稍早(避免时区问题)
    • 过期时间:设置足够长的有效期(如1年)
    • 协议:选择HTTPS
    • SAS版本:选择与代码一致的2022-11-02
  • 生成后复制完整的SAS URI,确保无多余符号。

2. 修正代码配置

  • 移除SAS URI末尾的多余分号,确保参数格式正确。
  • 将SetApplicationName改为固定字符串,确保所有实例共享同一密钥环。
  • 修正后的示例代码:
// 使用固定应用名称,避免环境路径差异导致密钥环隔离
string appName = "YourApplicationName";
AspNetCoreDataProtectionOptions aspNetCoreDataProtectionOptions = new AspNetCoreDataProtectionOptions() 
{
    BlobUriWithSasToken = "https://whatever.blob.core.windows.net/whatever-data-protection?sp=racwdl&st=2023-08-15T08:00:00Z&se=2024-08-15T08:00:00Z&spr=https&sv=2022-11-02&sr=c&sig=正确的签名值",
    KeyIdentifier = "https://whatever-key-vault.vault.azure.net/keys/whatever-data-protection/4a1114f79ad94cceaf6761796668c712"
};
builder.Services.AddDataProtection()
    .SetApplicationName(appName)
    .PersistKeysToAzureBlobStorage(new Uri(aspNetCoreDataProtectionOptions.BlobUriWithSasToken))
    .ProtectKeysWithAzureKeyVault(new Uri(aspNetCoreDataProtectionOptions.KeyIdentifier), new DefaultAzureCredential());

3. 验证Key Vault权限

  • 确保应用的托管标识(或服务主体)在Azure Key Vault中拥有Key Vault Crypto User角色,允许其执行加密/解密操作。
  • 检查Key Vault的访问策略,确认已添加该主体并授予相应权限。

4. 验证密钥环访问

  • 部署修正后的代码,查看Azure Blob容器中是否生成了key-{guid}.xml格式的密钥文件。
  • 如果存在旧密钥,确认应用能正常读取;如果没有,会自动生成新密钥并存储,后续所有实例将共享该密钥环,解决密钥找不到的问题。

额外建议

  • 不要将SAS令牌硬编码到代码中,存储到Azure Key Vault或安全配置服务,通过IConfiguration读取。
  • 定期轮换SAS令牌和Key Vault密钥,保障安全性。

内容的提问来源于stack exchange,提问作者Richard Barraclough

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:30:55