Skip to content

Интеграция с Vault

В этой главе рассматривается интеграция Apiary с Hashicorp Vault. В частности:

  • каким образом можно настроить хранение секретов в Vault;
  • алгоритм переноса существующих секретов в Vault;
  • особенности реализации интеграции с Vault.

Общая конфигурация интеграции с Vault

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

Имя свойства Назначение и комментарии
vault.address Адрес vault сервера. Обязательное поле.
vault.role_id.value Значение role_id. Обязательное поле.
vault.secret_id.wrapped.file_path Путь к файлу с запакованным (wrapped) секретом. Обязательное поле, если секрет не распаковывается (unwrapping) автоматически сторонним способом.
vault.secret_id.unwrapped.file_path Путь к файлу с распакованным (unwrapped) секретом. Обязательное поле.
vault.secret_id.unwrap.engine_type Тип движка Vault.
Возможные значения - kv-v1, kv-v2, approle. Дефолтное значение - kv-v2.
Обязательное поле, если используется запакованный (wrapped) секрет.
vault.secret_id.unwrap.field Наименование поля для хранения распакованного (unwrapped) секрета.
Обязательное поле, если используются kv-v1 и kv-v2.
Для approle дефолтное значение - secret_id.
vault.secret_id.unwrap.cacert Путь к файлу CA сертификата для доступа к vault серверу по https.
Если путь не задан, то используются корневые сертификаты ОС.
vault.secret_id.unwrap.capath Путь к директории с CA сертификатами для доступа к vault серверу по https. Если путь не задан, то используются корневые сертификаты ОС.
vault.auth.mount_point Полный путь к логину.
Может быть как однословным, напр. my-approle-1, так и в виде пути, напр. my/dep/approle

Как правило, не нужно использовать все эти свойства. В следующем параграфе приведены примеры конкретных конфигураций - вы можете выбрать наиболее подходящий для вас.

Примеры конфигураций

Пример 1. Если секрет попадает на машину с Apiary запакованный (wrapped) и его нужно распаковывать (unwrap) средствами Apiary:

[main]
vault.address = https://my-vault.example.com:8200 
vault.auth.mount_point = my-approle-1 
vault.role_id.value = 7d4714da-1c96-97be-a1ce-c19158d2a1ef 
vault.secret_id.unwrapped.file_path = /opt/vault_secret/secret_id 
vault.secret_id.wrapped.file_path = opt/vault_secret/wrapped_secret_id 
vault.secret_id.unwrap.engine_type = approle

Пример 2. Если секрет попадает на машину с Apiary уже распакованный (unwrapped):

[main]
vault.address = https://my-vault.example.com:8200
vault.auth.mount_point = my-approle-1 
vault.role_id.value = 7d4714da-1c96-97be-a1ce-c19158d2a1ef 
vault.secret_id.unwrapped.file_path = /opt/vault_secret/secret_id 

Не забудьте сделать reconfig как указано в параграфе Реконфигурация что бы изменения вступили в силу.

Распаковка секрета

Если секрет запакованный (wrapped), и Apiary настроен, как показано в примере 1 выше, тот этот секрет автоматически распаковывается при старте приложения. Эта операция может быть выполнена вручную при помощи утилиты vault в составе Apiary:

/opt/hw-fh/bin/vault unwrap 

⚠️ Примечание: для работы этой утилиты требуется утилита jq (легкий и гибкий JSON-процессор командной строки). Пожалуйста, убедитесь, что у вас установлена jq на машине с Apiary. В большинстве дистрибутивов jq доступен в базе пакетов.

Убедиться, что jqи прочие необходимые утилиты установлены в вашей ОС, вы можете проверить, введя следующую команду:

/opt/hw-fh/bin/vault check-config

Так же распаковка секрета может быть выполнена при помощи ваших средств автоматизации с использованием /opt/hw-fh/bin/vault или без неё. Если вы делаете это при помощи ваших средств автоматизации обратите внимание на параграф Особенности взаимодействия с Vault.

Задание путей хранения паролей в Vault для интеграций

После того как общая интеграция с Vault настроена, можно перенести хранение паролей к сервисным аккаунтам AD, SMTP сервера и Jira сервера используемых Apiary.

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

Войдите в WebUI в Apiary как администратор, откройте настройки AD и в поле Service Password введите параметры подключения к Vault, например, так:

engine=kv-v2,mount_point=hw/apiary-1,path=ad_accounts,key=ad_service 

