Наш рассказ — это гид автостопщика, некое summary тех вещей, которых нам не хватало при знакомстве с Vault. В нем мы сделаем несколько остановок: поговорим в целом про управление секретами, о том, почему мы рекомендуем именно Vault; рассмотрим, как Vault работает; поделимся лайфхаками по работе с секретами и болью о том, чего нам не хватает в продукте. Секрет — это любые аутентификационные данные (токены, пароли, ключи). Их можно хранить на стикере, прикрепленном к монитору, в текстовых файлах, в мессенджерах, Ansible-плейбуках, Git и других местах. К сожалению, это небезопасно, так как они могут теряться или «утекать». А вот если вы используете систему управления секретами, то они живут все вместе, а вы можете задавать к ним доступ, и вообще — они хранятся достаточно надежно. Зачем мы перекладываем все секреты в одно место? Ну, очевидно, чтобы потерять все сразу. Вопрос не лишен смысла, это известная проблема — проблема нулевого секрета (Secret Zero), когда у вас существует секрет, который защищает другие секреты, и который сам при этом не защищен. И если его потерять, то секреты тоже будут потеряны. В чём тогда смысл? Действительно, полностью эту проблему решить нельзя, но секреты всё равно защитить можно, и для этого необходимо использовать системы управления секретами, так как они имеют функции, которые помогают частично решить эту проблему. Почему, собственно, Vault? Что есть кроме Vault? Ближайшие аналоги — это CyberArk Conjur, Senhasegura DSM. Важно отметить, что ни одна из Enterprise-версий нижеописанных решений не доступна в России. Поэтому остается полагаться только на Open Source. Но что же о них стоит знать?   Conjur — это существовавший когда-то сам по себе продукт по управлению секретами, который был куплен компанией CyberArk. Сейчас является одним из модулей большой PAM-системы. Основные аспекты: CyberArk Conjur есть в Enterprise и Open Source версиях. Open Source версия сильно ограничена по функционалу. Не очень большое комьюнити. Если вы решите использовать CyberArk Conjur для управления секретами, то с трудом найдете инженеров, которые будут его эксплуатировать. Senhasegura DSM — эта аналог CyberArk. Потому что Senhasegura DSM — это тоже часть общей PAM-системы.  Основные аспекты: Senhasegura DSM — модуль PAM-системы Senhasegura PAM Нет Open Source версии Управление секретами является дополнением к Privileged Access Management, приходится делать много лишних действий Киллер-фича — автоматизация. Можно настроить ротацию секретов почти где угодно Логи на португальском Пока еще скромное комьюнити  Недостаток примерно тот же, что и у Conjur — это решение не сильно популярно, и пока о нем знает довольно узкий круг специалистов.  А что есть у Vault?   Vault — самое знаменитое решение по управлению секретами Версия для открытого использования не сильно уступает в функционале ее платному аналогу Очень подробная и информативная документация Ответы на большинство вопросов можно найти на Stackoverflow или GitHub Большое комьюнити Так как продукт популярен, поиск администраторов, которые будут его эксплуатировать, не составляет труда. Поэтому де факто Vault — лидер рынка. Поговорим о его базовых концептах.  Главное преимущество Vault — его прекрасный API-интерфейс. Любое действие с секретами (чтение, запись, аутентификация в Vault, работа с политиками), кроме инициализации (первого старта), — это всё обращения в API. И преимущество состоит в том, что любое взаимодействие с Vault можно автоматизировать. У Vault есть веб-интерфейс, но он вторичен по отношению к API. Например, из веб-интерфейса нельзя выпустить токен к политике. Поэтому API — наше всё. Второй базовый концепт — это Storage Backend. Это место, где Vault хранит секреты в зашифрованном виде. Это хранилище зашифровано мастер-ключом, этот мастер-ключ зашифрован root-ключом, и он тоже зашифрован другими ключами. Само хранилище может представлять собой файл, который расположен на том же хосте, где функционирует Vault или, например, может использоваться удаленная база данных. Главное, что надо знать, — что вот это хранилище зашифровано (и ключи шифрования также последовательно зашифрованы). И как раз с этим связаны понятия Seal и Unseal, о которых мы сейчас поговорим. Seal и Unseal — это запечатывание и распечатывание.  Sealed state — это запечатанное состояние Vault, при котором он имеет физический доступ к зашифрованным данным, но расшифровать их не способен, так как отсутствует доступ к ключу шифрования. При любом рестарте Vault переходит в запечатанное состояние. И чтобы перевести Vault в рабочее (распечатанное) состояние, нужно дать ему Unseal-ключ, который по умолчанию разделяется на части по алгоритму Шамира. Чтобы распечатать Vault, необходимо предоставить ему некоторое количество частей данного Unseal-ключа.  Secret Engine — это место, где хранятся секреты, такие сущности внутри Vault, которые работают с разными типами секретов. Есть простые Engine типа key-value, которые хранят секреты в виде ключ–значение. Есть Engine с типом database, которые могут, например, подключаться к системе управления базы данных, создавать учетную запись, выдавать какому-то пользователю данную УЗ и потом удалять ее после использования (динамический секрет). Также эти Engine с разным функционалом можно дописывать самому через механизм плагинов на языке Go. У HashiCorp на их портале есть классная инструкция с примерами, с листингами о том, как самому написать такой плагин и как подключить его к Vault. Ну и главное, что есть в Vault, — это токен. Он позволяет гарантировать доступ к самой системе управления секретами. Vault поддерживает разные методы аутентификации: можно аутентифицироваться по LDAP, по логопасу, какими-то другими методами. Но все они в конечном итоге просто дают нам доступ к токену. И уже по токену мы получаем доступ к секретам. Это важный концепт, который стоит понимать. Если мы как-то логинимся, то не получаем секрет — мы получаем токен, который нам что-то потом дает. В итоге вся безопасность доставки секретов сводится к безопасной доставке токена. У Vault есть два основных механизма. Первый — это Response-Wrapping. Vault может отдавать wrapping-токен, то есть токен в свернутом виде, непригодном для использования. Чтобы им воспользоваться, необходимо обратиться с ним к API Vault и сделать Unwrap — развертывание. Особенность функции заключается в том, что это единоразовая операция, то есть когда свернутый токен попадает в Vault, и он его развернул, второй раз эту же операцию выполнить уже не получится. Соответственно, если этот свернутый токен где-то по пути был скомпрометирован, то приложение, обращаясь за развертыванием к Vault, получит отказ (в данном случае можно бить тревогу). Второй способ доставить токен — это AppRole. Это аналог аутентификации по логину и паролю, но для приложений. AppRole состоит из Role ID и Secret ID — это, соответственно, логин и пароль. Приложение отправляет в Vault Role ID и Secret ID и в ответ получает токен для доступа к секретам. Благодаря этому мы можем разбить токен пополам: например, очень классно встраивать Vault в Pipeline, чтобы владелец Pipeline помещал в приложение одну половинку секрета, Secret ID или Role ID, а владелец приложения уже «докладывал» вторую часть самостоятельно после выполнения Pipeline. Из-за этого полный доступ к секретам будет только у владельца приложения, но не у владельца Pipeline.  Доставили токен, а что дальше? Как работать с распределением доступа к секретам? Токен всегда выпускается в привязке к политике. Поскольку в Vault всё основное — это API, то политика выглядит следующим образом: Есть какой-то путь внутри API. То есть когда вы создаете новый секрет, то одновременно создаете в API новые пути. К ним в политике прописывается действие, которое с ними можно выполнять. Секреты хранятся в secret/…/myapp, и политика дает доступ по данному пути с определенными возможностями. К этой политике выпускается токен. Когда какое-то приложение обращается по данному пути, предоставляя токен, Vault «смотрит», какая политика соответствует предъявленному токену, и определяет соответствующие доступы. Это готовые библиотеки от вендора для популярных языков программирования, которые содержат в себе методы взаимодействия с Vault: аутентификация по AppRole, получение секрета по выбранному пути, запись секрета и т. п. Этот способ хорош для тех приложений, которые вы разрабатываете для себя, потому что в этом случае вы привязываетесь к Vault как к системе хранения секретов.  Для приложений, которые поставляются «из коробки», в которых мы не можем попасть в исходный код и что-либо там дописать, существует вариант интеграции через Vault-agent. Агенты есть для Linux, для Windows. Отдельно ниже рассмотрим агент для Kubernetes/OpenShift. По сути, агент — это тот же самый сервер Vault, который просто запущен с флагом agent (в режиме клиента). Агенты позволяют получить токен у Vault и безопасно доставить секрет приложению, поместив его в файл или в переменную окружения.  Отдельно рассмотрим агент для Kubernetes/OpenShift — так называемый Kubernetes Injector. Он устанавливается в кластер Kubernetes или в кластер OpenShift и использует механизм Mutating Webhook.  Вендорская схема выглядит так: Если кратко, то всё работает так:  Запускается Admission Controller внутри Kubernetes и прочитывает все манифесты всех подов, которые попадают в кластер.  Если Admission Controller находит в загружаемых манифестах специальные строчки, которые говорят о том, что необходимо использовать Vault для доставки секрета, и секрет находится по определенному пути, то он инжектирует в такие поды init- и sidecar-контейнеры, которые аутентифицируются в Vault, получают секреты и кладут в разделяемую память. Плюс такой интеграции в том, что аутентификация в Vault происходит по пространству имен Kubernetes и Service Account токенами, которые вы отдаете в Vault. Минус в том, что маленькие контейнерные приложения начинают занимать примерно на 100 Мб больше места, потому что к ним в под инжектируется sidecar-контейнер, который является сервером Vault, только в клиентском режиме.  Есть более простой способ инжектировать секрет в под — External Secrets, который интегрируется со многими системами управления секретами.  Это такой оператор для Kubernetes, который создает кастомные ресурсы. Этот кастомный ресурс, содержащий в себе секрет из Vault, записывается как Kubernetes Secret. В свою очередь, последний уже монтируется в pod.   Итого:  Есть Vault, который хранит секреты в зашифрованном Storage Backend. Все секреты разложены по разным Secret Engine. Секрет можно получить через API, аутентифицировавшись в этом API по токену. Для того чтобы безопасно доставить токен, есть механизмы Response Wrapping и AppRole. Подключать приложения можно через SDK, агента для ОС и агента для Kubernetes. Так работает Vault. Теперь немного нашего опыта внедрения Vault. Для внедрения нужен сам Vault и какой-нибудь Backend для хранения секретов. Чтобы установить Vault, необходимо скопировать бинарник на виртуальную машину или поднять контейнер с Vault. Но данная инсталляция не подходит для бизнеса, так как она не отказоустойчива и не удовлетворяет основным его требованиям, поэтому ее стоит дополнить следующими решениями:  Организовать кластер, добавив экземпляров для отказоустойчивости Выполнить интеграции с LDAP или каким-либо SSO для удобной аутентификации Подключить хранилище секретов и конфигурацию Vault к периодическому бэкапированию Выполнить интеграцию с приложениями и CI/CD для доставки секретов Подключить систему мониторинга, чтобы не допустить аварии Начать отслеживать события безопасности Чтобы ничего не упустить, предлагаю следующий краткий чек-лист внедрения Vault — за чем надо следить, что, по нашему мнению, важно при внедрении Vault. Разницы почти никакой нет, потому что те преимущества, которые нам дает контейнеризация, например, динамический скейлинг в зависимости от нагрузки, никакого прироста производительности не дают: Vault работает по схеме Leader / Follower. У нас есть один Leader, который обрабатывает все данные, и Follower, которые ожидают отказа Leader. При такой схеме возрастает только отказоустойчивость. В жизни отказоустойчивость реализуется так: обычно перед кластером Vault ставится какой-нибудь компонент, отвечающий за высокую доступность, с активными Health Checks, который «пинает» по очереди все ноды Vault, определяет по их http-ответам, кто из них является Leader, и засылает туда весь трафик. Если трафик случайно попадает на ноду, которая является Follower, он тоже не потеряется — Follower переадресует его на Leader, и там он будет обработан. Поэтому почти нет разницы, размещать Vault в VM или в контейнере — можно делать так, как удобнее.  Как выбрать, где хранить секреты?  Классика — это Consul. Данный продукт также создан компанией HashiCorp и является официально поддерживаемым Storage Backend’ом. Его преимущество заключается в том, что бэкапирование и восстановление выполняется буквально в одну команду. Кроме того, Consul среди других Storage Backend показывает наилучшие результаты по чтению секретов.  Также самое простое в деплое решение, которое появилось не так давно — Integrated Storage. Это хранение данных прямо на той ноде, где находится Vault, в виде файла. Классно здесь то, что если вы собираете кластер из таких узлов с Vault, которые используют Integrated Storage в виде Storage Backend, то они реализуют Raft-алгоритм, поэтому данные консистентно записываются на все узлы Vault, тем самым обеспечивая целостность. Кроме этого, поддерживаются внешние базы данных, SQL-базы и базы типа key-value. Если у вас есть подразделения, которые оказывают услуги типа Database as a Service, то это отличный выбор для вас. Важно знать, что Vault кэширует несколько тысяч последних чтений, и при повторном обращении не будет создаваться сетевой нагрузки или нагрузки на диски. Парадоксально, но при нагрузочном тестировании был выявлен один факт — Integrated Storage оказался медленнее, чем PostgreSQL. Незначительно, но всё же: 21 тысячу ответов в секунду при пиковой нагрузке нам дал Integrated Storage с HTTPS, и 24,8 тысяч смог сделать PostgreSQL.  Бэкапирование зависит от выбранного Storage Backend. Если у вас интегрированный Storage, то Backup и восстановление делается через консоль Vault, само по себе. А если хранение секретов организовано в каком-то внешнем сервисе СУБД, то резервное копирование можно отдать на откуп ребятам, администрирующим ваши СУБД. В API Vault есть раздел /metrics , который отвечает за выдачу метрик. Prometheus может понимать эти данные и снимать их. Для их визуализации можно воспользоваться готовыми дашбордами Grafana. События записываются либо в файл в формате JSON, либо в сокет, а могут транслироваться в формате SYSLOG в /var/log/messages. В последнем случае Vault необходимы дополнительные утилиты для их отправки в SIEM, такие как RSYSLOG или SYSLOG-NG. Рекомендуем RSYSLOG, потому что в случае с SYSLOG-NG мы однажды столкнулись с невозможностью отправить слишком длинное сообщение, а в RSYSLOG можно настроить предельный размер сообщения.   Для распечатывания Vault рекомендуем использовать механизм Auto Unseal.  Что такое Auto Unseal? Вы поднимаете один транзитный узел с Vault (он так называется, поскольку внутри используется Secret Engine — transit). В данном Vault хранится ключ для распечатывания узлов основного кластера. В случае рестарта какого-либо узла из основного кластера, где, собственно, хранятся секреты, данный узел обращается к транзитной ноде. Там он получает ключ от всех дверей других ключей, который в итоге ему расшифрует хранилище. Это общепринятый способ. Важно выполнять бэкапирование ключа, который распечатывает основные узлы, так как в случае потери транзитной ноды будет потерян ключ для распечатывания, а следовательно, доступ до секретов основного кластера Vault.  Так как основной кластер Vault авторизуется в транзитной ноде и получает себе ключ для распечатывания с помощью токена, а данный токен имеет свое время жизни, то необходимо его продлевать. Для этого токен для получения Unseal-ключа должен быть создан с флагами -orphan и -periodic. Поясним, что это значит. Флаг Periodic нужен для того, чтобы токен продлевался на свой срок жизни при каждом использовании в Vault. То есть основной кластер сходил к транзиту, авторизовался по данному токену и получил ключ, тогда срок его жизни сразу обновится. Orphan — это понятие связано с тем, что в Vault все токены наследуются, и если вы под какой-то учетной записью выпустили токен, то он будет зависеть от токена той учетной записи, от которой вы его выпустили. Если, допустим, токену владельца осталось жить три дня, а вот выпускаемому им токену вы задали время жизни месяц, то он проживет три дня. Orphan означает то, что он сирота, у него нет родительского токена, и он будет жить столько, сколько вы указали при его создании.  Ну и грабли, на которые точно не стоит наступать — не делайте взаимно распечатываемые кластеры, потому что запросто получите взаимозапечатываемые кластеры. Еще немного про встраивание в Pipeline. На сайте вендора есть рекомендуемый паттерн использования AppRole в CI/CD.  И это не очень круто, так как секреты приложения раскрываются владельцу Pipeline. Что можно предпринять в таком случае? Отдать админу CI/CD, например, только Secret ID. Он встраивает данную часть AppRole в собираемое приложение. А Role ID — вторую часть AppRole — отдать владельцу приложения. Таким образом, только у владельца приложения будет полный доступ к Role ID и Secret ID, которые он подставит при деплое приложения. Также есть полезное решение, связанное с потерей данных для аутентификации в Vault при рестарте приложения или сервера. Если у вас Role ID и Secret ID хранятся в переменных окружения, то при рестарте хоста они будут затерты, и приложение не сможет получить нужный ему секрет. Одна из возможных схем решения — это создать еще одну AppRole, которая будет просто запрашивать креды для исходной AppRole. Она позволит разметить новые аутентификационные данные для входа, но сама прочитать секрет не сможет. Кроме того, есть полезное решение, связанное с агентом Vault для Windows. Агент для Windows сделан по образу и подобию агента Vault для Linux. Настолько по образу и подобию, что его можно размещать и запускать только на диске C, так как все пути в конфигурационном файле пишутся в линуксовом формате ( /path/to/file), и агенту требуется всегда знать абсолютный путь. Поэтому требуется сразу размещать агент на диске C. Также существует проблема, что агент Vault на Windows не может писать логи в файл. Он может выводить логи в stdout, если вы интерактивно запускаете его в командной строке. А если запускаете его как службу Windows, то записать логи Vault в файл никак не получится. Для решения проблемы нашлась классная утилита NSSM — альтернативный способ создать виндовую службу. NSSM запускается вместе со службой, и там же можно прописать ряд настроек.  Здесь есть скриншот: пишем настройку, возможно перенаправлять stdout и stderr, и Vault сможет записывать свои логи в файл. Напоследок расскажем про работу с политиками. Не все знают — политики можно писать не только в рекомендуемом вендором hcl-формате, но и в JSON. Очень удобно использовать для этого систему контроля версий, чтобы отслеживать, кто изменял политику, принимать различные изменения и прочее. Также существуют шаблоны и спецсимволы для того, чтобы параметризировать политики, применять на большее количество команд разработки без какого-то точного подгона. Подробнее это можно прочитать на портале вендора (https://developer.hashicorp.com/vault/tutorials/recommended-patterns/pattern-policy-templates). В Vault есть вещи, которые хотелось бы улучшить. Однако есть надежда на то, что когда-то всё это будет исправлено, потому что продукт развивается семимильными шагами.  Очень не хватает более функционального веб-интерфейса. API — наше всё, но из GUI нельзя даже токен к политике выпустить, не говоря о том, чтобы создать новую роль для AppRole.  Отсутствие некоторых возможностей. Всё еще есть проблема с отзывом доступа у AppRole. Если мы скомпрометировали какой-то токен, то у нас нет никакого механизма в Vault, который показывает, к какой AppRole относится выданный токен. Можно всё зарубить на корню, чтобы все заново переаутентифицировались, а вот отзывать доступы точечно не получается.  Отсутствие универсальных механизмов для Secret Engine. Секреты привязаны к своим Engine. Соответственно, мы можем или написать свой Engine, или ограничиваться существующими возможностями. Если у нас секрет лежит в key-value первой или второй версии, невозможно ротировать его без сторонних средств.  Vault — это, бесспорно, лидер среди систем управления секретами. Он устроен не очень просто, но разобраться с ним можно благодаря хорошей документации вендора и широчайшему комьюнити. Vault может выдавать хорошие результаты при невысоких требованиях к железу. Он не лишен недостатков, но развивается и улучшается. Поэтому для построения процесса управления секретами он будет отличным выбором. Никита Михайлов, инженер по информационной безопасности  «Инфосистемы Джет»   Павел Яньков, эксперт «Инфосистемы Джет»