что такое vault плагин
Безопасное использование секретов: шаблон для использования HashiCorp Vault
HashiCorp Vault — это инструмент с открытым исходным кодом, который обеспечивает безопасный и надежный способ хранения и распространения секретов, таких как ключи API, токены доступа и пароли. Программное обеспечение, такое как Vault, может быть критически важным при развертывании приложений, требующих использования секретов или конфиденциальных данных.
Согласно недавнему исследованию ученых из Университета штата Северная Каролина, более 100 000 общедоступных репозиториев GitHub содержат открытые секреты приложений непосредственно в исходном коде. Это исследование — от частных токенов API до криптографических ключей — просканировало только около 13% общедоступных репозиториев GitHub — показывает, что надлежащая защита секретов приложений является одним из наиболее часто игнорируемых методов защиты информации в программном обеспечении.
Хотя масштабы воздействия удивительны, важно отметить, что эта проблема затрагивает не только проекты с открытым исходным кодом. Даже частные репозитории исходного кода могут раскрывать секреты, если они не защищены должным образом. Возьмем, к примеру, нарушение безопасности в Buffer Inc. в 2013 году. То, что начиналось как незаконный доступ к собственному исходному коду Buffer, привело к утечке учетных данных Twitter API компании, что в конечном итоге привело к рассылке спама в учетных записях Twitter бесчисленных клиентов.
Я не собираюсь угнетать Buffer прямо сейчас. Компании взламывают каждый день, и Buffer дал первоклассный ответ. Их нефильтрованная прозрачность и информирование об инцидентах послужили интересным примером важности управления секретами как основного принципа информационной безопасности. Но это также поднимает вопрос о том, как лучше всего управлять секретами в растущей, масштабируемой организации.
Введение в HashiCorp Vault
Я большой поклонник HashiCorp. Их подход к инструментам DevOps, не зависящий от поставщика, предоставляет отличные портативные решения, которые абстрагируются от отдельных поставщиков облачных услуг и фокусируются на решении реальных проблем. Их инструмент управления секретами, Vault, не исключение.
В то время как каждый отдельный поставщик облачных услуг имеет собственное решение для управления секретами, Vault является независимым от поставщика решением, которое позволяет централизованно управлять и обеспечивать доступ к секретам приложений без учета базового механизма секретов или методов аутентификации.
Установка Vault
Прежде чем мы сможем начать работу с Vault, нам сначала нужно его установить. Как и все продукты HashiCorp, Vault кроссплатформенный, с поддержкой macOS, Windows, Linux, Solaris и даже BSD. Вы даже можете запустить его на Raspberry Pi.
Запуск сервера
После установки Vault нам нужно запустить наш сервер. В этой статье я буду работать только с сервером разработки Vault. Однако важно отметить, что сервер разработки невероятно небезопасен и хранит все данные в памяти, а это означает, что при его перезапуске все будет потеряно. По словам самих HashiCorp:
Сервер разработки следует использовать для экспериментов с функциями Vault, такими как: различные методы аутентификации, механизмы секретов, устройства аудита и т. д.
Как видите, на экран выводится много данных, с которыми вы можете поиграть. Прежде всего следует отметить, что сервер разработки по умолчанию не запускается как демон (и в целях тестирования, никогда не должен запускаться как демон). Следовательно, если вы хотите взаимодействовать с сервером, вы должны сначала открыть второе окно терминала и экспортировать предоставленную переменную среды VAULT_ADDR, чтобы команда Vault хранилища знала, с каким сервером она должна взаимодействовать.
Также важно отметить значения Unseal Key и Root Token. Хотя мы коснемся того, что делать с Root Token в следующем разделе, понимание запечатывания / распечатывания Vault имеет решающее значение для правильного развертывания Vault в производственной среде.
Расшифровка и аутентификация
В производственной среде сервер Vault запускается в закрытом состоянии. Это означает, что Vault знает, где находятся данные, но не знает, как их расшифровать. На сервере разработки Vault по умолчанию не запечатан (unsealed). Однако, если вы решите запечатать его, вы получите ключ распечатки (Unseal Key), чтобы распечатать (unseal) его. Незапечатанный Vault остается в этом состоянии до тех пор, пока оно не будет повторно запечатано или сам сервер не будет перезапущен.
При первом запуске производственного сервера Vault важно его инициализировать. Этот процесс сгенерирует ключи шифрования и начальный корневой токен, и его можно будет запустить только с новыми хранилищами без каких-либо данных:
Вход в систему
Хранение секретов
В то время как Vault HashiCorp можно использовать для безопасного хранения практически любых данных, наиболее распространенным вариантом использования Vault является хранилище ключей и значений для секретов приложений. После проверки подлинности хранение секретов становится невероятно простым благодаря команде vault kv put :
Например, давайте посмотрим, что произойдет, если мы введем новое значение для того же секрета:
Видите, как был увеличен ключ метаданных версии? Это означает, что наше исходное значение должно поддерживаться в дополнение к новым значениям, что обеспечивает отличный журнал аудита того, какие секреты были изменены и когда.
Извлечение секретов
Хранение секретов — это только половина дела. Другая половина — извлекать эти секреты. В нашем примере выше давайте сначала посмотрим, как получить весь список секретов:
Как видите, хотя технически мы помещаем два секрета, отслеживается только один ключ, потому что эти два секрета на самом деле являются всего лишь двумя версиями одного секрета. Чтобы получить его, выполните команду vault kv get с секретным пространством имен и ключом:
Ценность секретов с управлением версиями невероятна, поскольку они позволяют внутренним службам привязаться к различным секретным версиям, что дает возможность постепенно развиваться, выпускать (release) и откатывать изменения приложений, не опасаясь потери важных данных.
Удаление секретов
Это помечает данные как удаленные ( deleted ) и предотвращает их извлечение в обычных запросах GET, но фактически не удаляет данные:
Чтобы данные действительно были удалены без возможности восстановления, необходимо использовать команду destroy:
Вместо того, чтобы просто пометить данные как удаленные и ограничить доступ к ним, команда destroy удалит их полностью, что сделает невозможным последующее извлечение:
Копаем глубже в HashiCorp Vault
Vault — сложный инструмент, и управление такими секретами — это лишь малая часть того, что можно с его помощью сделать. Хотя тонкости Vault выходят далеко за рамки этой статьи, давайте коснемся лишь нескольких других концепций, которые делают Vault таким мощным.
Secrets engines
Хранилище ключей и значений по умолчанию в Vault является примером механизма секретов (в частности, механизма под названием kv ). По своей сути алгоритм секретов — это абстрактный механизм хранения секретных данных. Это означает, что вместо механизма хранения на основе ключа-значения можно использовать более целевые механизмы хранения. Например, механизм секретов базы данных может использоваться для динамического генерирования учетных данных базы данных ( database ) на основе настроенных ролей для MySQL и MariaDB, что позволяет производить автоматическую ротацию учетных данных root или даже временные учетные данные для доступа по запросу.
Методы аутентификации
В дополнение к стандартному методу аутентификации на основе токенов Vault поддерживает ряд дополнительных методов аутентификации для лучшей поддержки ваших вариантов использования. Отличным примером этого является метод проверки подлинности GitHub, который можно использовать для автоматического предоставления доступа к Vault разработчикам, принадлежащим к определенной организации GitHub — и даже к определенной группе внутри организации GitHub — с использованием только токена личного доступа. Для более крупных организаций решения единого входа на уровне предприятия, такие как LDAP или Okta, могут использоваться для аутентификации пользователей в Vault.
Авторизация
Авторизация всегда идет рука об руку с аутентификацией. Хотя предоставить глобальный доступ с помощью GitHub или аутентификации на основе токенов несложно, это почти никогда не бывает полным решением. Благодаря политике Vault может быть реализован метод авторизации в стиле RBAC, предоставляющий разным пользователям и группам CRUD-подобный доступ к различным аспектам самого хранилища. В сочетании с одним из более продвинутых методов аутентификации это может стать невероятно мощным инструментом для детального контроля доступа в большой организации.
За пределами Vault
Каким бы мощным ни было Vault, настроить его правильно довольно сложно. Хотя размер и объем различных методов проверки подлинности и механизмов секретов ясно показывают, сколько вы можете сделать с Vault, может быть сложным осмыслить основы управления секретами в контексте информационной безопасности исходного кода. Благодаря впечатляюще большому количеству как официальных, так и общественных библиотек API, получение секретов безопасным способом невероятно просто, и если вы стремитесь стать опытным пользователем Vault, собственная учебная программа Vault HashiCorp – отличный способ для начала изучения.
Помимо безопасности приложений и инфраструктуры, вам нужен план быстрого реагирования на инциденты. Ознакомьтесь с нашим бесплатным руководством «От реактивного к упреждающему: 6 способов трансформации вашего мониторинга и реагирования на инциденты» для создания прозрачных рабочих процессов управления инцидентами с высокой степенью совместной работы.
Minecraft: Доступ к API (Vault)
Для работы большинства плагинов в Minecraft, особенно на сервере bukkit нужны специальные библиотеки, о которых знает не так много игроков. Одним из самых нужных плагинов можно считать Vault, потому что без него не будет работать ни одно дополнение для поддержания экономики или расширения прав игроков в определенной группе или сервере. Сюда же относятся и различные дополнения, которые предназначены для введения собственного чата. Причем плагины не зависят друг от друга, и могут работать в полноценной мере поодиночке.
Плагины, поддерживаемые Vault
Здесь перечислим основные дополнения, для которых требуется Vault, а также небольшое описание каждого из них, чтобы вы понимали, для чего они нужны. Основная категория – это плагины для расширения прав игроков. Они позволяют настраивать определенные группы людей и назначать им права, в зависимости от используемых дополнений. Очень полезно на серверах, где есть несколько типов игроков, работает вместе с экономическими плагинами. Сюда относятся такие, как Permissions, PEX, GroupManager и другие. Если дополнению требуется Vault, на сайте в разделе «Установка» будет информация об этом.
Далее в списке идет категория экономических плагинов. Все они предназначены для ведения торгов на сервере при помощи встроенной виртуальной валюты. Обычно такое дополнение после установки автоматически создает новую базу, в которой хранит информацию о денежных переводах каждого игрока. Сюда относятся: iConomy, EconXP – позволяет торговать опытом, MineConomy, eWallet и другие. Для экономики разработано множество дополнений, и практически все они похожи между собой функционалом. И последняя группа – это плагины, которые используются для ведения чата. В игре Minecraft есть встроенный чат, однако он не поддерживает русский язык, и очень часто «тормозит».
Дополнения для внедрения чатов позволяют использовать не только общий канал для всех игроков, но и создавать свои собственные, например, внутри фракции или использовать личный для переписки с конкретным игроком.
Установка плагина Vault
Скачайте с сайта Vault, зайдите на свой сервер и перенесите загруженные файлы в папку /plugins, и перезапустите сервер. Обязательно учитывайте версию плагина, и сервера bukkit, который используется на вашем проекте. В настройках дополнения имеется возможность автоматического обновления при наличии новых версий. При желании можно отключить.
Как не хранить секреты где придётся, или зачем нам Hashicorp Vault
Задайте себе вопрос — как правильно хранить пароль от базы данных, которая используется вашим сервисом? В отдельном репозитории с секретами? В репозитории приложения? В системе деплоя (Jenkins, Teamcity, etc)? В системе управления конфигурациями? Только на личном компьютере? Только на серверах, на которых работает ваш сервис? В некоем хранилище секретов?
Зачем об этом думать? Чтобы минимизировать риски безопасности вашей инфраструктуры.
Начнём исследование вопроса с определения требований к хранению секретов.
Требования к способу хранения секретов инфраструктуры:
Примерим наши требования к возможным решениям:
Почему Vault?
Для нас Vault решает проблемы передачи секретов по незащищённым каналам, проблемы отказоустойчивого хранения секретов, а также проблемы гибкого разделения и аудита доступов. В планах использовать Vault как собственный CA.
Начало работы
Не буду переводить официальную документацию, поэтому вот несколько ссылок:
Итак, вы запустили Vault. Первым делом положим наш ключ в хранилище. Официальный процесс работы выглядит так:
О мастер-токене для каждого сервиса
Оказалось неудобным постоянно переключать токены, если ты отвечаешь за несколько сервисов.
Из-за особенности управления политиками доступа (подробнее ниже) выросли накладные расходы на первичное внедрение Vault в рабочий процесс сервиса.
Про особенности управления политиками доступа
Они описываются в формате JSON или HCL и записываются в Vault с помощью запроса к API или через cli. Например, так:
Чтобы созданный вами мастер-токен мог создавать новые токены, он должен иметь политику:
Мастер-токен может создавать токены только с теми политиками, которыми он обладает.
Это означает, что вам недостаточно выдать токену политику service_name_prod_root:
которая обладает полным доступом к secret/service_name/prod/*, но также нужно озаботиться, политикой service_name_prod_read:
и тогда вы сможете создавать токены для read-only доступа с помощью команды:
И тут есть нюанс: политики применяются по степени детализации. Это означает, что если вы сделаете root политику вида:
и захотите дать доступ на чтение политике service_name_prod_database_read:
то вам нужно будет назначить токену, управляющему этим сервисом обе этих политики. Когда вы это сделаете, вы не сможете писать в secret/service_name/prod/database/*:
Вам придётся уравновесить каждую детализированную политику на чтение, чтобы этого не случилось. Например, видоизменить политику service_name_prod_root:
Это не делает жизнь операторов легче, поэтому мы отказались от этого подхода и работаем с секретами только из под root-ключей.
Об учёте и обновлении токенов
Подробности тут.
Ведение данных о выданных токенах позволяет проводить быстрый аудит активных доступов в системе и настроить мониторинг на истечение срока жизни токена.
О параметрах токена
Пройдём по возвращённым параметрам:
Неочевидности и полезности
Если вы будете использовать consul-template для автоматической перегенерации конфигов при изменении секретов, имейте в виду (и этого вы не найдёте в документации), что consul-template опрашивает изменение секрета в двух случаях:
Наш процесс работы:
Нам не подошёл официальный процесс работы с Vault по причине излишней трудоёмкости внедрения Vault в эксплуатацию сервиса. Поделюсь нашими решениями и ответами на возникающие вопросы в процессе внедрения Vault.
Решите этот вопрос до того, как ваш список секретов начнёт быстро расти и вы начнёте прикручивать различные средства автоматизации. Мы используем первую схему.
Вернёмся к хранению секрета от базы данных
Мы установили и запустили Vault, получили root-токен. Что дальше?
По последней версии процесса, принятого в моей компании, это будет выглядеть так:
Установим vault.
Укажем расположение Vault:
Авторизуемся под root токеном:
Запишем наш секрет:
Запишем политику для чтения в файл service_name_prod_read.hcl:
Создадим политику в Vault:
Сгенерируем токен для чтения:
Запишем token_accessor для последующего аудита и мониторинга.
Проверим, что есть доступ на чтение:
Всё работает, мы готовы использовать наш токен в системах автоматизации. Приведу примеры для популярных систем.
Просто curl:
Ansible (мы используем https://github.com/jhaals/ansible-vault):
Используем переменные из Vault в роли:
Мы делаем запросы к vault только на уровне group_vars/group_name. Это удобно и позволяет не искать переменные по роли.
Hashicorp в своём блоге описали несколько путей использования секретов из Vault в своих chef-кукбуках — https://www.hashicorp.com/blog/using-hashicorp-vault-with-chef.html
Puppet:
Для puppet существует прекрасный модуль https://github.com/jsok/hiera-vault, из документации к которому понятен процесс использования секретов из Vault.
Consul-template:
Необходимо либо иметь токен и адрес Vault в переменных окружения:
или добавить в конфиг строчки:
и использовать секреты в своих шаблонах:
Спасибо за потраченное время, надеюсь, это было полезно.
Готов ответить на ваши вопросы.
Плагин Vault
Плагин Vault — это API разрешений, чата и экономики, позволяющий подключать подключаемые модули к этим системам без необходимости подключать или зависеть от каждого отдельного подключаемого модуля. Он возник из-за отвращения к тому, как работают и Реестр, и к текущему API разрешений, а также к их отсутствию функций или слишком сложным реализациям. Vault пытается решить эти проблемы за счет интуитивного понимания и предоставления плагинов поддержки для любой системы, которую они могут использовать.
проверка обновления
включает / выключает проверку обновлений
Разрешения:
vault.admin
позволяет получить доступ к информации о хранилище и командам преобразования
по умолчанию OP
vault.update
Любой, у кого есть это разрешение, будет уведомлен об устаревании Vault.
по умолчанию OP
значение false в permissions.yml отключит сообщения проверки версии для консоли
Vault в настоящее время поддерживает:
Уникальный идентификатор
Серверная версия Java
Находится ли сервер в автономном или онлайн-режиме
Версия плагина
Версия сервера
Версия ОС / название и архитектура
количество ядер для процессора
количество игроков онлайн
Метрическая версия
Какой крюк чата, экономики и разрешений используется.
Управление секретами при помощи HashiCorp Vault
Как правильно хранить секреты? В репозитории, в системе деплоя или в системе управления конфигурациями? На личном компьютере, на серверах, а может в коробке под кроватью? А как управлять секретами, чтобы не допускать утечек?
Сергей Носков (Albibek) — руководитель группы информационной безопасности платформы из Авито, знает ответ на эти вопросы и поделится с нами. В Авито два года активно используют HashiCorp Vault, за это время набили шишки, и прокачали опыт до уровня «Мастер».
В статье всесторонне поговорим про Vault: что это такое, где и как используется в компании, как в Авито управляют секретами с помощью HashiCorp Vault, как используют Puppet и Kubernetes, варианты использования с Puppet и другими SCM, какие возникают проблемы, что болит у безопасников и разработчиков, и, конечно, поделимся идеями, как все исправить.
Что такое секрет
Любая конфиденциальная информация:
HashiCorp Vault — одно из неплохих решений проблемы.
Что нового в HashiCorp Vault
Инструмент развивается и за последнее время в нем появилось много интересных фич: CORS-заголовки для GUI без посредников; встроенный GUI; нативная интеграция с Kubernetes; плагины для logical- и auth-бэкендов и фреймворк.
Большинство изменений, которые понравились лично мне, — это возможность не писать расширения и дополнения, которые будут стоять снаружи относительно инструмента.
Например, есть Vault, вы хотите его расширить — написать дополнительную логику или свой UI для автоматизации, который будет что-то автоматизировать. До изменений приходилось поднимать дополнительный сервис, который стоит перед Vault, и проксирует все запросы: сначала запросы идут в сервис, потом — в Vault. Это плохо тем, что в промежуточном сервисе может быть пониженный уровень безопасности, а через него идут все секреты. Риски безопасности намного выше, когда секрет проходит через несколько точек сразу!
Проблема курицы и яйца
Когда вы поднимаете вопрос хранения конфиденциальной информации и решаете шифровать, то, как только вы что-то зашифровали, ваш секрет смещается из места шифровки туда, где хранится ключ. Это происходит постоянно: как только вы сохранили куда-то секрет или изменили существующий, у вас появляется еще один и начинается заколдованный круг — где хранить секрет для доступа к секрету.
Секрет доступа к секрету — это та часть безопасности, которая называется аутентификацией. У безопасности есть еще одна часть — авторизация. В процессе авторизации проверяется, можно ли пользователю получить доступ именно туда, куда он запрашивает. В случае с Vault есть доверенная третья сторона, которая решает, выдать секрет или нет. Авторизация лишь частично решает проблему.
HashiCorp Vault в Авито
В Авито HashiCorp установлен в единственной большой инсталляции на всю сеть. У HashiCorp Vault много разных бэкендов. Мы используем бэкенд на базе Consul тоже от HashiCorp, потому что Vault умеет поддерживать собственную отказоустойчивость только через Consul.ь.
Unseal — это способ не держать в одном месте мастер-ключ. Когда запускается Vault, он все шифрует на каком-то ключе, и снова появляется проблема курицы и яйца: где хранить секрет, которым будут шифроваться все остальные секреты. Чтобы избежать этой проблемы, в Vault предусмотрен составной ключ, для получения которого требуется несколько частей ключа, которые мы раздаём нескольким сотрудникам. В Авито мы настроили в опциях Unseal на 3 человека из 7. Если мы запускаем Vault, то чтобы он начал работать, обязательно должны прийти как минимум 3 человека и ввести свою часть ключа. Ключ поделен на 7 частей и можно принести любые из них.
Мы собрали маленький тестовый Vault — песочницу для разработчиков, где они могут играть. Он есть в виде Docker-контейнера и создает простые секретики, чтобы люди могли потрогать инструмент руками, освоиться. В песочнице нет Consul и кластеризации, это просто файловая система, на которой Vault держит зашифрованные секреты, и маленький скрипт для инициализации.
Вот что мы сейчас храним в Vault:
Мы стараемся доставлять секреты в виде файлов.
Мы не говорим разработчику: «Иди в Vault, бери секрет!», а выкладываем на диск файл и сообщаем: «Разработчик, у тебя на диске появится файл, забирай секрет из него, а мы уже разберемся, как достать его из Vault и принести тебе».
Мы приняли простое соглашение для полей JSON, в котором указываем, с какими правами выкладывать файл. Это метаданные для файловой системы, а поле data — это закодированная строка c самим секретом, которая станет содержимым файла.
Puppet + Hiera + Vault
Практически во всей инфраструктуре Авито используется Puppet, им раскатываются все серверы.
У Puppet есть удобный инструмент организации иерархии — Hiera. Vault очень хорошо интегрируется с Hiera через дополнительный модуль, потому что в эту библиотеку идёт запрос ключ-значение, а Vault сам база ключ-значение, но со всеми функциями безопасности — с прозрачным шифрованием и возможностью выбора доступа к ключам.
Поэтому первое, что мы внедрили — это Vault в Puppet, но с одним дополнением — у нас есть промежуточный слой, который называется Router backend. Router backend — отдельный модуль Hiera, просто файлы на диске, в которых написано, куда Hiera должна идти за ключом — в Vault или в другое место.
Он нужен, чтобы Hiera не ходила в Vault постоянно, потому что она идет всегда по всей иерархии. Это не проблема Vault или нагрузки на него, а особенность работы самой Hiera. Поэтому если оставить только модуль для Vault без Router backend, Puppet-мастер будет очень долго собирать конфигурацию для Puppet-агента, так как будет проверять каждый ключ в Vault.
Для Puppet проблема курицы и яйца решается за счёт того, что авторизующая сторона у нас — Puppet-мастер. Именно он выдает секрет для доступа к секрету. Puppet-мастер имеет доступ ко всем секретам сразу, но каждому хосту разрешено получать только тот, который ему предназначен. Хост на Puppet-мастере уже авторизован своим сертификатом, который генерируется локально и пределов хоста не покидает. В принципе, секрет для доступа к секрету остается, но это уже не так критично.
Наш процесс выкладки нового секрета в Puppet состоит из следующих этапов.
Дополнительным плюсом мы получаем «фишку» Hiera — секрет можно выкладывать сразу для группы хостов или в зависимости от роли хоста, которую мы выставляем в переменной role.
Единственная опасность: если у вас Puppet, и вы используете Hiera, не подставляйте в пути в шаблоны переменных что попало, потому что многие факты и переменные собираются на клиентской стороне. Если злоумышленник подменит факт на клиенте, Puppet-мастер отдаст ему чужие секреты. Обязательно проверяйте переменные: используйте только те, что Puppet-мастер запрещает определять на клиентской стороне.
Как быть с SCM без мастера?
Если вдруг у вас не Puppet, то, скорее всего, Ansible. Для Chef и других централизованных SCM свои решения — это плагин, который умеет обращаться к Vault. Предлагаю несколько вариантов, которые можно реализовать с Ansible.
Локальный агент
Локально для сервера генерируете токен, который фактически является паролем для доступа к Vault. Токен действует постоянно. Вы можете обновлять его или автоматизировать. С этим токеном в обращаетесь в Vault и забираете свои секреты.
Идея в том, что у вас на сервере, куда надо доставить секреты, крутится агент, который приходит в Vault, смотрит все секреты и выкладывает их в виде файлов. Мы используем агента на нескольких отдельных серверах, где нет Puppet.
Минусы:
Транзитное шифрование
Vault имеет функцию transit encryption, суть которой в том, что Vault выступает сервером шифрования. Вы просто приносите ему открытый текст, а он на своем закрытом ключе, который есть только у него, шифрует и выдает закрытый текст. Дальше вы выбираете, кто этот закрытый текст сможет расшифровать.
У Ansible есть сущность, которая тоже называется Vault. Это — не HashiCorp Vault, а Ansible Vault. Здесь нужно не перепутать, а секреты можно хранить как в первом, так и во втором. В Ansible есть уже готовый плагин для доcтавки секретов из Hashicorp Vault. Если вам дать личный доступ в Vault, то вы сможете расшифровывать секреты. Когда вы накатываете Ansible, он от вашего имени идёт в Vault, расшифровывает секреты, которые в зашифрованном виде находятся в репозитории, и выкатывает в продакшен.
Здесь тоже есть недостаток — каждый администратор получает доступ к секретам. Но есть аудит: Vault умеет вести журнал активности о том, какой пользователь приходил, какой секрет читал, какой получил доступ. Вы всегда знаете, кто, когда и что делал с секретом. Этот вариант мне кажется неплохим.
Большой Недостаток № 1
Самый большой недостаток, который вызывает самую большую боль у нас — то, что в Vault нельзя никому делегировать полное управление какой-то частью данных. В Vault доступ к секрету осуществляется по путям, похожим на пути в UNIX — имена принято разделять слешами, и в результате получается «директория». Когда у вас есть такой путь, иногда вы хотите взять часть пути и отдать её на управление кому-то еще.
Например, вы завели сертификаты, назвали /certs, и хотите отдать отдельным безопасникам, которые занимаются PKI. В Vault не получится этого сделать. Вы не можете дать право выдавать права внутри этого префикса — чтобы безопасники сами могли раздавать права на сертификаты еще кому-то.
В Vault нет возможности выборочно выдавать права на выдачу прав. Как только вы дали право на выдачу прав, то выдали и возможность получить полный доступ ко всем секретам. Другими словами, вы не можете дать доступ на часть Vault.
Это одна из самых больших проблем. У меня есть идея, как ее решить, позже про нее расскажу.
Kubernetes
На РИТ++ я рассказывал про отдельную систему, которую мы реализовали для Kubernetes: она служит третьей стороной, ходит в API, проверяет доступ и потом запрашивает секрет в Vault.
Сейчас наша система потеряла актуальность, потому что в Vault 0.9 появилась нативная поддержка Kubernetes. Теперь Vault сам умеет ходить в Kubernetes и убеждаться, что доступ к секрету разрешён. Делает он это при помощи Service Account Token. Например, когда у вас выкатился pod, там лежит специальный, подписанный и авторизованный для него JWT, предназначенный для запросов к API Kubernetes. С токеном можно также авторизоваться в Vault и получить секреты именно для вашего namespace.
Все делается на уровне самого Vault. Правда, на каждый namespace надо будет заводить роль, то есть сообщать Vault, что есть такой namespace, в нём будет авторизация, и прописывать, куда ходить в Kubernetes. Это делается один раз, а дальше Vault будет сам ходить в API, подтверждать валидность JWT и выдавать свой собственный токен для доступа.
Правила Kubernetes
В плане имени сервисов и дополнительных метаданных мы доверяем разработчикам. Есть маленькая вероятность, что разработчики могут случайно или намеренно получить секреты других сервисов, которые крутятся в одном namespace, поэтому мы ввели правило: один сервис — один namespace.
Новый микросервис? Заводите новый namespace со своими секретами. Перейти через границу в соседний нельзя — там свои Service Account Token. Граница безопасности в Kubernetes на данный момент — это namespace. Если в двух разных namespace нужен один секрет — копируем.
В Kubernetes есть kubernetes secrets. Они хранятся в etcd в Kubernetes в незашифрованном виде и могут «засветиться» в dashboard или при запуске kubectl get pods. Если в вашем кластере отключена аутентификация в etcd, или если вы дали кому-то полный read-only-доступ, то ему видны все секреты. Именно поэтому мы ввели два правила: запрещено использовать kubernetes secrets и запрещено указывать секреты в переменные окружения в манифестах. Если вы в deployment.yaml прописываете секрет в environment — это плохо, потому что сам манифест могут посмотреть все кому не лень.
Доставка Kubernetes
Как я уже сказал, мы должны как-то положить файл в Kubernetes. У нас есть какой-то секрет: сущность, пароль, который в JSON записан в Vault. Как его теперь превратить в файл внутри контейнера в Kubernetes?
Первый вариант доставки.
Мы используем примерно такой префикс:
В имя префикса заложены имя кластера, namespace и имя сервиса. У каждого сервиса свой секрет, в каждом namespace свой секрет.
Второй вариант — это свой собственный entrypoint. К нему мы сейчас переходим в Авито, потому что с init-container у разработчиков естьпроблемы. На схеме этот вариант справа.
Собственный entrypoint не все могут себе позволить. Мы — можем, поэтому в каждом контейнере мы форсим наш специальный entrypoint.
Наш entrypoint делает то же самое, что init-container: идет в Vault с Service Account Token, берет секреты и выкладывает их. Кроме как в файлы, он кладет их еще в environment. Вы получаете возможность запускать приложение как это рекомендуется концепцией Twelve-Factor App: приложение берет все настройки, в том числе, секреты, из переменных окружения.
Переменные окружения не видно в манифестах и дашборде, поскольку их устанавливает PID 1(основной процесс контейнера) при запуске. Это не переменные окружения из deployment.yaml, а переменные окружения, которые выставил entrypoint в процессе работы. Они не видны в dashboard, их не видно, даже если сделать kubectl exec в контейнер, потому что в этом случае запускается другой процесс, параллельный PID1.
Workflow
С организационной точки зрения, процесс идет следующим образом. Разработчик узнаёт от security champion или из документации, что ему нельзя хранить секреты в репозитории, а только в Vault. Тогда он приходит к нам и спрашивает, куда класть секреты — подаёт заявку в security на заведение префикса. В будущем можно создавать префикс без заявки, сразу при создании сервиса.
Разработчик ждет, и это плохо, т.к. для него главное — time-to-market. Дальше он читает инструкции, разбирается с длинными файлами — «вставь туда ту строку, вставь сюда эту строку». Никогда раньше разработчик не заводил init-container, но он вынужден разобраться и прописывать его в deployment.yaml (helm chart).
Коммитит, ждет, пока TeamCity выкатит, видит ошибки в TeamCity, начинает испытывать боль, пытается что-то поправить, снова испытывает боль. Дополнительно накладывается то, что каждая выкатка в TeamCity ещё может встать в очередь. Иногда разработчик не может разобраться сам, приходит к нам, и мы разбираемся вместе.
В основном разработчик страдает из-за собственных ошибок: неправильно задал init-container или не дочитал документацию.
Со стороны Security тоже есть проблемы. Безопасник получает заявку, в которой всегда мало информации, и мы все равно выясняем недостающие вопросы: выясняем имена кластеров, namespace сервиса, так как разработчик не указывает их в заявке и даже не всегда знает, что это такое. Когда всё выясним, создаём политики и роли в Vault, прописываем политики группам и вместе с разработчиком начинаем выяснять, где и почему он ошибся, и вместе читаем логи.
Проблему помогает решить юнит «Архитектура» сокрытием от разработчика deployment.yaml. Они разрабатывают штуку, которая все генерирует за разработчика, в том числе entrypoint. Благодаря тому, что мы подставляем свой entrypoint, мы можем использовать его не только для доставки секретов, но и для других вещей, которые может понадобиться делать при старте.
Очевидные проблемы с секретами Kubernetes.
Идея: Kubernetes KMS
В новых версиях Kubernetes появилась подсистема KMS — Key Management Service — новая возможность Kubernetes по шифрованию секретов. В v1.11 она была с состоянии alpha, в v1.12 её перевели в beta.
Картинка с сайта проекта провайдера KMS для Vault, и на ней есть ошибка. Если найдете — напишите в комментариях.
Смысл KMS в том, чтобы устранить один-единственный недостаток — нешифрованное хранение данных в etcd.
KMS, как Ansible, умеет вот что.
CI/CD: TeamCity
В TeamCity все просто, потому что JetBrains написали плагин, который сам умеет прописать у себя секреты для доступа к секрету, зашифровать их средствами TeamCity, а потом там же в качестве параметра где-нибудь в шаблоне подставить через проценты. В этот момент агент TeamCity сам сходит в Vault, заберёт секрет и принесёт в билд в виде параметра.
Некоторые секреты нужны при деплое, например, миграции БД или оповещения в Slack. AppRole заводится на каждый проект — настройки тоже содержат секрет (данные для AppRole), но он вводится в режиме write-only — прочитать его потом TeamCity не позволяет.
TeamCity сам заботится о том, чтобы при попадании секрета в логи билда, он автоматически маскировался. В результате секрет либо не «проезжает» через диск совсем, либо вычищается с диска средствами TeamCity. В результате вся безопасность секрета хорошо обеспечена самим TeamCity и плагином, и дополнительных танцев с бубном не требуется
CI/CD не TeamCity?
Вот основные вопросы, над которыми надо подумать, если в качестве CI вы используете другую систему (не TeamCity).
Важно не забывать чистить результаты билда по окончании сборки, если они выложились на диск, либо обеспечить, чтобы они находились только в памяти.
Сертификаты
С сертификатами ничего особенного — мы используем Vault в основном для их хранения.
Vault имеет специальный PKI backend для выпуска сертификатов, в котором можно заводить Certificate Authority и подписывать новые сертификаты. У нас единый внутренний PKI… Корневой CA и CA второго уровня существуют отдельно, а CA третьего уровня мы уже управляем через Vault. Для хранения выпущенных сертификатов любого уровня, включая сертификаты подписанные внешними CA, мы используем отдельный префикс, и кладём туда почти все действующие сертификаты в целях учёта и мониторинга. Формат хранения сертификатов собственный, подходящий для хранения отдельно закрытого ключа и собственно сертификата.
Резюме
Слишком много ручной работы для безопасника, слишком большой порог вхождения для разработчика и нет встроенных средств для делегирования, хотя очень хочется…
Как быть? Дальше начинаются мечты.
Идеи: как сделать лучше
Как можно избавиться от кучи копий секрета?
Доставка master-slave
У нас есть master-секрет и специальный демон, который ходит, смотрит секрет и его метаданные, выкладывает куда надо, получается slave-секрет. По пути, куда демон выложил slave, ничего нельзя менять руками, потому что демон придет и заново выложит master-секрет поверх slave.
Сначала мы хотели сделать механизм симлинков, чтобы просто указать: «Вот этот секрет ищи там!», как в Linux. Оказалось, что возникают проблемы с правами доступа: неизвестно, как права доступа проверять — как в Linux или нет, с родительскими путями, с переходами между точками монтирования. Слишком много неоднозначных моментов и шансов ошибиться, поэтому от симлинков мы отказались.
Авторизация на основе владения
Второе, что мы хотим сделать — определить владельца для каждого секрета. По умолчанию секрет принадлежит тому, кто его создал. При необходимости можно расширить зону ответственности до юнита, выдав группу-владельца.
Когда мы научимся делегировать, мы выдадим владельцу права на секрет, и он сможет делать с секретом, что хочет.
Поскольку это владелец секрета, то для варианта доставки master-slave он мог бы выбирать, куда и в каком формате ему доставлять секрет. Получается, что владелец сам всем управляет, не надо подавать заявки, нужный префикс можно занять самостоятельно, секреты тоже можно создавать и удалять самому.
Делегирование через шаблоны ACL
Политика доступа Access Control List в Vault поделена на две части:
Мы хотим задавать ACL готовым шаблоном, который содержит путь и плейсхолдеры, на которых разрешено генерировать новые ACL по этому шаблону.
Пример
Ниже желтым шрифтом записан путь готовой стандартной ACL от Vault и дальше разрешённые действия на этот путь. Мы ее рассматриваем, как ACL на разрешение менять другую ACL внизу, которая задана в виде шаблона.
Мы хотим делегировать доступ на /k8s, разрешаем генерировать только такие шаблоны. Например, давать доступ только на чтение в конкретный кластер, namespace, сервис, но не менять поле capabilities.
Дополнительно мы хотим давать разрешение привязывать эти ACL и выдавать разные права.
В результате разработчик по своему усмотрению через наш плагин присваивает эту ACL кому захочет, а сам становится владельцем, может ей управлять, как секретом: удалять, отдавать и отнимать у пользователей и групп. Теперь человек сам ответственен за свой префикс: он управляет всеми секретами, генерирует по шаблону ACL, может присваивать ACL тем, кому захочет. Естественно, мы тоже можем его ограничить.
Вся магия работает при помощи новой сущности Vault — плагинов. Они представляют собой отдельный сервис, очень похожий на тот, о котором я говорил в начале, и работают почти точно также. Единственное важное отличие — они не прокси. Плагины запускаются «сбоку» от Vault, причём запускает их основной процесс Vault. За счёт этого все запросы идут не через сервис, а в Vault, который уже сам взаимодействует с плагином, отправляя ему проверенный и очищенный запрос.
Про плагины, как они устроены и как их писать, можно почитать на сайте Vault. Писать их лучше всего на Go, что достаточно просто, т.к. для Go есть фреймворк. Vault общается с плагином по grpc, запускает его как сервис, но не надо пугаться, вы его не касаетесь — во фреймворке уже все заложено. Вы просто пишете, более-менее стандартное REST приложение, в котором указываете endpoints, к ним даете готовые функции, хэндлеры, на которых будет логика.
Не бойтесь, что вы что-то сломаете в основном Vault. Плагин — это отдельный сервис. Даже если плагин у вас запаниковал и упал, работу Vault это никак не нарушит. Vault просто перезапустит плагин и будет работать дальше.
Кроме того, есть дополнительные настройки для самого плагина: он обязательно проверяет хэш-суммы, чтобы никто не подменил бинарник. Безопасность запуска плагинов обеспечена.
Полезные ссылки:
Про DevOps и безопасность, CI/CD, k8s, Puppet и всё в таком духе будем говорить на HighLoad++ (ближайший в Питере в апреле) и на DevOpsConf. Приходите поделиться своим опытом или посмотреть на других. Чтобы не забыть, подпишитесь на блог и рассылку, в которой мы будем напоминать о дедлайнах и собирать полезные материалы.