В данном примере:

  • kv-v2: это название secret engine, которое используется в вашем vault. В настоящее время в Apiary поддерживаются kv-v1 и kv-v2.
  • hw/apiary-1: это путь к vault secret engine (так же известная, как mount point), которое вы использовали, когда активировали этот secret engine в vault.
  • ad_accounts: путь к секрету внутри secret engine, в котором хранятся ваши секреты.
  • ad_service: имя ключа в котором хранится пароль к сервисному аккаунту.

В настоящее время все 4 поля (engine, mount_point, path, key) являются обязательными.

После того как вы изменили пароль к сервисному аккаунту к AD, выполните test connect.

Если test connect выполнен успешно это означает, что:

  • Секрет для аутентификации в vault был успешно распакован (если предоставлялся запакованным) или просто успешно прочитан Apiary.

  • При помощи указанного role_id и этого секрета удалось корректно залогиниться в vault.

  • Vault secret engine по указанному в mount_point пути существует и доступен на чтение для этой approle.

  • Версия этого vault secret engine указана корректно.

  • Путь внутри этого secret engine указан корректно.

  • Указанный ключ с паролем по указанному пути нашёлся.

  • В этом ключе хранится корректный пароль к AD серверу и сервисному аккаунту удалось залогиниться в AD и получить список пользователей.

Если test connect оказался неуспешным, необходимо проверить корректность введенных данных на каждом шагу, указанному выше.

Аналогичным образом вы можете задать пути для секретов для соединения с Jira и SMTP сервером.

Перенос существующего секрета в Vault

Если у вас уже была настроенная и работающая Apiary вам может потребоваться перенести секреты, которые сейчас в настоящее время хранятся в ini файлах в Vault. В данном параграфе описана последовательность действий для переноса остальных секретов.

Общая последовательность действий для каждого секрета выглядит так:

  • Получить существующее значение секрета при помощи /opt/hw-fh/bin/get-config-value из существующего в ini файлах свойства (список свойств смотрите ниже).

  • Создать в Vault секрет с этим значением. Это может быть отдельный секрет или поле в существующем секрете - на ваш выбор.

  • Сформировать полный путь этого секрета в Vault, включая mount-point, path, key.

  • Сохранить полный путь секрета в новое свойство (см. список ниже) в /opt/hw-fh/config/user.ini. Пример пути:

    VAULT;engine=kv_v1,mount_point=role_v1_t,path=hw/hive»,key=cipher_key
    

  • Удалить старое свойство при помощи /opt/hw-fh/bin/rm-config-value из ini файлов.

  • Для применения настроек выполните reconfig.

  • Обратите внимание, что после применения настроек в файлах local.ini появятся новые значения для свойств, которые вы удалили. Эти значения автоматически генерируются при каждой реконфигурации системы, однако, эти значения не применяются и не являются секретами для каких-либо сервисов.

Свойства, которые нужно задать для переноса паролей и ключа шифрования в Vault:

  • из sensdata.encrypt.key в sensdata.encrypt.key_path.

  • из f.postgres.password в f.postgres.password_path.

  • из d.postgres.password в d.postgres.password_path.

  • из rmq.password в rmq.password_path.

Подробнее по каждому свойству.

Свойство sensdata.encrypt.key_path:

  • Путь в хранилище секретов Vault к ключу шифрования чувствительных данных, таких как пароли соединений проектов Hive - Apiary. Если путь не задан, используется ключ шифрования, указанный в свойстве sensdata.encrypt.key. При некорректном указании пути, появляется сообщение об ошибке в логе приложения.

  • Указывается как строка в формате: <ENGINE>;<PATH>, где ENGINE в настоящее время только VAULT, а PATH: engine=<engine_type>,mount_point=<mount_point>,path=<path>,key=<key>.

  • Пример: VAULT;engine=kv_v1,mount_point=role_v1_t,path=new/default,key=cipher_key

  • Примечания:

    • Используйте get-config-value sensdata.encrypt.key что бы получить существующий ключ шифрования.
    • После переноса ключа шифрования в Vault рекомендуем удалить свойство при помощи утилиты rm-config-value sensdata.encrypt.key.
    • Ключи шифрования для Hive и Apiary различаются, хотя свойство имеет одинаковое имя.
    • Изменение ключа шифрования для существующих коннектов не предусмотрено.

