Оффтоп

Наш рассказ — это гид автостопщика, некое 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

Поговорим о его базовых концептах. 

Everything is API

Главное преимущество Vault — его прекрасный API-интерфейс. Любое действие с секретами (чтение, запись, аутентификация в Vault, работа с политиками), кроме инициализации (первого старта), — это всё обращения в API. И преимущество состоит в том, что любое взаимодействие с Vault можно автоматизировать. У Vault есть веб-интерфейс, но он вторичен по отношению к API. Например, из веб-интерфейса нельзя выпустить токен к политике. Поэтому API — наше всё.

Storage Backend

Второй базовый концепт — это Storage Backend. Это место, где Vault хранит секреты в зашифрованном виде. Это хранилище зашифровано мастер-ключом, этот мастер-ключ зашифрован root-ключом, и он тоже зашифрован другими ключами. Само хранилище может представлять собой файл, который расположен на том же хосте, где функционирует Vault или, например, может использоваться удаленная база данных. Главное, что надо знать, — что вот это хранилище зашифровано (и ключи шифрования также последовательно зашифрованы). И как раз с этим связаны понятия Seal и Unseal, о которых мы сейчас поговорим.

Seal/Unseal

Seal и Unseal — это запечатывание и распечатывание. 

Sealed state — это запечатанное состояние Vault, при котором он имеет физический доступ к зашифрованным данным, но расшифровать их не способен, так как отсутствует доступ к ключу шифрования. При любом рестарте Vault переходит в запечатанное состояние. И чтобы перевести Vault в рабочее (распечатанное) состояние, нужно дать ему Unseal-ключ, который по умолчанию разделяется на части по алгоритму Шамира. Чтобы распечатать Vault, необходимо предоставить ему некоторое количество частей данного Unseal-ключа. 

Secret Engine

Secret Engine — это место, где хранятся секреты, такие сущности внутри Vault, которые работают с разными типами секретов. Есть простые Engine типа key-value, которые хранят секреты в виде ключ–значение. Есть Engine с типом database, которые могут, например, подключаться к системе управления базы данных, создавать учетную запись, выдавать какому-то пользователю данную УЗ и потом удалять ее после использования (динамический секрет). Также эти Engine с разным функционалом можно дописывать самому через механизм плагинов на языке Go. У HashiCorp на их портале есть классная инструкция с примерами, с листингами о том, как самому написать такой плагин и как подключить его к Vault.

All about token

Ну и главное, что есть в Vault, — это токен. Он позволяет гарантировать доступ к самой системе управления секретами. Vault поддерживает разные методы аутентификации: можно аутентифицироваться по LDAP, по логопасу, какими-то другими методами. Но все они в конечном итоге просто дают нам доступ к токену. И уже по токену мы получаем доступ к секретам. Это важный концепт, который стоит понимать. Если мы как-то логинимся, то не получаем секрет — мы получаем токен, который нам что-то потом дает.

https://www.meme-arsenal.com/memes/1a595cd6ebb879c92b77fa05456e2606.jpg
https://www.meme-arsenal.com/memes/1a595cd6ebb879c92b77fa05456e2606.jpg

В итоге вся безопасность доставки секретов сводится к безопасной доставке токена. У Vault есть два основных механизма.

Первый — это Response-Wrapping. Vault может отдавать wrapping-токен, то есть токен в свернутом виде, непригодном для использования. Чтобы им воспользоваться, необходимо обратиться с ним к API Vault и сделать Unwrap — развертывание. Особенность функции заключается в том, что это единоразовая операция, то есть когда свернутый токен попадает в Vault, и он его развернул, второй раз эту же операцию выполнить уже не получится. Соответственно, если этот свернутый токен где-то по пути был скомпрометирован, то приложение, обращаясь за развертыванием к Vault, получит отказ (в данном случае можно бить тревогу).

Cubbyhole Response Wrapping | Vault | HashiCorp Developer
Источник Cubbyhole Response Wrapping | Vault | HashiCorp Developer

Второй способ доставить токен — это AppRole. Это аналог аутентификации по логину и паролю, но для приложений. AppRole состоит из Role ID и Secret ID — это, соответственно, логин и пароль. Приложение отправляет в Vault Role ID и Secret ID и в ответ получает токен для доступа к секретам. Благодаря этому мы можем разбить токен пополам: например, очень классно встраивать Vault в Pipeline, чтобы владелец Pipeline помещал в приложение одну половинку секрета, Secret ID или Role ID, а владелец приложения уже «докладывал» вторую часть самостоятельно после выполнения Pipeline. Из-за этого полный доступ к секретам будет только у владельца приложения, но не у владельца Pipeline. 

AppRole auth method workflow
Источник AppRole auth method workflow

Доставили токен, а что дальше? Как работать с распределением доступа к секретам?

Политики доступа

Токен всегда выпускается в привязке к политике. Поскольку в Vault всё основное — это API, то политика выглядит следующим образом:

Источник

