Vault — это фактически стандарт для хранения секретов в мире ИТ. И не только для хранения секретов. Ещё для управления сертификатами, шифрования as-a-service, подписания SSH-ключей, выдачи индивидуальных доступов для работы с базами данных. При этом Vault отлично интегрируется с внешними IdP — например, Keycloak или LDAP. А также он позволяет аутентифицировать приложения Kubernetes на основе JWT-токенов, а для «обычных» приложений можно использовать AppRole. Да и сам Vault может выступать как Identity Provider, если возникнет такая необходимость. Список его возможностей можно перечислять долго.

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

Ситуация становится ещё интереснее, если бэкенд хранения исходного Vault — PostgreSQL, а перенести данные мы хотим, например, в Raft. С такой проблемой мы столкнулись, когда начали мигрировать данные клиентов из Vault в наш продукт, построенный на основе Vault, — Deckhouse Stronghold.

Сложности миграции данных из Vault

В Stronghold мы используем Integrated Storage (Raft), чтобы эксплуатация сервиса была проще и понятнее. Не нужно думать отдельно про Vault и отдельно про настройку и обслуживание Postgres или Сonsul, потому что Stronghold сам хранит свои данные. С использованием Integrated Storage получается меньше взаимодействий между сервисами, меньше задержки, а инженерам требуется меньше знаний для обслуживания сервиса. Ну а ещё мы запускаем Stronghold в Kubernetes, и использование таких бэкендов хранения, как Postgres или MySQL, в нём доставляет определённые трудности, так как эти базы не являются изначально Cloud Native.

На просторах Open Source существуют утилиты по миграции данных между инстансами Vault, например medusa или vault-cp. В конце концов, можно написать что-то подобное на любом языке программирования: у Vault открытый API, и существует множество библиотек для создания своих решений.

Но у этого подхода есть несколько проблем:

  1. При импорте из Vault данные расшифровываются. Их, конечно, можно сохранить на диск, перешифровав при сохранении (у той же medusa есть такой функционал), но тем не менее.

  2. Для копирования данных вам нужен будет токен, имеющий доступ к секретам.

  3. Такие утилиты поддерживают, как правило, только импорт/экспорт секретов, но часто копировать нужно ещё политики, PKI или ключи Transit.

  4. PKI или ключи Transit могут быть неэкспортируемыми, поэтому их нельзя извлечь, используя API.

Если у нас в исходном Vault и целевом Stronghold бэкендом хранения был бы PostgreSQL, можно было бы перенести его дамп. Если бы в обоих случаях был Integrated Storage, можно было бы перенести снапшот Raft. Но исходные кластеры Vault у разных клиентов могли быть настроены по-разному, поэтому хотелось бы иметь универсальное решение.

Встроенное решение для миграции

Мало кто знает, но у Vault есть опция миграции из одного storage в другой. В документации ей посвящён целый раздел. Однако Google и ChatGPT не в курсе про миграцию между storage backend.

Поисковая выдача Google и ответ ChatGPT

Второй намёк на малоизвестность этой опции — само наличие таких инструментов, как medusa или vault-cp.

Но опция всё же есть. Поэтому всё, что нам нужно для переноса данных из Vault с бэкендом PostgreSQL в Stronghold с бэкендом Integrated Storage — это выполнить миграцию.

Создадим файл migrate.hcl:

storage_source "postgresql" {
  connection_url = "postgres://vault:vaultpassword@postgresql_server_ip/vault"
  ha_enabled = "true"
}
storage_destination "raft" {
  path = "/tmp/vault-data"
}

Выполним команду vault operator migrate -config=migrate.hcl.

Ну или в нашем случае d8 stronghold operator migrate -config=migrate.hcl.

d8 — это консольная (CLI) утилита, закрывающая все потребности администратора платформы при работе с Deckhouse Kubernetes Platform, начиная от kubectl и доступа к registry и заканчивая управлением виртуализацией и API Stronghold.

После этого мы можем записать данные из каталога /tmp/vault-data на внешний накопитель и перенести данные на нём в другой, закрытый, контур. Данные, сохранённые на накопителе, будут зашифрованы.

Вообще говоря, storage_source и storage_destination могут быть любыми. Не важно, Сonsul, MySQL или file. Vault прочитает данные из одного storage backend и сохранит as-is в другом.

Вот пример файла, который поможет перенести данные из Consul в file-storage:

storage_source "consul" {
  address = “counsul-server:8500”
  path = "vault"
}
storage_destination "file" {
  path = "/tmp/vault-data"
}

В нашем случае — при миграции из Vault с бэкендом PostgreSQL в Stronghold с бэкендом Raft — нужно будет поместить данные с флешки в /var/lib/deckhouse/strongdhold и включить модуль Stronghold в кластере Deckhouse Kubernetes Platform. При включении модуля будет создан кластер из трёх узлов Stronghold, в который будут импортированы полученные при миграции данные. 

После этого достаточно распечатать один из узлов кластера — остальные его узлы будут распечатаны автоматически. Это, кстати, ещё одно отличие Stronghold от ванильного Vault: для auto unseal ему не требуется внешний KMS или Transit Vault, узлы кластера самостоятельно распечатывают своих соседей. 

Наличие автораспечатывания значительно помогает в эксплуатации хранилища в среде Kubernetes, где перезапуск подов — это скорее норма, чем проблема. При этом, в отличие от операторов Vault вроде Bank-Vaults, мы не храним ключ распечатки в Kubernetes-секрете или где-либо ещё, кроме памяти процесса Stronghold. Это позволяет повысить безопасность хранилища секретов.

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

Наши клиенты, которым по разным причинам требуется отечественное ПО или сертификат ФСТЭК России и которые ранее пользовались HashiCorp Vault, не подходящим под эти требования, могут абсолютно безопасно перенести свои данные из Vault в Stronghold, в том числе между закрытыми контурами.

P. S. 

Если вы ничего не слышали про Stronghold ранее, то буквально в нескольких фразах:

  • мы пишем свой форк HashiCorp Vault;

  • мы не просто импортозамещаем, а переосмысливаем продукт: добавляем тот функционал, которого, на наш взгляд, не хватает для российского рынка;

  • мы в реестре отечественного ПО с 24 апреля 2024 года.

Подробнее обо всём этом можно послушать в записи вебинара «Мы умеем хранить секреты»

В целом миграция между storage backend Vault незаслуженно обделена вниманием на просторах интернета. Возможно,  эта статья поможет кому-то с ответом на вопрос «Как безопасно перенести данные из Vault в другой Vault?».

Комментарии (2)


  1. Al_Pollitruk
    26.12.2024 08:25

    Дай думаю прочту, как безопасно мигрировать данные из Autodesk Vault в отечественную среду общих данных, но нет.


    1. Shaman_RSHU
      26.12.2024 08:25

      Это нужно примерно 0.001% читателей, в отличие от Hashicorp Vault. Да и что значит "безопасно мигрировать"? Без ошибок или чтобы кто-нибудь не украл? :)