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
错误原因分析
- SAS令牌过期:错误信息明确显示当前时间已超过SAS的过期时间,导致Azure存储拒绝请求,应用无法读取密钥环,进而触发密钥找不到的错误。
- SAS签名不匹配:从错误的
String to sign可以看到,签名计算的路径是/blob/whatever/$root,但代码中配置的是容器whatever-data-protection,说明生成SAS的对象错误——是给存储账户的**根容器($root)**生成的SAS,而非目标容器,导致请求路径与签名计算的路径不一致,签名验证失败。另外代码中SAS URI末尾有多余的双分号;;,会干扰参数解析,也可能引发异常。 - 应用名称不固定:使用
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
相关产品推荐
相关产品推荐

