Секреты .Net-приложения в Яндекс.Облаке: Lockbox

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Наверное, в любых проектах есть необходимость использования различных секретных данных - строки подключения к БД, АПИ-ключи внешних сервисов и т.д.. К сожалению, до сих пор далеко не всегда разработчики заботятся о соответствующей защите этих данных: на прошлой неделе Гитхаб даже выкатил функцию push protection, чтобы у пользователя был ещё один рубеж защиты от проникновения этих данных в репозиторий.

Несмотря на то, что на рынке довольно много облачных сервисов для хранения и управления секретами, ввиду их зарубежного происхождения с недавних пор их использование стало затруднительно. Но мы не унываем, потому что на наших просторах появился Яндекс.Облако Локбокс.

Давайте добавим работу с секретами из Яндекс.Облака в .Net Core приложение в виде одного из источников конфигурации.

Когда разработчик думает о развёртывании приложения и его секретах, то первыми приходят на ум переменные окружения (сегодня мы не рассматриваем Кубернетис, а будем говорить о классическом развёртывании на виртуальные машины или облачные сервисы). Действительно, у такого решения много плюсов - отсутствие внешней зависимости, простота конфигурирования и так далее. Но они перекрываются одним жирным минусом - это небезопасно. Переменные окружения хранятся в незашифрованном виде и доступны любому процессу в системе. К тому же любая библиотека вашего приложения сможет получить доступ к этим данным, поэтому вы должны быть очень уверены в поставщиках своих зависимостей.

Вынос секретов вовне предполагает внедрение дополнительной зависимости, но добавляет удобства уравления и однозначно добавляет очков безопасности вашему решению: малваря, которая может распространиться по среде вашего приложения, уже не сможет просто так забрать всё в укромный уголок.

Ввиду этого, в переменных окружения есть смысл хранить только те данные, с помощью которых нужно каким-либо образом авторизоваться во внешнем поставщике секретов.

Держа в уме это сокровенное знание, переходим к практике.

Создание секрета в Yandex.Cloud Lockbox

Не так давно в Яндекс.Облаке был анонсирован сервис Lockbox, который представляет из себя хранилище секретов в виде набора пар ключ-значение (до 32-х пар в одном секрете). На данный момент сервис всё ещё находится в предварительном виде и не тарифицируется, но вы можете запросить к нему доступ и уже сейчас воспользоваться этим функционалом.

Для начала откроем консоль Яндекс.Облака и создадим сервисную учётную запись с ролью "lockbox.payloadViewer". Её идентификатор нам понадобится в будущем.

Новая сервисная учётка
Новая сервисная учётка

Следующим шагом создадим новый авторизованный ключ для этой сервисной учётки. Нам необходимо записать идентификатор этого ключа, а также приватный ключ. Приватный ключ нам понадобится позже, когда наше приложение будет аутентифицироваться в Облаке с помощью JWT-токена.

Новый ключ
Новый ключ

Теперь можно создать первый секрет

Новый секрет
Новый секрет

Обратите внимание на ключ секрета. Стандартный построитель конфигурации дотнетного приложения IConfigurationBuilder (Microsoft.Extensions.Configuration) умеет работать с иерархией, поэтому мы в .Net можем строить сложные конфигурационные объекты. Разбор древовидной структуры происходит с помощью разделителя, по-умолчанию это символ ":", но, к сожалению, этот символ не поддерживается в поле Ключ, поэтому приходится заменить его другим.

Теперь мы создали всё на стороне Локбокса и можно приступать к настройке своего приложения.

Добавление секрета в .Net Core приложение

Для начала добавим нужные для работы и не секретные параметры в настройки приложения (appsettings.json):

{
  "YC": {
    "ConfigurationSecretId": "e6q3a82d6m2bkltjar6q",
    "ServiceAccountId": "ajk2cdb9jq2mk4unqq13",
    "ServiceAccountAuthorizedKeyId": "ak228rm0obcn5o90ij43"
  }
}

Также добавьте приватный ключ авторизованного ключа в переменную окружения YC_PRIVATE_KEY.

Для того, чтобы ваше приложение могло взять секреты из Локбокса, ему необходимо аутентифицироваться в Облаке. Для аутентификации есть несколько вариантов:

  1. OAuth-токен - не самый лучший вариант так как привязан непосредственно к вашему пользователю и имеет срок жизни 1 год.

  2. JWT-токен - отлично подходит для аутентификации приложений. Привязан к сервисной учётке и аутентифицирует приложение с помощью короткоживущего IAM-токена.

  3. API-ключ и Статический ключ - простая аутентификация бессрочным ключом, но поддерживаются не все сервисы Облака.

