Azure Key Vault 机密访问间歇性地无法连接套接字异常
Posted
技术标签:
【中文标题】Azure Key Vault 机密访问间歇性地无法连接套接字异常【英文标题】:Azure Key Vault secret access intermittently failing to connect with socket exception 【发布时间】:2019-06-29 17:46:02 【问题描述】:我有一个在 .NET 4.7.2 上运行并托管在 Azure AppService 中的 MVC 5 Web 应用程序,它使用 Azure Key Vault 来保存机密。该项目使用Microsoft.Azure.KeyVault 3.0.3
NuGet 包,并使用KeyVaultClient
和.GetSecretAsync()
访问机密。所有资源都位于同一个 Azure 区域。
在大多数情况下,这工作得很好,大约 90% 的时间它以毫秒为单位返回秘密。
但访问 Key Vault 的调用有时会失败。这不会表现为 SDK 引发的异常,但 Web 应用程序会挂起。最终——通常在 1 分钟左右,但有时更长时间——秘密被返回,一切都恢复正常。这是因为 SDK 使用重试模式,它会不断尝试获取密钥。
查看 AppService 的 Application Insights,我可以看到 SDK 生成的 GET 请求从 Key Vault 获得 HTTP 500 响应并引发 SocketException,结果代码为 ConnectFailure。
例外是:
查看遥测数据并单步执行代码,没有任何共同点或明显原因。它似乎完全是随机的。
底线是 Azure 托管的 AppService有时无法使用最新的框架和 SDK 版本连接到同一数据中心中的 Azure 托管的 Key Vault。
有其他人看过这个或有任何想法吗?我四处搜寻,发现有几个人遇到同样的问题,但没有人找到原因或解决方案。
编辑 (1):我现在尝试在另一个区域完全启动一个新的 Key Vault,但问题仍然完全相同。
【问题讨论】:
我建议联系 Azure 支持并要求他们调查长期依赖持续时间 @MartinLiversage 是的,我同意了。 【参考方案1】:我们在项目中遇到了相同的行为,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();
这两个更改似乎对我们很有效,而且我们已经有一段时间没有遇到任何问题了。
【讨论】:
谢谢。今天下午我确实考虑过按照这些思路做一些事情,但偶尔我也会看到它在应用程序启动时挂起第一次访问。这仍然会产生问题,首先要让秘密缓存起来。你在启动时经历过吗? @IraRainey 我们已经有一段时间没有遇到这个问题了,但我不记得在应用程序启动时看到它。尽管如此,我们的应用程序中没有任何东西需要在启动时使用 KeyVault。我们只需要在响应 API 请求、服务总线消息等时从 KeyVault 获取一些东西,此时应用程序已经在运行。 好的,谢谢。实际上考虑它不是关于应用程序启动,而是在使用AAD登录之后。一旦用户通过身份验证,我们需要获取一些秘密。我已经看到它在那里失败了,这使得它有时看起来像是登录失败。 我们的应用程序中有一些代表身份验证流程间歇性失败。我们经常 ping 登录服务器以验证图形 api 调用,并看到一些非常相似的行为。我也打算建议一种缓存方法(即使我们的问题是切线的)。这些服务请求是否有可能受到速率限制? @ScubaSteve Key Vault 的速率有限,但速率相当高,而且我们只进行少量调用。根据文档,如果由于速率限制而失败,它将返回 429 响应代码,而不是 500。【参考方案2】:另一种选择是将密钥从 keyvault 部署到您的应用服务应用程序,作为部署管道中的应用设置。
优点:
将秘密置于源代码控制之外 移除对 keyvault 的运行时依赖 更快速可靠的本地访问机密缺点:
更新机密需要重新部署【讨论】:
以上是关于Azure Key Vault 机密访问间歇性地无法连接套接字异常的主要内容,如果未能解决你的问题,请参考以下文章
使用 Azure Key Vault 进行 Terraform 以获取机密值