【发布时间】:2018-08-29 18:14:59
【问题描述】:
我正在开发一个当前在 Azure Functions 中运行代码的解决方案。这些功能使用 MSI 身份验证向我们的 PaaS 服务(Key Vault/Service Bus/Blob Storage 等)进行身份验证。
验证的代码如下:
// Connect to KeyVault in the context of the running code.
var tokenProvider = new AzureServiceTokenProvider();
var config = new ConfigurationBuilder().AddAzureKeyVault(
keyvaultUri,
new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback)),
new DefaultKeyVaultSecretManager())
.Build();
这让我可以使用如下代码安全地连接到服务总线:
// Get ServiceBus connection settings.
config.GetSection("Messaging").Bind(ConfigSettings);
var namespaceName = Regex.Match(ConfigSettings.ConnectionString, @"Endpoint=sb:\/\/([^.]*)", RegexOptions.IgnoreCase).Groups[1].Value;
var token = tokenProvider.GetAccessTokenAsync("https://management.core.windows.net/", string.Empty).Result;
var tokenCredentials = new TokenCredentials(token);
var client = RestClient.Configure()
.WithEnvironment(AzureEnvironment.AzureGlobalCloud)
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.WithCredentials(new AzureCredentials(tokenCredentials, tokenCredentials, string.Empty, AzureEnvironment.AzureGlobalCloud))
.Build();
// Authenticate against Service Bus.
ServiceBusNamespace = Azure.Authenticate(client, string.Empty)
.WithSubscription(ConfigSettings.SubscriptionId)
.ServiceBusNamespaces.List()
.SingleOrDefault(n => n.Name == namespaceName);
我们正在更改我们的解决方案,以便我们将在控制台应用程序(在 Linux 上运行)中执行相同的操作,而不是在 ASE 上运行函数。显然 MSI auth 在这种情况下不起作用,所以我希望使用服务原则 AppId 和 AppSercret。我在 AAD 中设置的原理如下:
利用本服务原则AppId和AppSecret的代码如下:
public async static Task<string> GetAccessToken(string tenantId, string appId, string appSecret)
{
var authenticationContext = new AuthenticationContext($"https://login.windows.net/{tenantId}");
var credential = new ClientCredential(clientId: appId, clientSecret: appSecret);
var result = await authenticationContext.AcquireTokenAsync(resource: "https://management.core.windows.net/", clientCredential: credential);
if (result == null) {
throw new InvalidOperationException("Failed to obtain the JWT token");
}
return result.AccessToken;
}
但它要求我准备好 AppId、AppSecret 和 TenantId 之类的内容以供应用使用。出于明显的安全原因,我不想使用 AppSettings。
我现在可以使用与之前类似的代码运行服务总线身份验证:
var namespaceName = Regex.Match(connectionString, @"Endpoint=sb:\/\/([^.]*)", RegexOptions.IgnoreCase).Groups[1].Value;
var tokenCredentials = new TokenCredentials(token);
var client = RestClient.Configure()
.WithEnvironment(AzureEnvironment.AzureGlobalCloud)
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.WithCredentials(new AzureCredentials(tokenCredentials, tokenCredentials, string.Empty, AzureEnvironment.AzureGlobalCloud))
.Build();
var serviceBusNamespace = Azure.Authenticate(client, string.Empty)
.WithSubscription(subscriptionId)
.ServiceBusNamespaces.List()
.SingleOrDefault(n => n.Name == namespaceName);
if (serviceBusNamespace == null)
{
throw new InvalidOperationException($"Couldn't find the service bus namespace {namespaceName} in the subscription with ID {subscriptionId}");
}
我的问题 - 担心安全性然后将所需的配置字段(AppId、AppSecret、TenantId)存储在 config 或 Env Vars 中似乎适得其反。我还有其他选择吗?除非经过身份验证,否则我无法使用 KeyVault,但我需要再次验证我的服务原则才能访问它。
以前有人做过这种方法吗?也许服务原则不是正确的方法?
提前感谢任何指点!
【问题讨论】:
-
您确定不能使用 MSI 吗?最终,它使用了一个可从运行时环境访问的 HTTP 端点(你也应该能够从 Linux 中使用它:))
-
其实不是,我不是!我只是习惯于通过 ASE 而不是在代码中配置它。有什么好的例子吗?不幸的是,我无法从控制台应用程序中看到使用 msi 进行身份验证的具体代码示例
-
您也可以查看我关于 MSI 的文章:joonasw.net/view/azure-ad-managed-service-identity。我提到了它在后台使用的两个环境变量。当然问题是您需要获取这些环境变量。我不确定您的控制台应用程序是否可以获取它们。
-
感谢 Joonas,所以如果我设置 MSI_ENDPOINT 和 MSI_SECRET 这两个环境变量,并运行这几行代码,它仍然适用于控制台应用程序吗?整洁的!我从哪里获得 MSI_ENDPOINT 和 MSI_SECRET? (我最初没有设置) - 谢谢!!!
标签: c# azure .net-core console-application azure-keyvault