Свойство f.postgres.password_path:

  • Путь в хранилище секретов Vault к паролю встроенной БД postgresql сервиса. Если путь не задан, используется пароль, указанный в свойстве f.postgres.password. При некорректном указании пути, появляется сообщение об ошибке в логе приложения.

  • Указывается как строка в формате: <ENGINE>;<PATH>, где ENGINE в настоящее время только VAULT, а PATH: engine=<engine_type>,mount_point=<mount_point>,path=<path>,key=<key>.

  • Пример: VAULT;engine=kv_v2,mount_point=role_v2_t,path=hw/customer-portal/main_pg,key=password

  • Примечания:

    • Используйте get-config-value f.postgres.password что бы получить существующий пароль.
    • После переноса пароля в Vault рекомендуем удалить свойство при помощи утилиты rm-config-value f.postgres.password.
    • Изменение пароля в контейнере со встроенным postgresql может быть произведено вручную, если это требуется.

Свойство d.postgres.password_path:

  • Путь в хранилище секретов Vault к паролю встроенной БД postgresql depot сервиса. Если путь не задан, используется пароль, указанный в свойстве d.postgres.password. При некорректном указании пути, появляется сообщение об ошибке в логе приложения.

  • Указывается как строка в формате: <ENGINE>;<PATH>, где ENGINE в настоящее время только VAULT, а PATH: engine=<engine_type>,mount_point=<mount_point>,path=<path>,key=<key>.

  • Пример: VAULT;engine=kv_v2,mount_point=role_v2_t,path=hw/customer-portal/depot_pg,key=password

  • Примечания:

    • Используйте get-config-value d.postgres.password что бы получить существующий пароль.
    • После переноса пароля в Vault рекомендуем удалить свойство при помощи утилиты rm-config-value d.postgres.password.
    • Изменение пароля в контейнере со встроенным postgresql может быть произведено вручную, если это требуется.

Свойство rmq.password_path:

  • Путь в хранилище секретов Vault к паролю встроенного брокера сообщений rabbitmq. Если путь не задан, используется пароль, указанный в свойстве rmq.password. При некорректном указании пути, появляется сообщение об ошибке в логе приложения.

  • Указывается как строка в формате: <ENGINE>;<PATH>, где ENGINE в настоящее время только VAULT, а PATH: engine=<engine_type>,mount_point=<mount_point>,path=<path>,key=<key>.

  • Пример: VAULT;engine=kv_v2,mount_point=role_v2_t,path=hw/customer-portal/rmq,key=password

  • Примечания:

    • Используйте get-config-value rmq.password_path что бы получить существующий пароль.
    • После переноса пароля в Vault рекомендуем удалить свойство при помощи утилиты rm-config-value rmq.password.
    • Изменение пароля в контейнере со встроенным rabbitmq может быть произведено вручную, если это требуется.

Особенности взаимодействия с Vault

Как Apiary логинится в Vault:

  • role_id: хранится на диске в ini файле и передаётся в контейнер в виде переменной среды окружения.

  • Секрет для аутентификации распаковывается только (unwrap) один раз при старте Apiary.

  • Запакованный secret_id: хранится на диске в директории, определённой администратором системы и используется только для распаковки (unwrap) секретов.

  • Распакованный secret_id: хранится на диске в директории, определённой администратором системы и передаётся в контейнер как ReadOnly том (volume).

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

  • При этом часть процессов (для background обработки) могут запускаться не сразу при старте Apiary, а по мере потребности.

  • После успешного логина каждый процесс получает токен для доступа к секрету и далее работает с ним.

Поведение при истечении времени использования токена и секрета AppRole:

  • При истечении времени использования токена Apiary выполняет автоматический повторный логин в Vault при помощи того же самого секрета.

  • При невозможности повторного логина с тем же секретом производится попытка повторного чтения распакованного секрета.

Особенности поведения при ротации секрета для аутентификации в Vault:

  • Повторная автоматическая распаковка запакованного секрета, в случае, если Apiary не смогла залогиниться в Vault с имеющимся секретом, не предусмотрен.

  • Если ваша система автоматического развёртывания меняет секрет для логина в Vault и доставляет запакованный секрет на машину с Apiary, та же самая система должна будет распаковывать его, например, вызвав скрипт /opt/hw-fh/bin/vault unwrap.

  • В случае, если распакованный секрет будет доставляться на машину другими способами (не через наш скрипт), пожалуйста, убедитесь, что inode этого файла не изменяется.

Пример sh скрипта для изменения содержимого файла не изменяя его inode:

touch "${unwrapped_secret_file}"
truncate -s 0 "${unwrapped_secret_file}"
chmod 644 "${unwrapped_secret_file}"
echo "${new_unwrapped_value}" >> "${unwrapped_secret_file}"