Есть какой-то путь внутри API. То есть когда вы создаете новый секрет, то одновременно создаете в API новые пути. К ним в политике прописывается действие, которое с ними можно выполнять. Секреты хранятся в secret/…/myapp, и политика дает доступ по данному пути с определенными возможностями. К этой политике выпускается токен. Когда какое-то приложение обращается по данному пути, предоставляя токен, Vault «смотрит», какая политика соответствует предъявленному токену, и определяет соответствующие доступы.

Способы интеграции с приложениями

Vault SDK

Источник

Это готовые библиотеки от вендора для популярных языков программирования, которые содержат в себе методы взаимодействия с Vault: аутентификация по AppRole, получение секрета по выбранному пути, запись секрета и т. п. Этот способ хорош для тех приложений, которые вы разрабатываете для себя, потому что в этом случае вы привязываетесь к Vault как к системе хранения секретов. 

Vault Agent

Для приложений, которые поставляются «из коробки», в которых мы не можем попасть в исходный код и что-либо там дописать, существует вариант интеграции через Vault-agent. Агенты есть для Linux, для Windows. Отдельно ниже рассмотрим агент для Kubernetes/OpenShift.

По сути, агент — это ��от же самый сервер Vault, который просто запущен с флагом agent (в режиме клиента).

Источник

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

Агент для Kubernetes/OpenShift

Отдельно рассмотрим агент для Kubernetes/OpenShift — так называемый Kubernetes Injector. Он устанавливается в кластер Kubernetes или в кластер OpenShift и использует механизм Mutating Webhook. 

Вендорская схема выглядит так:

Kubernetes

Если кратко, то всё работает так: 

  1. Запускается Admission Controller внутри Kubernetes и прочитывает все манифесты всех подов, которые попадают в кластер. 

  2. Если Admission Controller находит в загружаемых манифестах специальные строчки, которые говорят о том, что необходимо использовать Vault для доставки секрета, и секрет находится по определенному пути, то он инжектирует в такие поды init- и sidecar-контейнеры, которые аутентифицируются в Vault, получают секреты и кладут в разделяемую память. Плюс такой интеграции в том, что аутентификация в Vault происходит по пространству имен Kubernetes и Service Account токенами, которые вы отдаете в Vault. Минус в том, что маленькие контейнерные приложения начинают занимать примерно на 100 Мб больше места, потому что к ��им в под инжектируется sidecar-контейнер, который является сервером Vault, только в клиентском режиме. 

Есть более простой способ инжектировать секрет в под — External Secrets, который интегрируется со многими системами управления секретами.

HashiCorp Vault - External Secrets Operator
Источник HashiCorp Vault - External Secrets Operator

Это такой оператор для Kubernetes, который создает кастомные ресурсы. Этот кастомный ресурс, содержащий в себе секрет из Vault, записывается как Kubernetes Secret. В свою очередь, последний уже монтируется в pod.  

Итого: 

Есть Vault, который хранит секреты в зашифрованном Storage Backend. Все секреты разложены по разным Secret Engine. Секрет можно получить через API, аутентифицировавшись в этом API по токену. Для того чтобы безопасно доставить токен, есть механизмы Response Wrapping и AppRole. Подключать приложения можно через SDK, агента для ОС и агента для Kubernetes. Так работает Vault.

Внедрение Vault

Теперь немного нашего опыта внедрения Vault. Для внедрения нужен сам Vault и какой-нибудь Backend для хранения секретов. Чтобы установить Vault, необходимо скопировать бинарник на виртуальную машину или поднять контейнер с Vault. Но данная инсталляция не подходит для бизнеса, так как она не отказоустойчива и не удовлетворяет основным его требованиям, поэтому ее стоит дополнить следующими решениями: 

  1. Организовать кластер, добавив экземпляров для отказоустойчивости

  2. Выполнить интеграции с LDAP или каким-либо SSO для удобной аутентификации

  3. Подключить хранилище секретов и конфигурацию Vault к периодическому бэкапированию

  4. Выполнить интеграцию с приложениями и CI/CD для доставки секретов

  5. Подключить систему мониторинга, чтобы не допустить аварии

  6. Начать отслеживать события безопасности

Чтобы ничего не упустить, предлагаю следующий краткий чек-лист внедрения Vault — за чем надо следить, что, по нашему мнению, важно при внедрении Vault.

VM или контейнер

Разницы почти никакой нет, потому что те преимущества, которые нам дает контейнеризация, например, динамический скейлинг в зависимости от нагрузки, никакого прироста производительности не дают: Vault работает по схеме Leader / Follower. У нас есть один Leader, который обрабатывает все данные, и Follower, которые ожидают отказа Leader. При такой схеме возрастает только отказоустойчивость.

Источник

В жизни отказоустойчивость реализуется так: обычно перед кластером Vault ставится какой-нибудь компонент, отвечающий за высокую доступность, с активными Health Checks, который «пинает» по очереди все ноды Vault, определяет по их http-ответам, кто из них является Leader, и засылает туда весь трафик. Если трафик случайно попадает на ноду, которая является Follower, он тоже не потеряется — Follower переадресует его на Leader, и там он будет обработан. Поэтому почти нет разницы, размещать Vault в VM или в контейнере — можно делать так, как удобнее. 

