Azure - аутентификация консольного приложения с использованием альтернативы MSI - PullRequest
0 голосов
/ 28 августа 2018

Я работаю над решением, которое в настоящее время выполняет код в функциях Azure. Эти функции аутентифицируются в наших сервисах PaaS (хранилище ключей / служебная шина / хранилище BLOB-объектов и т. Д.) С использованием аутентификации MSI.

Код для аутентификации выглядит следующим образом:

// 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);

Мы меняем наше решение, чтобы вместо запуска функций на ASE мы выполняли ту же операцию в консольном приложении (работающем в Linux). Очевидно, что аутентификация MSI не будет работать в этом сценарии, поэтому я искал использование AppId Service Priniple и AppSercret. Я устанавливаю Принцип в AAD следующим образом:

enter image description here

Этот код для использования этих Принципов обслуживания 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, пока я не аутентифицировался, но, опять же, мне требуется аутентификация моего Принципа обслуживания, прежде чем я смогу получить к нему доступ.

Кто-нибудь делал такой подход раньше? Может быть, принцип обслуживания - не правильный подход?

Заранее спасибо за любые указатели!

1 Ответ

0 голосов
/ 29 августа 2018

Согласно вашему описанию, вы не хотите хранить AppId в конфигурационном файле и хотите использовать Service Principle для аутентификации.

Если это так, вы можете обратиться к статье juunas и использовать AzureServiceTokenProvider для аутентификации и перехода к тому, что вы хотите.

Вы можете использовать следующий код, чтобы получить секрет хранилища ключей без использования AppId и AppSecret.

var azureServiceTokenProvider = new AzureServiceTokenProvider();

var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

var scret = keyVaultClient.GetSecretAsync("https://xxxx.vault.azure.net", "xxxx").GetAwaiter().GetResult();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...