Когда я устанавливаю Vault в Kubernetes, я держу в голове, что очень важно иметь возможность сделать автоматическое распечатывание(Auto-Unseal), чтобы кластер Vault был по настоящему высокодоступным. В моей предыдущей статье "Highly available Vault cluster in Kubernetes" (ссылка), несмотря на то, что я изо всех сил пытался сделать кластер Vault максимально доступным, без автоматического распечатывания кластер Vault мог бы выдержать частичный отказ подов, но не пережил бы перезагрузку всего кластера. В этой статье хорошо объяснено, почему это произошло. Для меня проблема заключается в том, что я не пользуюсь "службой AWS KMS", которую можно было бы использовать, или подобной службы безопасности от "облачного" провайдера, потому что я управляю Kubernetes на self-hosted "облаке" (в этой статье объясняется моя настройка). В Vault версии 1.1 добавлена поддержка "Transit Auto Unseal", которая заключается в использовании второго Vault кластера B для автоматического распечатывания (Auto-Unseal) кластера А. Итак, вот идея: развернуть 2 кластера Vault A и B и настроить их так, чтобы они делали автоматическое распечатывание друг для друга. Если оба кластера Vault A и B высокодоступны сами по себе, в случае падения/обновления любого пода, новый под может быть автоматически распечатан из другого кластера. Вероятность того, что все поды обоих кластеров упадут в одно и то же время, должна быть очень мала. В этой статье я развернул два кластера Vault в одном Kubernetes, и назвал их "vault" и "vault-unlock", в двух неймспейсах. В реальной продакшн-среде я бы предложил более надежный способ их установки в двух кластерах Kubernetes. Ниже приведена диаграмма. Обновлено 1/9/2020 Первый кластер называется "vault", в папке с исходным кодом "vault".
Этот кластер предназначен для внешнего обслуживания, поэтому у него есть правило Ingress. Следуйте инструкциям, описанным здесь, или аналогичным тем, что описаны ниже. Второй кластер называется "vault-unlock", в папке с исходным кодом "vault2".
Этот кластер предназначен для осуществления автоматического распечатывания(Auto-Unseal). Для его развертывания надо сделать то же, что и для первого кластера, только в пространстве имён "vault-unlock", и без Ingress. Проверьте файлы README.md в исходниках на наличие нижеприведенных команд. Когда всё развернуто, пользовательский интерфейс Consul будет выглядеть так. Пользовательский интерфейс Vault доступен через публичный адрес. Я следую инструкциям из официального документа. "vault” кластер полностью распечатан и работает Скопируйте файл "vault2/config/vault.json” из исходников, назовите его "vault2/config/vault_autounseal.json”, и добавьте конфигурацию "seal". Ниже приведен мой пример, подробности о настройке можно узнать в документе. Заполните токен, полученный на предыдущем шаге. Обновим конфигмап "vault" с содержимым из файла "vault_autounseal.json", но назовем его "vault.json”, чтобы под мог его использовать". Пересоздаем деплоймент vault-unlock. Лог с параметрами для автоматического распечатывания выглядит следующим образом: Теперь кластер "vault-unlock” находится в режиме "seal migration mode”. Делаем миграцию запечатывания (Seal) Миграцию запечатывания необходимо сделать только в одном поде "vault-unlock” кластера. Теперь перезапускаем "vault-unlock” кластер ещё раз. Все поды кластера "vault-unlock” станут автоматически распечатанными. Лог будет выглядеть вот так: Итак, у кластера "vault-unlock” появилась возможность автоматического распечатывания. В основном, это то же самое, что и в первой части. Просто держите в уме, с каким кластером работаете в данный момент… Особенно на этапе "пересоздания" деплоймента, убедитесь, что папка с исходниками верна. Я бы посоветовал создавать резервные копии кластера "Consul" по ходу выполнения шагов. Согласно доке. После того, как оба Vault кластера переключатся в режим автоматического распечатывания, важно помнить, что не следует уничтожать оба деплоймента одновременно. Если хотя бы один под Vault находится в распечатанном режиме, то в конечном итоге все они окажутся распечатанными. Это происходит из-за того, что Configmap vault всё ещё содержит конфиг из файла "config/vault.json”. Обновите его содержимым файла "config/vault_autounseal.json”. Эта проблема долгое время доставляла мне неприятности… даже после того, как я поверил, что правильно настроил все параметры для конфигурации "seal". Легко заставить всё работать, установив "tls_skip_verify" как "true", и в данном случае это может быть нормально, так как здесь оба кластера Vault находятся внутри одного и того же кластера Kubernetes. Однако, в случае двух кластеров Vault в двух разных кластерах Kubernetes, проверка TLS должна быть выполнена. Итак, 2 кластера Vault теперь делают автоматическое распечатывание друг за другом. Цель — получить высокодоступный Vault в качестве сервиса. С точки зрения пользователя, я настраиваю тест, чтобы проверять состояние Vault каждую секунду с помощью statping, как показано ниже. Он проверяет состояние Vault из Интернета на контроллере Ingress от Kubernetes, а затем на кластере Vault. Более подробная информация о настройке приведена в моей статье "Измерение и улучшение высокой доступности кластера Kubernetes во время перезагрузки" (ссылка). Как описано в этой статье, выпуск vault’a объединяет "RollingUpdate”, "livenessProbe”, "readinessProbe”, "lifecycle-preStop”, и "PodDisruptionBudget”. Во время обновления происходит подтверждение, что только один из трех подов был завершен и вновь созданный под должен получить состояние распечатанного для следующего обновления. Во всех обновленях в деплойменте vault’a, которые я проводил за время написания этой статьи, не было обнаружено ни одной ошибки. Во время написания этой статьи, мой облачный провайдер временно отключил одну хост-машину на обслуживание. Для двух серверов, на одном из которых был haproxy, а на другом — мастер-нода с Ingress Controller’ом, падение заняло 20 минут. В этом случае statping зафиксировал 4 ошибки. Чтобы протестировать сценарий перезапуска обслуживания, я использую метод, описанный в этой статье. Я последовательно перезагружаю все ноды кластера Kubernetes, например: Для каждой ноды сначала удалим поды, затем перезагружаем, дожидаемся, пока все вернется на место, и, наконец, "развяжем” ноду. В этом тесте statping зафиксировал около 50 ошибок, по 2-6 за один цикл перезагрузки. У меня ушло очень много времени для поиска решения. Я пытался использовать методы из этой статьи, но данный способ не помог. Обсуждение по ссылке объясняет, почему Vault не создан для нулевого простоя. Когда активная Vault-нода падает, проходит некоторое время, прежде чем резервная перенимает контроль на себя. Поэтому в исходном коде я сделал лучшее, что мог: 6 секунд задержки для vault контейнера, и 6 секунд задержки, а затем вызов "consul leave” для consul-vault-agent. Дайте мне знать, если здесь есть возможность внести улучшения. Что случится, если оба Vault кластера умрут в одно и то же время?
Я сталкивался с таким случаем лишь однажды, когда я случайно уничтожил деплоймент Consul. Несмотря на то, что я смог вернуть Consul обратно без потери данных, оба Vault кластера были недоступны для распечатывания. Обновление: я нашел еще один случай, который также наверняка отключит Vault кластер. Так как Vault зависит от Consul, как от хранилища бэкенда, если Consul кластер упадет, например, если он попадет в такое состояние, что не будет существовать ведущего, Vault кластер перейдет в состояние "Все Запечатано”. Поэтому важно убедиться, что Consul кластер будет высокодоступным. Я обновил consul_statefulset.yml, чтобы добавить livenessProbe. Когда Consul кластер нуждается в плавающем обновлении, я вижу, что у Consul и Vault кластеров все в порядке. Кроме того, если произойдет одновременная перезагрузка серверов с worker-нодами, Vault кластер попадет в состояние dead lock’a. Поэтому такой ситуации стоит избегать. К сожалению, я не смог найти способ для восстановления, когда оба кластера остаются навсегда в состоянии Sealed… Хочу надеяться, что в этом случае Vault может быть распечатанным со всеми ключами восстановления, но не уверен, что это возможно(соответствующий пост по ссылке). Так что в этот раз у меня не было другого выбора, кроме как пересобрать оба Vault кластера. Как восстановиться из dead lock’a, который, вроде бы, происходит редко, но, тем не менее, возможен в теории? Да и происходит он обычно из-за человеческой оплошности. Встает проблема, что оба Vault кластера взаимозависимы для распечатывания. Мы должны сломать эту взаимозависимость, то есть должен быть еще один кластер, остающийся в ручном режиме распечатывания. Моя идея заключается, как показывает диаграмма, в том, чтобы создать кластер Vault с "Ручным распечатыванием” во втором кластере Kubernetes. Этот кластер "Vault” содержит то самое, что и кластер "Vault-Unlock”, но в то же время он находится в режиме "Ручного распечатывания”. Todo: разобраться, как настроить TLS коммуникацию между главным "Vault” кластером Kubernetes и вспомогательным "Vault-Unlock” кластером. На текущий момент TLS верификация пропущена. Обновлено: Оказывается, настроить TLS верификацию очень легко. Так как Kubernetes helper предоставляет Vault сервис через Trafik Ingress по https://vault.backup.example.com, он использует сертификат Let’s Encrypt. Просто закомментируйте две строчки из vault_deployment.yml в "Vault” кластере: Логи: Спустя месяц, я обнаружил, что автоматическое распечатывание не работает. Я получил "403 permission denied”, когда пытался совершить распечатывание между Vault’ами. Это произошло из-за того, что мы рассчитывали на токен с политикой "Автоматического Распечатывания”, чтобы выполнить работу. Помните, в шагах выше: Токен для выполнения автоматического распечатывания истечет после 768 часов, что приблизительно равно 32 дням. Так как мы используем токен в конфигмапе (vault_autounseal.json), становится невозможным удаленно подключиться после истечения срока токена. В "vault_autounseal.json” даже если "disable_renewal” определен как "false”, токен все равно истекает. В моем понимании "renew” не происходит, если токен не был использован в течении всех 32-х дней, например, если за все время автоматическое распечатывание так и не произошло. Чтобы решить эту проблему, должно быть несколько действий: В этой статье я описал мою попытку создания высокодоступного Vault сервиса. Чтобы достичь цели, я установил 2 кластера Vault для взаимного автоматического распечатывания. Один из них обеспечивал Vault сервис для пользователей, а другой был скрыт и выполнял "Unlock” работу. Чтобы избежать Dead Lock’а, который мог произойти в экстренных ситуациях, третий Vault кластер был в роли бэкапа для "Unlock” Vault’a. Все исходники доступны в github. Auto-unseal using Transit Secrets Engine
transit Seal configurations
vault Server configurations
tcp Listener configurations Управляющий партнер / CVO @ Nixys