Storage Backend

Как выбрать, где хранить секреты? 

Классика — это 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. 

Немного очевидных фактов про Backup и восстановление

Бэкапирование зависит от выбранного Storage Backend. Если у вас интегрированный Storage, то Backup и восстановление делается через консоль Vault, само по себе. А если хранение секретов организовано в каком-то внешнем сервисе СУБД, то резервное копирование можно отдать на откуп ребятам, администрирующим ваши СУБД.

Мониторинг Vault

В API Vault есть раздел /metrics , который отвечает за выдачу метрик. Prometheus может понимать эти данные и снимать их. Для их визуализации можно воспользоваться готовыми дашбордами Grafana.

События безопасности

События записываются либо в файл в формате JSON, либо в сокет, а могут транслироваться в формате SYSLOG в /var/log/messages. В последнем случае Vault необходимы дополнительные утилиты для их отправки в SIEM, такие как RSYSLOG или SYSLOG-NG. Рекомендуем RSYSLOG, потому что в случае с SYSLOG-NG мы однажды столкнулись с невозможностью отправить слишком длинное сообщение, а в RSYSLOG можно настроить предельный размер сообщения.  

TIPS & TRICKS

Для распечатывания Vault рекомендуем использовать механизм Auto Unseal.

Источник

Что такое Auto Unseal? Вы поднимаете один транзитный узел с Vault (он так называется, поскольку внутри используется Secret Engine — transit). В данном Vault хранится ключ для распечатывания узлов основного кластера. В случае рестарта какого-либо узла из основного кластера, где, собственно, хранятся секреты, данный узел обращается к транзитной ноде. Там он получает ключ от всех дверей других ключей, который в итоге ему расшифрует хранилище. Это общепринятый способ. Важно выполнять бэкапирование ключа, который распечатывает основные узлы, так как в случае потери транзитной ноды будет потерян ключ для распечатывания, а следовательно, доступ до секретов основного кластера Vault. 

Источник

Так как основной кластер Vault авторизуется в транзитной ноде и получает себе ключ для распечатывания с помощью токена, а данный токен имеет свое время жизни, то необходимо его продлевать. Для этого токен для получения Unseal-ключа должен быть создан с флагами -orphan и -periodic. Поясним, что это значит. Флаг Periodic нужен для того, чтобы токен продлевался на свой срок жизни при каждом использовании в Vault. То есть основной кластер сходил к транзиту, авторизовался по данному токену и получил ключ, тогда срок его жизни сразу обновится. Orphan — это понятие связано с тем, что в Vault все токены наследуются, и если вы под какой-то учетной записью выпустили токен, то он будет зависеть от токена той учетной записи, от которой вы его выпустили. Если, допустим, токену владельца осталось жить три дня, а вот выпускаемому им токену вы задали время жизни месяц, то он проживет три дня. Orphan означает то, что он сирота, у него нет родительского токена, и он будет жить столько, сколько вы указали при его создании. 

Ну и грабли, на которые точно не стоит наступать — не делайте взаимно распечатываемые кластеры, потому что запросто получите взаимозапечатываемые кластеры.

Еще немного про встраивание в Pipeline. На сайте вендора есть рекомендуемый паттерн использования AppRole в CI/CD. 

AppRole auth method workflow
Источник AppRole auth method workflow

И это не очень круто, так как секреты приложения раскрываются владельцу 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 есть вещи, которые хотелось бы улучшить. Однако есть надежда на то, что когда-то всё это будет исправлено, потому что продукт развивается семимильными шагами. 

  1. Очень не хватает более функционального веб-интерфейса. API — наше всё, но из GUI нельзя даже токен к политике выпустить, не говоря о том, чтобы создать новую роль для AppRole. 

  2. Отсутствие некоторых возможностей. Всё еще есть проблема с отзывом доступа у AppRole. Если мы скомпрометировали какой-то токен, то у нас нет никакого механизма в Vault, который показывает, к какой AppRole относится выданный токен. Можно всё зарубить на корню, чтобы все заново переаутентифицировались, а вот отзывать доступы точечно не получается. 

  3. Отсутствие универсальных механизмов для Secret Engine. Секреты привязаны к своим Engine. Соответственно, мы можем или написать свой Engine, или ограничиваться существующими возможностями. Если у нас секрет лежит в key-value первой или второй версии, невозможно ротировать его без сторонних средств. 

Итоги

Vault — это, бесспорно, лидер среди систем управления секретами. Он устроен не очень просто, но разобраться с ним можно благод��ря хорошей документации вендора и широчайшему комьюнити. Vault может выдавать хорошие результаты при невысоких требованиях к железу. Он не лишен недостатков, но развивается и улучшается. Поэтому для построения процесса управления секретами он будет отличным выбором.

Никита Михайлов, инженер по информационной безопасности «Инфосистемы Джет»

Павел Яньков, эксперт «Инфосистемы Джет»