Как использовать составную идентификацию для аутентификации в Azure для доступа к хранилищу ключей Azure

#azure #azure-active-directory #azure-keyvault

#azure #azure-active-directory #azure-keyvault

Вопрос:

Вопрос:

Azure Key Vault поддерживает «составную идентификацию» для управления доступом (https://learn.microsoft.com/en-us/azure/key-vault/general/secure-your-key-vault ), но есть ли у кого-нибудь некоторый опыт в том, как выполнять аутентификацию в .NET с использованием составной идентификации?

Я полагаю, что при запуске с рабочего стола с использованием собственного приложения аутентификация будет включать оба:

  1. интерактивный вход и согласие пользователя и
  2. аутентификация приложения с секретом клиента

Как будет выглядеть рабочий процесс аутентификации? Есть какой-нибудь пример? Можем ли мы достичь этого с помощью MSAL?

Объяснение Som о составной идентификации:

Предположим, мы создали хранилище ключей Azure и сохранили некоторые секреты в этом хранилище. Как я могу реализовать следующие функциональные возможности в настольном приложении, работающем под управлением Windows 10:

  • Текущий пользователь Windows является частью группы Azure AD group GroupA под тем же клиентом Azure Key Vault.
  • Когда текущий пользователь запускает настольное приложение из того же сеанса пользователя, приложение может получить доступ к секретам в указанном хранилище ключей.
  • Текущий пользователь не может получить доступ к секретам напрямую при входе на портал Azure из своих браузеров.
  • Если приложение запущено другим пользователем, который не является частью группы Azure AD (GroupA), приложение не сможет получить доступ к секретам в указанном хранилище ключей.

Другими словами, я хочу, чтобы доступ к ресурсу хранилища ключей можно было получить с помощью комбинации двух аутентификаций

  • Учетные данные пользователя и
  • секрет приложения

Ответ №1:

Я собираюсь ответить на свой вопрос. Короткий ответ заключается в использовании

 IConfidentialClientApplication.AcquireTokenOnBehalfOf(
      IEnumerable<string> scopes,
      UserAssertion userAssertion);
  

Пользовательский токен, полученный в интерактивном режиме, может использоваться в качестве подтверждения пользователя.

Длинная версия, поскольку я начинающий пользователь, я пройдусь по всем деталям, которые я узнал. Оказывается, здесь и там есть биты для создания полноценного работоспособного приложения .net, поэтому не все напрямую связано с моим вопросом.

1. Создайте регистрацию приложения в Azure AD.

  1. Платформа: мобильное и настольное приложение

  2. Настройка сертификатов или Secrets: Мы собираемся использовать secret в этой демонстрации.

  3. Перенаправить URI: добавьте новый в Mobile and desktop application разделе и установите его как http://127.0.0.1

    При запуске в качестве консольного приложения нет окна, напрямую связанного с запущенным приложением, поэтому самый простой способ выполнить вход пользователя в систему — использовать приложение веб-браузера по умолчанию. Таким образом, единственный способ использования возвращаемого кода — использовать URL redir с точки зрения «http://localhost » или «http://127.0.0.1 «, он же URL-адрес обратной связи. Во время выполнения MSAL будет использовать динамический порт в качестве локального веб-сервера для перехвата URL-адреса redir из веб-браузера. Поскольку он выполняется локально, разрешены как http://, так и https://, если только кто-то не взломал «localhost» с помощью DNS или файла hosts.

  4. Настройте API в разделе «Предоставить API» и добавьте область.

    В рабочем процессе от имени пользователя пользователь выполняет вход, используя область, предоставляемую приложением, вместо прямого доступа к ресурсу хранилища ключей. Нам нужно «Установить» идентификатор URI приложения и создать хотя бы одну область, которая будет использоваться при интерактивном входе.

2. Создайте хранилище ключей и настройте политики доступа в плоскости данных.

  1. Создайте хранилище ключей.

  2. В разделе «Политики доступа» добавьте новую политику доступа.

    Чтобы создать составную идентификацию, выберите действительную учетную запись пользователя или группы для Seelct principal и выберите то же приложение, которое мы создали на предыдущем шаге для Authorized application .

3. Напишите код

Создайте консольное приложение .NET Core. Добавьте следующие пакеты nuget

 <PackageReference Include="Microsoft.Identity.Client" Version="4.18.0" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.8" />
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.5" />
  

Вот код, использующий составную идентификацию для доступа к хранилищу ключей

 
const string AppClientId = "[Enter_your_Application_(client)_ID";
const string AppClientSecret = "[Enter_your_Application_(secret)";
const string TenantId = "[Enter_your_tenantId]";
const string KeyVaultBaseUri = "https://[your_keyvault_name].vault.azure.net/";

// In on-behalf-of flow, the following scope needs to be consented when acquiring the user token. Otherwise, the app cannot access the key vault on-behalf-of user.
const string KeyVaultUserImScope = "https://vault.azure.net/user_impersonation";
// In on-behalf-of flow, the following scope is used to access key vault data when acquiring client token
const string KeyVaultScope = "https://vault.azure.net/.default";
// An "Exposed API" in app registration is required when using on-behalf-of flow. 
const string AppClientScope = "[Enter_your_Application_ID_URI]/[Enter_Your_Scope_Name]";
const string Instance = "https://login.microsoftonline.com/";

Console.WriteLine("Acquire User token");
var pubClient = PublicClientApplicationBuilder.Create(AppClientId)
                .WithAuthority($"{Instance}{TenantId}")
                .WithRedirectUri("http://localhost")    // Make sure the "http://localhost" is added and selected as the app Redirect URI
                .Build();
var userResult= pubClient
                .AcquireTokenInteractive(new[] {AppClientScope })
                .WithExtraScopesToConsent(new [] {KeyVaultUserImScope})
                .WithPrompt(Prompt.Consent)
                .ExecuteAsync().Resu<

// In normal case, when user token is directly given from outside, we should validate if the user Result has consented to the required customized scope AppClientScope before proceeded with next steps. Here we will ignore this step.


Console.WriteLine("Acquire Client token");
// The following two steps are equivalent to https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow#middle-tier-access-token-request
var conClient = ConfidentialClientApplicationBuilder.Create(AppClientId)
                .WithAuthority($"{Instance}{TenantId}")
                .WithClientSecret(AppClientSecret)
                .Build();

            
var OboResult= conClient.AcquireTokenOnBehalfOf(
                    new[] {KeyVaultScope},
                    new UserAssertion(userReult.AccessToken))
                .ExecuteAsync().Resu<



Console.WriteLine("Access Key Vault");
var kc = new KeyVaultCredential((authority, resource, scope) =>
                {
                    Console.WriteLine($"Authority: {authority}, Resource: {resource}, Scope: {scope}");
                    return Task.FromResult(OboResult.AccessToken);
                });

var kvClient = new KeyVaultClient(kc);
var secretBundle = await kvClient.GetSecretAsync(KeyVaultBaseUri, SecretName);

Console.WriteLine("Secret:"   secretBundle.Value);
  

Если мы не используем составную идентификацию, мы можем использовать Azure.Security.KeyVault.Secrets.SecretClient для доступа к данным хранилища ключей один из следующих способов

 // For access policy assigned to confidential application 
var client = new SecretClient(new Uri(KeyVaultBaseUri),
                new ClientSecretCredential(TenantId, AppClientId, AppClientSecret));
var secretBundle = await client.GetSecretAsync(SecretName);
Console.WriteLine("Secret:"   secretBundle.Value.Value);
  

и

 // For access policy assigned to User or Group account
var client = new SecretClient(new Uri(KeyVaultBaseUri), new InteractiveBrowserCredential());
var secretBundle = await client.GetSecretAsync(SecretName);
Console.WriteLine("Secret:"   secretBundle.Value.Value);
  

Ответ №2:

На самом деле, если вы предоставляете права доступа, например, к секретам, это не позволяет пользователям просматривать Хранилище ключей на портале Azure. Если у них нет доступа на чтение к ресурсу в Azure RBAC, они не смогут его просмотреть. Таким образом, вы должны иметь возможность добавлять доступ к пользователям и вызывать его непосредственно из приложения от имени пользователя.

Другим подходом было бы использование серверной части, которая проверяет идентификатор пользователя и обращается к хранилищу ключей вместо пользователя.

  • Пользователь входит в приложение
  • Приложение получает токен доступа к серверной части для пользователя
  • Приложение вызывает серверную часть с токеном
  • Сервер проверяет токен, проверяет, разрешен ли доступ этому пользователю
  • Получите секрет из хранилища ключей с помощью токена доступа, полученного только с учетными данными внутреннего клиента

Здесь вам нужно только разрешить серверному приложению доступ к самому хранилищу ключей.

Комментарии:

1. когда вы говорите «Если у них нет доступа на чтение к ресурсу в Azure RBAC, они не могут его просматривать», вы имеете в виду, что «просмотр секрета из хранилища ключей» — это другое разрешение, чем «получение секрета из хранилища ключей»? Разве пользователь не мог бы просто написать свой собственный сценарий powershell для извлечения секрета, не проходя через приложение, упомянутое в моем вопросе?

2. Да, ну, у них есть к нему доступ? В чем проблема с тем, что они видят это через PowerShell, а ваше приложение Windows извлекает его, и они просматривают его, например, с помощью Fiddler?

3. Используя аналогию, мы хотим, чтобы платный клиент (пользователь в GroupA) мог заказать специальную версию коктейля с рецептами (секретными), ежедневно обновляемыми из внутренней базы знаний (хранилища ключей), у бармена (приложение), но мы не хотим, чтобы клиент знал фактический рецепт (он же секрет)

4. Ну, тогда вам нужен сервер, который никогда не отправляет секрет самому приложению. Если секрет попадает в приложение пользовательского интерфейса, пользователь может его увидеть.

5. Ах, это правда! Это должно позволить вам ограничить доступ только к этому приложению, не позволяя пользователю использовать, например, PowerShell. Для регистрации вашего приложения должно потребоваться делегированное разрешение в хранилище ключей Azure, чтобы выдавать себя за текущего пользователя. Затем в вашем приложении вы получаете токен для https://vault.azure.net/user_impersonation области. Затем это должно позволить вам вызывать хранилище ключей от имени пользователя.