Без разрешения списка ошибка хранилища ключей Azure «Запрещено» - PullRequest
0 голосов
/ 20 декабря 2018

TL; DR: Без разрешения списка Веб-приложение Asp.Net Core 2.2, развернутое в Azure, завершается с ошибкой - Microsoft.Azure.KeyVault.Models.KeyVaultErrorException: Operation returned an invalid status code 'Forbidden' при запуске при использовании AzureServiceTokenProvider

, над которым я работаюВеб-приложение Asp.Net Core 2.2, и я знаю, как работает хранилище ключей Azure и как веб-приложение, развернутое в Azure, может получать доступ к ключам, секретам и сертификатам из ключевого кода.

Ниже приведена текущая конфигурация:

Я создал хранилище ключей Azure для хранения информации о подписке всех моих клиентов:

Azure Key Vault with multiple secrets

Затем я создал веб-приложение Azure и создал для него удостоверение:

Web app with Identity created

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

Azure Secret Access Policy

Я не хотел жестко кодировать какие-либо секреты в своем коде, поэтому я использовал AzureServiceTokenProvider для подключения и полученияНиже приведен код моего файла Program.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
using Microsoft.Extensions.Logging;
using NLog.Common;
using NLog.Web;

namespace AzureSecretsTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            {
                InternalLogger.LogFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "nlog-internals.txt");
                var host = CreateWebHostBuilder(args).Build();
                host.Run();
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Stopped program because of exception");
                throw;
            }
            finally
            {
                // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
                NLog.LogManager.Shutdown();
            }
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((ctx, builder) =>
                {
                    //https://anthonychu.ca/post/secrets-aspnet-core-key-vault-msi/
                    var keyVaultEndpoint = Environment.GetEnvironmentVariable("KEYVAULT_ENDPOINT");
                    if (!string.IsNullOrEmpty(keyVaultEndpoint))
                    {
                        var azureServiceTokenProvider = new AzureServiceTokenProvider();
                        var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                        builder.AddAzureKeyVault(keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                    }
                })
                .UseStartup<Startup>();
    }
}

Ниже приведен простой файл Startup.cs с кодом для доступа к секретам из хранилища ключей Azure:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace AzureSecretsTest
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IConfiguration configuration)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Run(async (context) =>
            {
                string configValue = configuration["OneOfTheSecretKey"];
                StringBuilder sb = new StringBuilder();
                var children = configuration.GetChildren();
                sb.AppendLine($"Is null or whitespace: {string.IsNullOrWhiteSpace(configValue)}, Value: '{configValue}'");
                foreach (IConfigurationSection item in children)
                {
                    sb.AppendLine($"Key: {item.Key}, Value: {item.Value}");
                }
                await context.Response.WriteAsync(sb.ToString());
            });
        }
    }
}

Всеработает нормально, пока я дал разрешение «Список»Однако, предоставив разрешение «Список», я заметил, что весь секретный список доступен.Это раскрывает всю другую информацию о подписке клиента, которая меня не устраивает.Я могу пойти и создать одно хранилище ключей для каждого клиента, но это кажется излишним.

Возможно, я делаю глупую ошибку и не вижу ее, или вполне возможно, что вы не можете удалить разрешение «Список».В любом случае я был бы признателен, если бы кто-то, обладающий большими знаниями, мог пролить свет на то, могу ли я использовать AzureServiceTokenProvider без предоставления разрешения для Списка или нет?

Обновление: 1

Обнаружено, что в GitHub уже есть проблема, зарегистрированная для этого: Ошибка обработки разрешения списка для секретов и Сбой ключа Azure без списка разрешений на секреты

Обновление: 2 На основе Ответ Джоуи - это окончательный рабочий код:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
using Microsoft.Extensions.Logging;
using NLog.Common;
using NLog.Web;

namespace AzureSecretsTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            {
                InternalLogger.LogFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "nlog-internals.txt");
                var host = CreateWebHostBuilder(args).Build();
                host.Run();
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Stopped program because of exception");
                throw;
            }
            finally
            {
                // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
                NLog.LogManager.Shutdown();
            }
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((ctx, builder) =>
                {
                    //https://anthonychu.ca/post/secrets-aspnet-core-key-vault-msi/
                    //var keyVaultEndpoint = Environment.GetEnvironmentVariable("KEYVAULT_ENDPOINT");
                    //if (!string.IsNullOrEmpty(keyVaultEndpoint))
                    //{
                    //    var azureServiceTokenProvider = new AzureServiceTokenProvider();
                    //    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                    //    keyVaultClient.GetSecretAsync(keyVaultEndpoint, "").GetAwaiter().GetResult();
                    //    //builder.AddAzureKeyVault(keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                    //}
                })
                .UseStartup<Startup>();
    }
}

И

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace AzureSecretsTest
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IConfiguration configuration)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Run(async (context) =>
            {
                var keyVaultEndpoint = Environment.GetEnvironmentVariable("KEYVAULT_ENDPOINT");
                StringBuilder sb = new StringBuilder();
                if (!string.IsNullOrEmpty(keyVaultEndpoint))
                {
                    var azureServiceTokenProvider = new AzureServiceTokenProvider();
                    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                    var secret = await keyVaultClient.GetSecretAsync(keyVaultEndpoint, "OneOfTheSecretKey");
                    sb.AppendLine($"Is null or whitespace: {string.IsNullOrWhiteSpace(secret.Value)}, Value: '{secret.Value}'");
                }

                //string configValue = configuration["OneOfTheSecretKey"];
                //var children = configuration.GetChildren();

                //sb.AppendLine($"Is null or whitespace: {string.IsNullOrWhiteSpace(configValue)}, Value: '{configValue}'");

                //foreach (IConfigurationSection item in children)
                //{
                //    sb.AppendLine($"Key: {item.Key}, Value: {item.Value}");
                //}
                await context.Response.WriteAsync(sb.ToString());
            });
        }
    }
}

1 Ответ

0 голосов
/ 21 декабря 2018

Как сказал Томас, когда вы используете расширение AddAzureKeyVault для добавления KeyVaultProvider.На данный момент, промежуточное программное обеспечение имеет достаточно информации, чтобы пойти и извлечь все данные KeyVault .Мы можем немедленно начать извлекать секретные значения с помощью API конфигурации.

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

var azureServiceTokenProvider = new AzureServiceTokenProvider();

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

var scret = keyVaultClient.GetSecretAsync(keyvaultEndpoint, SecretName).GetAwaiter().GetResult();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...