Stronghold совместим с API HashiCorp Vault, поэтому миграция сводится к переносу конфигурации и данных и к переключению клиентов на новый адрес. Шифрованное хранилище Vault нельзя подключить к Stronghold напрямую: данные переносятся через API.
Цель
Перенести в Stronghold секреты KV, политики, методы аутентификации, PKI и динамические секреты из работающего HashiCorp Vault, переключить клиентов и сохранить возможность отката.
Предварительные требования
Для выполнения примера нужны:
- Развёрнутый и распечатанный кластер Stronghold.
- Токен HashiCorp Vault с правами
readиlistна переносимые пути, а также наsys/mounts,sys/authиsys/policies/acl. - Токен Stronghold с административными правами.
- Сетевая связанность между Stronghold и Vault, если используется KV-репликация.
- Утилиты
vault,d8иjqна рабочей станции.
В примерах ниже адреса и токены задаются переменными окружения:
export VAULT_ADDR=https://vault.example.com:8200
export VAULT_TOKEN=<VAULT_TOKEN>
export STRONGHOLD_ADDR=https://stronghold.example.com
export STRONGHOLD_TOKEN=<STRONGHOLD_TOKEN>Где:
<VAULT_TOKEN>— токен HashiCorp Vault с правами на чтение переносимых данных;<STRONGHOLD_TOKEN>— токен Stronghold с административными правами.
Утилита vault использует только переменные VAULT_* и отправляет запросы в HashiCorp Vault. Утилита d8 stronghold копирует переменные STRONGHOLD_* в VAULT_*, поэтому STRONGHOLD_ADDR и STRONGHOLD_TOKEN переопределяют VAULT_ADDR и VAULT_TOKEN, и команды d8 stronghold отправляются в Stronghold. Задайте и STRONGHOLD_ADDR, и STRONGHOLD_TOKEN: иначе d8 stronghold отправит в Stronghold токен Vault или в Vault — токен Stronghold.
Шаг 1. Проведите инвентаризацию
Составьте перечень объектов, которые нужно перенести. Выполните команды на стороне Vault:
vault secrets list -detailed -format=json > vault-mounts.json
vault auth list -detailed -format=json > vault-auth.json
vault policy list -format=json > vault-policies.json
vault namespace list -format=json > vault-namespaces.jsonКоманда vault namespace list доступна только в Vault Enterprise. Если в Vault используются пространства имён, повторите инвентаризацию для каждого из них с параметром -namespace.
Для каждого mount зафиксируйте тип (kv версии 1 или 2, pki, database, transit и другие), путь и параметры (default_lease_ttl, max_lease_ttl). Для каждого метода аутентификации — тип, путь, роли и привязанные политики.
Пространства имён поддерживаются только в Stronghold EE. Если в Vault используются пространства имён, а целевая инсталляция — базовый Stronghold, перенесите содержимое каждого пространства имён в отдельные пути монтирования.
Шаг 2. Воссоздайте пространства имён и механизмы секретов
Воссоздайте в Stronghold пространства имён и механизмы секретов Vault:
Если нужны пространства имён (Stronghold EE), создайте их:
d8 stronghold namespace create team-aВключите механизмы секретов по тем же путям, что и в Vault. Например, для KV версии 2:
d8 stronghold secrets enable -path=secret -version=2 kvСохраняйте прежние пути монтирования: тогда политики и клиентский код не придётся менять.
Шаг 3. Перенесите секреты KV
Выберите одну из стратегий.
Стратегия A. Копирование скриптом
Подходит для базового Stronghold и для разового переноса. Скрипт обходит дерево секретов в Vault и записывает последнюю версию каждого секрета в Stronghold. История версий KV2 не переносится.
#!/usr/bin/env bash
set -euo pipefail
SRC_MOUNT=secret
DST_MOUNT=secret
copy_tree() {
local path="$1"
for key in $(vault kv list -mount="$SRC_MOUNT" -format=json "$path" | jq -r '.[]'); do
if [[ "$key" == */ ]]; then
copy_tree "${path}${key}"
else
vault kv get -mount="$SRC_MOUNT" -format=json "${path}${key}" | jq '.data.data' > /tmp/secret.json
d8 stronghold kv put -mount="$DST_MOUNT" "${path}${key}" @/tmp/secret.json
echo "copied ${path}${key}"
fi
done
rm -f /tmp/secret.json
}
copy_tree ""Для KV версии 1 используйте поле .data вместо .data.data. Перед запуском убедитесь, что временный файл создаётся в директории, доступной только вам, либо замените его на передачу через стандартный ввод.
Стратегия B. KV-репликация из внешнего Vault
Используйте эту стратегию, чтобы данные оставались синхронизированными во время переключения клиентов.
KV-репликация доступна только в Stronghold EE.
Репликация KV1/KV2 работает по pull-модели: Stronghold периодически забирает секреты из источника через API. Источником может быть Vault CE, Vault Enterprise или другое хранилище с совместимым API KV/KV2. Такой вариант позволяет держать данные синхронизированными на всё время переключения клиентов.
На стороне Vault создайте политику и токен для чтения исходного хранилища:
vault policy write replicate-secret - <<'POLICY' path "secret/*" { capabilities = ["read", "list"] } path "sys/mounts/secret" { capabilities = ["read"] } path "auth/token/lookup-self" { capabilities = ["read"] } path "auth/token/renew-self" { capabilities = ["update"] } POLICY vault token create -policy=replicate-secret -orphan=true -period=30d -wrap-ttl=5m -field=wrapping_tokenКоманда выводит токен обёртывания. Используйте его как
<WRAPPING_TOKEN>на следующем шаге.В Stronghold смонтируйте реплицируемое хранилище:
d8 stronghold secrets enable -path=secret -src-address="$VAULT_ADDR" -src-wrapping-token=<WRAPPING_TOKEN> -src-mount-path=secret -src-ca-cert=@vault-ca.pem -sync-period-min=5 -version=2 kvПараметр
-src-addressполучает адрес HashiCorp Vault из переменнойVAULT_ADDR. Версии KV в источнике и в Stronghold должны совпадать.Проверьте параметры репликации:
d8 stronghold read sys/mounts/secret/tune
Пока репликация включена, хранилище в Stronghold работает только на чтение. После переключения клиентов отключите репликацию, чтобы разрешить запись:
d8 stronghold secrets tune -sync-enable=false secretНе включайте репликацию повторно после отключения: все локальные изменения будут перезаписаны данными из источника.
Шаг 4. Перенесите политики
Синтаксис ACL-политик совместим, поэтому политики переносятся без изменений:
for p in $(vault policy list | grep -v -E '^(root|default)$'); do
vault policy read "$p" > "policy-$p.hcl"
d8 stronghold policy write "$p" "policy-$p.hcl"
doneПроверьте политики, которые ссылаются на accessor методов аутентификации (шаблоны {{identity.entity.aliases.<MOUNT_ACCESSOR>...}}). После воссоздания методов аутентификации accessor изменится: замените его в политиках на новое значение. Подробнее — в разделе «Шаблонные политики».
Шаг 5. Воссоздайте методы аутентификации
Конфигурацию методов аутентификации и их роли перенесите вручную или через IaC-инструмент: секретные параметры (например, client_secret OIDC, bindpass LDAP) Vault не возвращает при чтении.
Включите методы по прежним путям:
d8 stronghold auth enable -path=oidc oidc d8 stronghold auth enable -path=kubernetes kubernetes d8 stronghold auth enable -path=approle approleПрочитайте несекретные параметры ролей в Vault и запишите их в Stronghold:
vault read -format=json auth/approle/role/my-app | jq '.data' > role-my-app.json d8 stronghold write auth/approle/role/my-app @role-my-app.jsonДля AppRole выпустите новые
secret_id: существующие значения из Vault перенести нельзя.role_idможно задать явно, записав его вauth/approle/role/<ROLE_NAME>/role-id, чтобы не менять конфигурацию клиентов.Для OIDC добавьте в список разрешённых redirect URI у провайдера идентификации адрес Stronghold.
Настройка методов описана в разделах OIDC, Kubernetes, AppRole, LDAP.
Шаг 6. Перенесите PKI
Выберите вариант в зависимости от того, насколько важна непрерывность цепочки доверия.
Перевыпуск. Создайте в Stronghold новый промежуточный CA, подпишите его существующим корневым CA и выпускайте новые сертификаты из Stronghold. Старые сертификаты продолжают действовать до истечения срока. При этом варианте закрытый ключ CA не покидает Vault. Процедура описана в руководстве «Внутренний PKI».
Импорт CA. Если ключ CA экспортируемый (сгенерирован как
exportedили хранится вне Vault), импортируйте пакет «сертификат + ключ» в Stronghold:d8 stronghold secrets enable -path=pki pki d8 stronghold write pki/issuers/import/bundle pem_bundle=@ca-bundle.pemЗатем воссоздайте роли (
pki/roles/<ROLE_NAME>) и параметрыpki/config/urls. Если адреса CRL и OCSP в выпущенных сертификатах указывают на Vault, сохраните доступность старых адресов до истечения этих сертификатов.
Шаг 7. Перенастройте динамические секреты
Динамические учётные данные (database, ldap, kubernetes) не переносятся: они привязаны к арендам исходного кластера.
Воссоздайте конфигурацию подключений и роли в Stronghold. Для базы данных используйте отдельную служебную учётную запись, а не ту, что использует Vault, иначе ротация root-пароля в одной системе сломает другую.
Выполните
rotate-rootдля новой учётной записи, чтобы её пароль знал только Stronghold:d8 stronghold write -force database/rotate-root/my-databaseПосле переключения клиентов отзовите аренды в Vault:
vault lease revoke -prefix database/creds/.
Шаг 8. Переключите клиентов
Большинство клиентов Vault (CLI, SDK, Vault Agent, External Secrets Operator, Terraform-провайдер) определяют адрес сервера по переменной VAULT_ADDR или по параметру конфигурации. В окружении клиента укажите адрес Stronghold:
export VAULT_ADDR=https://stronghold.example.comНе меняйте VAULT_ADDR в оболочке, в которой выполняете команды миграции: команды vault из этого руководства, например отзыв аренд на шаге 7, должны по-прежнему отправляться в HashiCorp Vault. Для утилиты d8 stronghold используйте переменную STRONGHOLD_ADDR.
Переключайте клиентов поэтапно: сначала тестовые окружения, затем некритичные сервисы, затем остальные. Для сервисов с DNS-именем Vault можно переключить CNAME на Stronghold, если сертификат Stronghold содержит это имя в SAN.
Проверка
Проверьте результат:
Сравните количество секретов в Vault и Stronghold для каждого KV-хранилища.
Прочитайте несколько секретов через клиента приложения и через CLI:
d8 stronghold kv get -mount=secret myapp/configВыполните вход каждым перенесённым методом аутентификации и проверьте набор политик в выданном токене:
d8 stronghold token lookup.Выпустите тестовый сертификат и динамические учётные данные базы данных.
Убедитесь по журналам Vault, что к нему больше не обращаются рабочие клиенты.
План отката
Держите Vault в рабочем состоянии, пока не завершится период наблюдения (обычно одна–две недели).
- При стратегии A не удаляйте данные в Vault. Если после переключения секреты менялись в Stronghold, перед откатом перенесите изменения обратно тем же скриптом, поменяв местами источник и приёмник.
- При стратегии B, пока репликация включена, Vault остаётся источником, а клиенты возвращаются на прежний адрес без переноса данных.
- Верните
VAULT_ADDRклиентов или DNS-запись на Vault. - Динамические учётные данные, выданные Stronghold, отзовите:
d8 stronghold lease revoke -prefix database/creds/.
Очистка
После завершения периода наблюдения:
- Отключите KV-репликацию (
-sync-enable=false) и отзовите токен репликации в Vault. - Удалите временные файлы с политиками и ролями (
policy-*.hcl,role-*.json). - Выведите Vault из эксплуатации в соответствии с регламентом организации: сделайте финальный снимок, отзовите токены и аренды, остановите серверы.