我有一个运行在.NET 4.7.2上并托管在Azure AppService中的MVC 5 Web应用程序,该应用程序使用Azure Key Vault来保存机密。该项目使用Microsoft.Azure.KeyVault 3.0.3
NuGet包,并使用KeyVaultClient
和.GetSecretAsync()
访问秘密。所有资源都位于同一Azure区域。
在大多数情况下,此方法效果很好,并且在90%的时间内,它以毫秒为单位返回秘密。
但是,偶尔访问该Vault的调用失败。这本身并没有表现为SDK引发的异常,但是Web应用程序挂起。最终-通常在1分钟左右,但有时甚至更长的时间-秘密被返回,一切都很好。这是因为SDK使用了重试模式,它将继续尝试获取机密。
查看AppService的应用程序见解我可以看到,SDK生成的GET请求从Key Vault获得HTTP 500响应,并抛出SocketException,结果代码为ConnectFailure。
例外是:
查看遥测并逐步执行代码,没有任何共性或明显原因。这似乎是完全随机的。
最重要的是,Azure托管的AppService有时 不能使用最新的框架和SDK版本连接到同一数据中心中的Azure托管的Key Vault。
有没有其他人看到过这个或有任何想法?我四处搜寻,发现有人遇到相同问题,但没有人有原因或解决方案。
编辑(1):我现在尝试完全在另一个区域中旋转一个新的Key Vault,问题仍然完全相同。
答案 0 :(得分:4)
我们在项目中遇到了相同的行为,在大多数情况下,KeyVault都是快速而可靠的,然后间歇性地停止响应或花费很长时间返回,偶尔没有明显的原因来解释原因。这种情况发生在我们应用程序的所有层,从API到Azure Functions,再到命令行工具。
最终,我们不得不通过在内存中缓存机密来解决此问题,以避免过于频繁地访问KeyVault,而我们的AppSettings类将在内部缓存这些机密。除此之外,我们还配置了DI容器以将该类视为单例。
这是一个非常简化的示例:
public class MyAppSettings : IAppSettings
{
private readonly ObjectCache _cache = MemoryCache.Default;
private readonly object _lock = new Object();
private KeyValueClient _kvClient;
public string MySecretValue => GetSecret("MySecretValue");
private KeyValueClient GetKeyVaultClient()
{
// Initialize _kvClient if required
return _kvClient;
}
private string GetSecret(string name)
{
lock (_lock)
{
if (_cache.Contains(key))
return (string) _cache.Get(key);
// Sanitize name if required, remove reserved chars
// Construct path
var path = "...";
// Get value from KV
var kvClient = GetKeyVaultClient();
Task<SecretBundle> task = Task.Run(async() => await kvClient.GetSecretAsync(path));
var value = task.Result;
// Cache it
_cache.Set(name, value, DateTime.UtcNow.AddHours(1));
return value;
}
}
}
这还没准备好投入生产-您需要修改它并实现GetKeyVaultClient
方法以实际返回您的KeyVaultClient对象,并且GetSecret
方法还应该清理检索到的键名。
在我们的DI注册中心中,我们进行了以下设置以使用单例:
For<IAppSettings>().Use<MyAppSettings>().Singleton();
这两个更改似乎对我们来说效果很好,而且我们暂时还没有遇到任何问题。