Из предложенного мы воспользуемся JWT-токеном как наиболее безопасным и универсальным вариантом.

Не так давно команда Яндекса начала работу над SDK для платформы .Net (спасибо им!), но, к сожалению, в нём пока не реализован провайдер авторизации с помощью JWT-токена, поэтому пришлось реализовать его самому.

Добавьте в ваше приложение (.Net 6) пакет Delobytes.Extensions.Configuration:

dotnet add package Delobytes.Extensions.Configuration

И добавьте вызов расширения AddYandexCloudLockboxConfiguration в его настройки конфигурации:

WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddYandexCloudLockboxConfiguration(config =>
        {
            IConfigurationRoot tempConfig = new ConfigurationBuilder()
                    .AddEnvironmentVariables()
                    .AddJsonFile("appsettings.json")
                    .Build();
            config.PrivateKey = Environment.GetEnvironmentVariable("YC_PRIVATE_KEY");
            config.ServiceAccountId = tempConfig.GetValue<string>("YC:ServiceAccountId");
            config.ServiceAccountAuthorizedKeyId = tempConfig.GetValue<string>("YC:ServiceAccountAuthorizedKeyId");
            config.SecretId = tempConfig.GetValue<string>("YC:ConfigurationSecretId");
            config.Path = "MyPath";
            config.PathSeparator = '-';
            config.Optional = false;
            config.ReloadPeriod = TimeSpan.FromDays(7);
            config.LoadTimeout = TimeSpan.FromSeconds(20);
            config.OnLoadException += exceptionContext =>
            {
                //log
            };
        });

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

WebApplication? app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Расширение создаст JWT-токен, обменяет его на IAM-токен и загрузит указанный SecretId. В вашу конфигурацию будут загружены все пары "ключ-значение" и они будут подгружаться снова через указанный промежуток времени.

В результате во всём приложении вы сможете получать секреты с помощью стандартных механизмов работы с конфигурацией. Например, вы можете создать соответствующий объект и замапить на него ваш секрет:

public class AppSecrets
{
    public string SecretServiceToken { get; set; }
}
[Route("/")]
[ApiController]
public class HomeController : ControllerBase
{
    public HomeController(IConfiguration config)
    {
        _config = config;
    }

    private readonly IConfiguration _config;

    [HttpGet("")]
    public IActionResult Get()
    {
        AppSecrets secrets = _config.GetSection(nameof(AppSecrets)).Get<AppSecrets>();

        return Ok();
    }
}

Итогo

В результате проделанного опыта можно в очередной раз порадоваться гибкости .Net - простота интеграции в существующую Asp Net Core среду (спасибо Майкрософт за наше счастливое детство) позволяет производить миграции с одной платформы на другую в рекордные сроки.

Надеюсь, что Яндекс.Облако и дальше продолжит радовать разработчиков годными сервисами и будет расширять свою поддержку .Net-сообщества, а сообщество будет работать над тем, чтобы не пополнять печальную статистику утёкших секретных данных.

Всем добра!

Источник: https://habr.com/ru/post/660449/


Интересные статьи

Интересные статьи

Использование глубокого обучения и обработки изображений для реставрации и сохранения произведений искусства.Когда в 2005 году Карола-Бибиана Шёнлиб начала защищать докторскую диссертацию по математик...
Фото Ricardo Gomez Angel, Unsplash.com Используем метрики для отправки уведомлений через Slack В предыдущей статье мы задеплоили оператор Prometheus с помощью helm-чарта и на примере набора сервис...
Criteo — это компания, работа которой основана на данных. Каждый день через наши системы проходят десятки терабайт новых данных для обучения моделей рекомендаций, обрабатывающих запр...
Статья о том, как упорядочить найм1. Информируем о вакансии2. Ведём до найма3. Автоматизируем скучное4. Оформляем и выводим на работу5. Отчитываемся по итогам6. Помогаем с адаптацией...
Один из ключевых сценариев работы в CRM это общение с клиентом в удобном для него канале. По почте, по телефону, по SMS или в мессенджере. Особенно выделяется WhatsApp — интеграцию с ...