Русский
Русский
English
Статистика
Реклама

Hashicorp vault

Zabbix под замком включаем опции безопасности компонентов Zabbix для доступа изнутри и снаружи

02.11.2020 10:17:21 | Автор: admin
А не пришло ли время разобраться и навести наконец-то порядок с безопасностью в мониторинге? Тем более, в одной из популярных систем мониторинга и встроенная возможность такая имеется.



На схеме видно, что зашифровать можно почти все потоки внутри Zabbix. В этой статье мы расскажем и покажем как это сделать, а еще расскажем о новой интеграции Zabbix с хранилищем секретов Hashicorp Vault. Там можно хранить любую чувствительную информацию от логина/пароля в БД до значений макросов. Это позволит централизованно управлять авторизационными данными, вести аудит и не хранить их на файловой системе или в БД Zabbix. Такой функционал появился в последней (на момент публикации статьи) версии Zabbix 5.2.

Интересный факт: включение шифрования на компонентах Zabbix не требует открытия дополнительных портов на фаерволлах, демоны Zabbiх поддерживают шифрованные и нешифрованные соединения одновременно.

Велкам ту подкат.

В Zabbix есть следующие основные информационные потоки:

  • Пользователь (web-браузер) <-> Zabbix web-сервер. Управление конфигурацией Zabbix, представление метрик. Шифрование настраивается средствами web-сервера.
  • Zabbix web-сервер <-> Zabbix-сервер. Web-сервер проверяет запущен ли Zabbix-сервер, запрашивает текущее состояние очереди, выполняет тест элементов данных и некоторые другие операции. Единственный поток, который в соответствии с архитектурой Zabbix нельзя зашифровать. Мы даже пытаться не будем.
  • Zabbix web-сервер <-> База данных Zabbix. Web-сервер обновляет конфигурацию в БД, извлекает данные для визуализации, удаляет исторические данные (по нажатию на Очистить историю) и запускает задания Выполнить сейчас (Execute now). Можно настроить при установке или позже в файле конфигурации zabbix.conf.php. Поддерживается TLS-шифрование при помощи ключей. Для хранения логина и пароля для БД можно использовать Vault. Важный факт: сертификаты, защищённые паролем не поддерживаются.
  • Zabbix-сервер <-> База данных Zabbix. Zabbix-сервер через configuration syncer загружает в свой кэш конфигурацию, через history syncer записывает собранные данные в БД, очищает историю (housekeeping) и выполняет некоторые другие операции. Настройки шифрования выполняются через присваивание значений специальным ключам в конфигурационном файле zabbix_server.conf.
  • Zabbix-сервер <-> Zabbix-агент. Поддерживаются общий ключ PSK и сертификаты. Взаимодействие этих компонентов делится на две части: к узлу сети (TLSAccept для пассивных проверок) и от узла сети (TLSConnect для активных проверок).
  • Zabbix-сервер <-> Zabbix-прокси. Поддерживаются общий ключ PSK и сертификаты. Настройки выполняются через присваивание значений специальным ключам в конфигурационном файле zabbix_proxy.conf.
  • Zabbix-прокси <-> Zabbix-агент. Поддерживаются общий ключ PSK и сертификаты. Взаимодействие этих компонентов делится на две части: к узлу сети (TLSAccept для пассивных проверок) и от узла сети (TLSConnect для активных проверок).
  • Zabbix-прокси <-> БД Zabbix-прокси. Настройки выполняются через присваивание значений специальным ключам в конфигурационном файле zabbix_proxy.conf.
  • Zabbix sender -> Zabbix-прокси. Поддерживаются общий ключ PSK и сертификаты в качестве параметров при вызове через командную строку.
  • Zabbix-агент -> Zabbix get. Поддерживаются общий ключ PSK и сертификаты в качестве параметров при вызове через командную строку.


Пользователь (web-браузер) <-> Zabbix web-сервер


Шифрование этой коммуникации не поддерживается со стороны Zabbix, нужно самостоятельно выполнить настройку на стороне Apache или Nginx. В этой статье мы рассмотрим настройку Nginx с самоподписанным SSL-сертификатом, т.к. преимущественно используем именно Nginx в своих проектах по мониторингу на базе Zabbix. Можно использовать сертификат доверенного центра сертификации, например, бесплатный от Let's Encrypt. Это позволит избежать страшных предупреждений в браузере. Обращаем внимание, что использование самоподписанного сертификата никак не умаляет надежности шифрованного соединения, оно будет таким же защищённым как и при использовании сертификата от доверенного CA.

Листинг настройки
# mkdir -p /etc/ssl/private/
# chmod 0750 /etc/ssl/private
# openssl req \
> -newkey rsa:2048 -nodes -keyout /etc/ssl/private/zabbix.key \
> -x509 -days 365 -out /etc/ssl/certs/zabbix.crt \
> -subj "/C=RU/ST=Russia/L=Moscow/O=Gals/OU=Gals_Dev/CN=gals.software/emailAddress=welcome@gals.software"
# chmod 0400 /etc/ssl/certs/zabbix.crt
# chmod 0400 /etc/ssl/private/zabbix.key
# mv /etc/nginx/conf.d/zabbix.conf /etc/nginx/conf.d/zabbix-ssl.conf
# vi /etc/nginx/conf.d/zbx-ssl.conf
listen 443 ssl default_server;
ssl on;
ssl_certificate /etc/ssl/certs/zabbix.crt;
ssl_certificate_key /etc/ssl/private/zabbix.key;
# vi /etc/nginx/conf.d/zabbix.conf
server {
listen 80;
return 301 https://$host$request_uri;
}
# systemctl restart nginx




В браузере появится замочек и можно посмотреть детали сертификата. Соединение зашифровано.


Zabbix web-сервер <-> База данных Zabbix


Перед началом настройки на стороне Zabbix, в БД должны быть созданы пользователи и роли с атрибутами, требующими шифрованное подключение.

Листинг создания пользователей для Zabbix web-сервера и Zabbix-сервера
mysql> CREATE USER    'zabbix_srv'@'%' IDENTIFIED WITH mysql_native_password BY '<strong_password>',    'zabbix_web'@'%' IDENTIFIED WITH mysql_native_password BY '<strong_password>' REQUIRE SSL    PASSWORD HISTORY 5; mysql> CREATE ROLE 'zabbix_srv_role', 'zabbix_web_role'; mysql> GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP, ALTER, INDEX, REFERENCES ON zabbix.* TO 'zabbix_srv_role'; mysql> GRANT SELECT, UPDATE, DELETE, INSERT ON zabbix.* TO 'zabbix_web_role'; mysql> GRANT 'zabbix_srv_role' TO 'zabbix_srv'@'%'; mysql> GRANT 'zabbix_web_role' TO 'zabbix_web'@'%'; mysql> SET DEFAULT ROLE 'zabbix_srv_role' TO 'zabbix_srv'@'%'; mysql> SET DEFAULT ROLE 'zabbix_web_role' TO 'zabbix_web'@'%';


Вызов статуса вернет, в том числе, данные по настройкам шифрования. Убедимся, что в строке SSL указаны алгоритмы шифрования.



Настройку шифрования между Zabbix и базой данных можно выполнить сразу при первичной настройке Zabbix через web-интерфейс. Обратите внимание на подпись напротив Database TLS encryption. Из-за того, что для подключения к локальной БД используется socket file, нет возможности настроить шифрованное подключение. Поэтому в поле Хост базы данных должны быть указаны IP-адрес или имя сервера с БД.



Меняем localhost на IP-адрес сервера и появляется чекбокс.



На двух скриншотах выше можно увидеть нововведение в Zabbix версии 5.2 поддержку интеграции с хранилищем Vault. Перед началом настройки Zabbix мы создали пару ключей и учетными данными для подключения к БД.



Берем клиентские ключи MySQL, заполняем необходимые поля и нажимаем Далее.



Другой способ настроить то же самое соответствующие ключи в конфигурационном файле zabbix.conf.php.

$DB['ENCRYPTION'] = true;
$DB['KEY_FILE'] = '/etc/ssl/mysql/client-key.pem';
$DB['CERT_FILE'] = '/etc/ssl/mysql/client-cert.pem';
$DB['CA_FILE'] = '/etc/ssl/mysql/ca.pem';
$DB['VERIFY_HOST'] = true;
$DB['CIPHER_LIST'] = '';


Zabbix-сервер <-> База данных Zabbix


На предыдущем шаге мы уже создали пользователя для подключения, клиентские ключи для подключения тоже есть. Осталось прописать эти данные в конфигурационный файл Zabbix-сервера.

DBTLSConnect=required
DBTLSCAFile=/etc/ssl/mysql/ca.pem
DBTLSCertFile=/etc/ssl/mysql/client-key.pem
DBTLSKeyFile=/etc/ssl/mysql/client-cert.pem
DBTLSCipher=''


После выполненных настроек, необходима перезагрузка службы Zabbix-сервера. Логин и пароль для подключения Zabbix-сервера к БД мы также храним в Vault.



Использование Vault требует добавления значений к следующим переменным в конфигурации Zabbix-сервера:

VaultDBPath=kv/secret/zabbix
VaultToken=s.Ev50RnGXNM3FmmcVBMRrR4Nz
VaultURL=http://192.168.56.101:8200


Переменная VaultDBPath отвечает за хранение учетных данных для подключения к БД. Подробнее о шифровании подключений к БД можно узнать в документации Zabbix.

Zabbix-сервер <-> Zabbix-прокси


Как многие пользователи Zabbix знают, в системе существует два типа подключений для передачи метрик: пассивные и активные. Пассивные подразумевают запрос к источнику данных, а активные отправку данных от источника вне зависимости запроса приемника. Аналогичным образом, соединение между сервером и прокси могут быть пассивными или активными. На скриншоте ниже настроен активный прокси, соединение, с которым зашифровано по технологии PSK.



Обратите внимание, что исходящие соединения (пассивные) могут выполняться каким-то одним способом на выбор, а для входящих доступны комбинации вариантов: без шифрования, PSK или сертификат.

На стороне прокси все настройки выполняются в конфигурационном файле. Для активных проверок:

TLSConnect=psk
TLSPSKIdentity=test_zabbix
TLSPSKFile=/var/zabbix/agentd.psk


Для пассивных проверок:

TLSAccept=psk
TLSPSKIdentity=test_zabbix
TLSPSKFile=/var/zabbix/agentd.psk


Второй способ шифрования подключения использование сертификатов. Заметим, что для pre-shared key (PSK) и сертификатов, закрытый ключ хранится на файловой системе в открытом виде.
Подробная информация доступна в документации Zabbix.

Zabbix-сервер <-> Zabbix-агент и Zabbix-прокси <-> Zabbix-агент


Мы не будем повторяться, настройка этих соединений аналогична настройке соединения сервера с прокси: для исходящих соединений доступен один вариант, для входящих один или несколько.



Названия переменных для настройки шифрования на стороне агента полностью аналогичны переменным в конфигурации прокси.

Zabbix-прокси <-> БД Zabbix-прокси


Подход к настройке аналогичен настройке шифрованного соединения между Zabbix-сервером и БД. Названия переменных такие же, указываются в конфигурационном файле Zabbix-прокси.

Zabbix sender -> Zabbix-прокси и Zabbix-агент -> Zabbix get


Шифрование соединения с утилитами Zabbix sender и Zabbix get выполняется при помощи специальных параметров при вызове соответствующих утилит.

zabbix_sender -z 127.0.0.1 -s zabbix02 -k Encrypt -o 18 --tls-connect psk --tls-psk-identity test_zabbix --tls-psk-file /etc/zabbix/keys/agent.psk

zabbix_get -s 127.0.0.1 -k agent.version \
--tls-connect psk --tls-psk-identity test_zabbix --tls-psk-file /etc/zabbix/keys/agent.psk


Авторегистрация с шифрованием


Шифрование также поддерживается и для процесса авторегистрации.



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

Хранение чувствительной информации в Vault


Приятное нововведение, которое появилось в версии Zabbix 5.2 поддержка хранилища Vault. Его можно использовать как для хранения учетных данных для доступа к БД так и для значений макросов. Так значения макросов выглядят в Vault:



А так на них можно сослаться в интерфейсе Zabbix:



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

Заключение


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

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

А ещё можно почитать:

Добавляем CMDB и географическую карту к Zabbix

Мониторинг принтеров дело благородное

Структурированная система мониторинга на бесплатных решениях

Elastic под замком: включаем опции безопасности кластера Elasticsearch для доступа изнутри и снаружи

Для обработки событий от Zabbix, Prometheus, Elastic и других систем рекомендуем использовать Amixr (презентация по запросу).
Подробнее..

Перевод Безопасное использование секретов шаблон для использования HashiCorp Vault

11.01.2021 10:24:00 | Автор: admin

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


Согласно недавнему исследованию ученых из Университета штата Северная Каролина, более 100 000 общедоступных репозиториев GitHub содержат открытые секреты приложений непосредственно в исходном коде. Это исследование от частных токенов API до криптографических ключей просканировало только около 13% общедоступных репозиториев GitHub показывает, что надлежащая защита секретов приложений является одним из наиболее часто игнорируемых методов защиты информации в программном обеспечении.


Хотя масштабы воздействия удивительны, важно отметить, что эта проблема затрагивает не только проекты с открытым исходным кодом. Даже частные репозитории исходного кода могут раскрывать секреты, если они не защищены должным образом. Возьмем, к примеру, нарушение безопасности в Buffer Inc. в 2013 году. То, что начиналось как незаконный доступ к собственному исходному коду Buffer, привело к утечке учетных данных Twitter API компании, что в конечном итоге привело к рассылке спама в учетных записях Twitter бесчисленных клиентов.


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


Введение в HashiCorp Vault


Я большой поклонник HashiCorp. Их подход к инструментам DevOps, не зависящий от поставщика, предоставляет отличные портативные решения, которые абстрагируются от отдельных поставщиков облачных услуг и фокусируются на решении реальных проблем. Их инструмент управления секретами, Vault, не исключение.


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


Установка Vault


Скачать Vault Vault от HashiCorp


Прежде чем мы сможем начать работу с Vault, нам сначала нужно его установить. Как и все продукты HashiCorp, Vault кроссплатформенный, с поддержкой macOS, Windows, Linux, Solaris и даже BSD. Вы даже можете запустить его на Raspberry Pi.


Запуск сервера


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


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


Чтобы запустить сервер разработки, просто запустите команду vault server -dev (-dev указывает, что мы должны запускать сервер разработки, а не рабочий сервер):


$ vault server -dev==> Vault server configuration:        Api Address: http://127.0.0.1:8200                Cgo: disabled    Cluster Address: https://127.0.0.1:8201        Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")        Log Level: info            Mlock: supported: false, enabled: false            Storage: inmem            Version: Vault v1.2.1WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memoryand starts unsealed with a single unseal key. The root token is alreadyauthenticated to the CLI, so you can immediately begin using Vault.You may need to set the following environment variable:    $ export VAULT_ADDR='http://127.0.0.1:8200'The unseal key and root token are displayed below in case you want to seal/unseal the Vault or re-authenticate.Unseal Key: p8MumXfy57bh2T1FxdvZSmHhxqr7aQAByPpfE4PLujk=Root Token: s.aSQmpEYEi5MKelf5TDLPC6r9Development mode should NOT be used in production installations!==> Vault server started! Log data will stream in below:

Как видите, на экран выводится много данных, с которыми вы можете поиграть. Прежде всего следует отметить, что сервер разработки по умолчанию не запускается как демон (и в целях тестирования, никогда не должен запускаться как демон). Следовательно, если вы хотите взаимодействовать с сервером, вы должны сначала открыть второе окно терминала и экспортировать предоставленную переменную среды VAULT_ADDR, чтобы команда Vault хранилища знала, с каким сервером она должна взаимодействовать.


Также важно отметить значения Unseal Key и Root Token. Хотя мы коснемся того, что делать с Root Token в следующем разделе, понимание запечатывания / распечатывания Vault имеет решающее значение для правильного развертывания Vault в производственной среде.


Расшифровка и аутентификация


В производственной среде сервер Vault запускается в закрытом состоянии. Это означает, что Vault знает, где находятся данные, но не знает, как их расшифровать. На сервере разработки Vault по умолчанию не запечатан (unsealed). Однако, если вы решите запечатать его, вы получите ключ распечатки (Unseal Key), чтобы распечатать (unseal) его. Незапечатанный Vault остается в этом состоянии до тех пор, пока оно не будет повторно запечатано или сам сервер не будет перезапущен.


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


$ vault operator initUnseal Key 1: 4jYbl2CBIv6SpkKj6Hos9iD32k5RfGkLzlosrrq/JgOmUnseal Key 2: B05G1DRtfYckFV5BbdBvXq0wkK5HFqB9g2jcDmNfTQiSUnseal Key 3: Arig0N9rN9ezkTRo7qTB7gsIZDaonOcc53EHo83F5chAUnseal Key 4: 0cZE0C/gEk3YHaKjIWxhyyfs8REhqkRW/CSXTnmTilv+Unseal Key 5: fYhZOseRgzxmJCmIqUdxEm9C3jB5Q27AowER9w4FC2CkInitial Root Token: s.KkNJYWF5g0pomcCLEmDdOVCWVault initialized with 5 key shares and a key threshold of 3. Please securely distribute the key shares printed above. When the Vault is re-sealed, restarted, or stopped, you must supply at least 3 of these keys to unseal it before it can start servicing requests.Vault does not store the generated master key. Without at least 3 keys to reconstruct the master key, Vault will remain permanently sealed!It is possible to generate new unseal keys, provided you have a quorum of existing unseal keys shares. See "vault operator rekey" for more information.

Вход в систему


Когда сервер запущен, следующее, что нам нужно сделать, это войти в него. Это можно сделать с помощью команды vault login, которая запросит токен аутентификации. При первоначальной настройке вы можете пройти аутентификацию с помощью Root Token (см. Выше). Однако в производственной среде базовые методы аутентификации можно изменить, чтобы обеспечить более точный контроль над тем, кто имеет доступ и почему:


$ vault loginToken (will be hidden):Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "vault login" again. Future Vault requests will automatically use this token.Key                 Value---                 -----token               s.aSQmpEYEi5MKelf5TDLPC6r9token_accessor      MaJhao2R54EdV9fDq7sL11d4token_duration      token_renewable     falsetoken_policies      ["root"]identity_policies   []policies            ["root"] 

Хранение секретов


В то время как Vault HashiCorp можно использовать для безопасного хранения практически любых данных, наиболее распространенным вариантом использования Vault является хранилище ключей и значений для секретов приложений. После проверки подлинности хранение секретов становится невероятно простым благодаря команде vault kv put:


$ vault kv put secret/foo bar=bazKey             Value---             -----created_time    2019-08-09T16:43:10.604124Zdeletion_time   n/adestroyed       falseversion         1

Чтобы немного разобрать приведенную выше команду и ответ, мы создали новый секрет с именем foo в пространстве имен secret со значением bar=baz, ответ дает нам некоторые базовые метаданные о нашем новом секрете. Хотя ключи created_time, deletion_time и destroyed не требуют пояснений, вам следует обратить особое внимание на ключ version, потому что это подразумевает, что секреты могут быть версированы.


Например, давайте посмотрим, что произойдет, если мы введем новое значение для того же секрета:


$ vault kv put secret/foo bat=ballKey             Value---             -----created_time    2019-08-09T16:43:32.638788Zdeletion_time   n/adestroyed       falseversion         2

Видите, как был увеличен ключ метаданных версии? Это означает, что наше исходное значение должно поддерживаться в дополнение к новым значениям, что обеспечивает отличный журнал аудита того, какие секреты были изменены и когда.


Извлечение секретов


$ vault kv list secretKeys----foo

Хранение секретов это только половина дела. Другая половина извлекать эти секреты. В нашем примере выше давайте сначала посмотрим, как получить весь список секретов:


Как видите, хотя технически мы помещаем два секрета, отслеживается только один ключ, потому что эти два секрета на самом деле являются всего лишь двумя версиями одного секрета. Чтобы получить его, выполните команду vault kv get с секретным пространством имен и ключом:


$ vault kv get secret/foo====== Metadata ======Key             Value---             -----created_time    2019-08-09T16:43:32.638788Zdeletion_time   n/adestroyed       falseversion         2=== Data ===Key Value--- -----bat ball

По умолчанию Vault будет извлекать самую последнюю версию секрета, но если мы хотим получить предыдущую версию, можно использовать директиву -version:


$ vault kv get -version=1 secret/foo====== Metadata ======Key             Value---             -----created_time    2019-08-09T16:43:10.604124Zdeletion_time   n/adestroyed       false   version         1=== Data ===Key Value--- -----bar baz

Ценность секретов с управлением версиями невероятна, поскольку они позволяют внутренним службам привязаться к различным секретным версиям, что дает возможность постепенно развиваться, выпускать (release) и откатывать изменения приложений, не опасаясь потери важных данных.


Удаление секретов


Несмотря на преимущества контроля секретами, нам может понадобится фактическое удаление секрета (или его версии). Это можно сделать двумя способами, в зависимости от того, насколько удаленным вы хотите, чтобы секрет был: удалить delete и уничтожить destroy. Чтобы проиллюстрировать это, давайте сначала рассмотрим удаление версии нашего секрета foo:


$ vault kv delete -versions=1 secret/fooSuccess! Data deleted (if it existed) at: secret/foo

Это помечает данные как удаленные (deleted) и предотвращает их извлечение в обычных запросах GET, но фактически не удаляет данные:


$ vault kv get -version=1 secret/foo====== Metadata ======Key             Value---             -----created_time    2019-08-09T16:43:10.604124Zdeletion_time   2019-08-09T16:45:39.664577Zdestroyed       falseversion         1

Чтобы данные действительно были удалены без возможности восстановления, необходимо использовать команду destroy:


$ vault kv destroy -versions=1 secret/fooSuccess! Data written to: secret/destroy/foo

Вместо того, чтобы просто пометить данные как удаленные и ограничить доступ к ним, команда destroy удалит их полностью, что сделает невозможным последующее извлечение:


$ vault kv get -version=1 secret/foo====== Metadata ======Key             Value---             -----created_time    2019-08-09T16:43:10.604124Zdeletion_time   2019-08-09T16:45:39.664577Zdestroyed       trueversion         1

Копаем глубже в HashiCorp Vault


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


Secrets engines


$ vault secrets enable databaseSuccess! Enabled the database secrets engine at: database/

Хранилище ключей и значений по умолчанию в Vault является примером механизма секретов (в частности, механизма под названием kv). По своей сути алгоритм секретов это абстрактный механизм хранения секретных данных. Это означает, что вместо механизма хранения на основе ключа-значения можно использовать более целевые механизмы хранения. Например, механизм секретов базы данных может использоваться для динамического генерирования учетных данных базы данных (database) на основе настроенных ролей для MySQL и MariaDB, что позволяет производить автоматическую ротацию учетных данных root или даже временные учетные данные для доступа по запросу.


Методы аутентификации


$ vault auth enable githubSuccess! Enabled github auth method at: github/

В дополнение к стандартному методу аутентификации на основе токенов Vault поддерживает ряд дополнительных методов аутентификации для лучшей поддержки ваших вариантов использования. Отличным примером этого является метод проверки подлинности GitHub, который можно использовать для автоматического предоставления доступа к Vault разработчикам, принадлежащим к определенной организации GitHub и даже к определенной группе внутри организации GitHub с использованием только токена личного доступа. Для более крупных организаций решения единого входа на уровне предприятия, такие как LDAP или Okta, могут использоваться для аутентификации пользователей в Vault.


Авторизация


$ vault write auth/userpass/users/test policies="dev-readonly,logs"

Авторизация всегда идет рука об руку с аутентификацией. Хотя предоставить глобальный доступ с помощью GitHub или аутентификации на основе токенов несложно, это почти никогда не бывает полным решением. Благодаря политике Vault может быть реализован метод авторизации в стиле RBAC, предоставляющий разным пользователям и группам CRUD-подобный доступ к различным аспектам самого хранилища. В сочетании с одним из более продвинутых методов аутентификации это может стать невероятно мощным инструментом для детального контроля доступа в большой организации.


За пределами Vault


Каким бы мощным ни было Vault, настроить его правильно довольно сложно. Хотя размер и объем различных методов проверки подлинности и механизмов секретов ясно показывают, сколько вы можете сделать с Vault, может быть сложным осмыслить основы управления секретами в контексте информационной безопасности исходного кода. Благодаря впечатляюще большому количеству как официальных, так и общественных библиотек API, получение секретов безопасным способом невероятно просто, и если вы стремитесь стать опытным пользователем Vault, собственная учебная программа Vault HashiCorp отличный способ для начала изучения.


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

Подробнее..

VaultPydantic продолжение саги, локальная разработка

16.12.2020 02:21:17 | Автор: admin


Предыстория


Предыдущая статья


В предыдущей статье я писал о том, как сконфигурировать ваше приложение с помощью Sitri, однако, упустил момент с локальной разработкой, так как согласитесь, что не очень удобно разворачивать vault локально, да и хранить локальный конфиг в общем vault, особенно, если над проектом работают несколько человек неудобнее вдвойне.


В Sitri данная проблема решается достаточно просто с помощью локального режима для ваших классов настроек, то есть вам не придётся даже переписывать ничего или дублировать код, да и структура json файла для локального режима будет почти полностью повторять структуру секретов.


Итак, ну а теперь, давайте добавим в наш проектик буквально пару строк кода + я покажу, как со всем этим можно работать, если ваш проект локально запускается в docker-compose.


Готовим код


Для начала, давайте договоримся, что local_mode действует тогда, когда ENV = "local" :) Далее, я предлагаю немного отредактировать наш provider_config.py и создать там класс BaseConfig от которого мы будем наследовать в наших настройках Config классы. Мы сделаем это для того, чтобы не дублировать код, то есть в самих классах настроек будет только то, что специфично для них.


import hvacfrom sitri.providers.contrib.system import SystemConfigProviderfrom sitri.providers.contrib.vault import VaultKVConfigProviderfrom sitri.settings.contrib.vault import VaultKVSettingsconfigurator = SystemConfigProvider(prefix="superapp")ENV = configurator.get("env")is_local_mode = ENV == "local"local_mode_file_path = configurator.get("local_mode_file_path")def vault_client_factory() -> hvac.Client:    client = hvac.Client(url=configurator.get("vault_api"))    client.auth_approle(        role_id=configurator.get("role_id"),        secret_id=configurator.get("secret_id"),    )    return clientprovider = VaultKVConfigProvider(    vault_connector=vault_client_factory,    mount_point=f"{configurator.get('app_name')}/{ENV}",)class BaseConfig(VaultKVSettings.VaultKVSettingsConfig):    provider = provider    local_mode = is_local_mode    local_provider_args = {"json_path": local_mode_file_path}

Немного про local_provider_args в этом поле мы указываем аргументы для создания экземпляра JsonConfigProvider, они будут провалидированы и данный словарь должен соотвествовать схеме, поэтому не волнуйтесь это не какой-то грязный приём. Однако, если вы хотите создать экземпляр локального провайдера сами, то вы просто положить его в опциональное поле local_provider.


Теперь, мы можем спокойно наследовать конфиг классы от базового. Например, класс настроек для соединения с Kafka будет выглядеть так:


from typing import Any, Dictfrom pydantic import Fieldfrom sitri.settings.contrib.vault import VaultKVSettingsfrom superapp.config.provider_config import BaseConfig, configuratorclass KafkaSettings(VaultKVSettings):    mechanism: str = Field(..., vault_secret_key="auth_mechanism")    brokers: str = Field(...)    auth_data: Dict[str, Any] = Field(...)    class Config(BaseConfig):        default_secret_path = "kafka"        default_mount_point = f"{configurator.get('app_name')}/common"        local_mode_path_prefix = "kafka"

Как видите требуемые изменения минимальны. local_mode_path_prefix мы указываем, чтобы в нашем json файле сохранялась структура общего конфига. А теперь, давайте напишем этот самый json файл для локальной конфигурации:


{    "db":    {        "host": "testhost",        "password": "testpassword",        "port": 1234,        "user": "testuser"    },    "faust":    {        "agents":        {            "X":            {                "concurrency": 2,                "partitions": 5            }        },        "app_name": "superapp-workers",        "default_concurrency": 5,        "default_partitions_count": 10    },    "kafka":    {        "auth_data":        {            "password": "testpassword",            "username": "testuser"        },        "brokers": "kafka://test",        "mechanism": "SASL_PLAINTEXT"    }}

Ну, или просто скопипастим его из конца прошлой статьи. Как видите, тут всё весьма просто. Для наших дальнейших изысканий, переименуем main.py в корне проекта на __main__.py, чтобы можно было запустить пакет командой из docker-compose.


Запихиваем приложение в контейнер и наслаждаемся сборкой


Первое, что мы должны сделать это написать небольшой Dockerfile:


FROM python:3.8.3-busterENV PYTHONUNBUFFERED=1 \    POETRY_VIRTUALENVS_CREATE=false \    POETRY_VIRTUALENVS_IN_PROJECT=false \    POETRY_NO_INTERACTION=1RUN pip install poetryRUN mkdir /superapp/WORKDIR /superapp/COPY ./pyproject.toml ./poetry.lock /superapp/RUN poetry install --no-ansiWORKDIR /

Здесь мы просто устанавливаем зависимости и всё, так как он для локальной разработки, то код проекта мы не копируем.


Далее, нам понадобиться env-файл с необходимыми для local-mode переменными:


SUPERAPP_ENV=localSUPERAPP_LOCAL_MODE_FILE_PATH=/config.jsonSUPERAPP_APP_NAME=superapp

Как видите, ничего лишнего, никакой конфигурационной информации для Vault не нужно, так как при локальном режиме, приложение даже не попытается постучаться в Vault.


Ну и последнее, что мы должны написать сам docker-compose.yml файл:


# docker-compose config for local developmentversion: '3'services:  superapp:    command: python3 -m superapp    restart: always    build:      context: ./      dockerfile: Dockerfile    volumes:      - ./superapp:/superapp      - ./config.json:/config.json    env_file:      - .env.local

Как видите, тут тоже всё просто. Наш json-файл мы кладём в корень, как и указали выше в переменной окружения для контейнера.


Ну а теперь, запуск:


docker-compose up

Creating article_sitri_vault_pydantic_superapp_1 ... doneAttaching to article_sitri_vault_pydantic_superapp_1superapp_1  | db=DBSettings(user='testuser', password='testpassword', host='testhost', port=1234) faust=FaustSettings(app_name='superapp-workers', default_partitions_count=10, default_concurrency=5, agents={'X': AgentConfig(partitions=5, concurrency=2)}) kafka=KafkaSettings(mechanism='SASL_PLAINTEXT', brokers='kafka://test', auth_data={'password': 'testpassword', 'username': 'testuser'})superapp_1  | {'db': {'user': 'testuser', 'password': 'testpassword', 'host': 'testhost', 'port': 1234}, 'faust': {'app_name': 'superapp-workers', 'default_partitions_count': 10, 'default_concurrency': 5, 'agents': {'X': {'partitions': 5, 'concurrency': 2}}}, 'kafka': {'mechanism': 'SASL_PLAINTEXT', 'brokers': 'kafka://test', 'auth_data': {'password': 'testpassword', 'username': 'testuser'}}}

Как видите, всё успешно запустилось и информация из нашего json-фала успешно прошла все проверки и стала настройками для локальной версии приложения, юхху!


Код этой статьи я положил в отдельную ветку, так что можете зайти, склонить и протестировать всё самолично :)
branch

Подробнее..

Бэкапы для HashiCorp Vault с разными бэкендами

26.05.2021 10:15:20 | Автор: admin

Недавно мы публиковали статью про производительность Vault с разными бэкендами, а сегодня расскажем, как делать бэкапы и снова на разных бэкендах: Consul, GCS (Google Cloud Storage), PostgreSQL и Raft.

Как известно, HashiCorp предоставляет нативный метод бэкапа только для одного бэкенда Integrated Storage (Raft Cluster), представленного как GA в апреле прошлого года. В нем можно снять снапшот всего одним curlом и не беспокоиться о каких-либо нюансах. (Подробности смотрите в tutorial и документации по API.)

В остальных же случаях придется выкручиваться самим, придумывая, как правильно реализовывать бэкап. Очевидно, что во время резервного копирования Vault часть данных может меняться, из-за чего мы рискуем получить некорректные данные. Поэтому важно искать пути для консистентного бэкапа.

1. Consul

В Consul существует встроенный механизм для создания и восстановления снапшотов. Он поддерживает point-in-time backup, поэтому за консистентность данных можно не переживать. Однако есть существенный недостаток: на время снапшота происходит блокировка, из-за чего могут возникнуть проблемы с операциями на запись.

Для создания такого снимка необходимо:

1. Подключиться к инстансу с Consul и выполнить команду:

# consul snapshot save backup.snapSaved and verified snapshot to index 199605#

2. Забрать файл backup.snap (заархивировать и перенести в место для хранения бэкапов).

Для восстановления будет схожий алгоритм действий с выполнением другой команды на сервере с Consul:

# consul snapshot restore backup.snap

В HA Vault-кластере активный узел будет являться лидером во время экспорта данных или моментального снимка. После восстановления данных Vault в Consul необходимо вручную снять эту блокировку, чтобы кластер Vault мог выбрать нового лидера.

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

# consul kv delete vault/core/lock

Работа со снапшотами обычно происходит быстро (см. примеры в конце статьи) и обычно не вызывает трудностей.

2. Google Cloud Storage

С GCS всё оказалось сложнее: подходящих вариантов для создания снапшотов/бэкапов бакета найти не удалось. Предусмотрена поддержка версионирования, но с ним восстановить сразу весь бакет на определенный момент времени нельзя можно только по одному файлу. В теории это решается скриптом для взаимодействия со всеми файлами, но если учесть размер Vaultа и количества файлов в нем, скорее всего такой скрипт будет работать слишком долго. Если мы хотим получить консистентные данные, то снятия дампа придется на время останавливать Vault.

А для копирования данных в GCS предусмотрен удобный способ Data Transfer. С его помощью можно создать полную копию бакета, а дальше уже работать с ним по своему усмотрению.

Последовательность действий:

  1. Выключаем Vault.

  2. Заходим в Data Transfer (https://console.cloud.google.com/transfer/cloud).

  3. Выбираем исходный бакет, вводим название бакета, куда переносить данные, и выбираем разовую операцию. Здесь возможно установить и операцию по расписанию, но она не учитывает специфики Vault (тот факт, что сервис необходимо остановить Vault на время её выполнения), поэтому оставляем разовый запуск.

  4. После успешного копирования запускаем Vault.

  5. С созданным бакетом можно работать: например, скачать его содержимое при помощи gsutil, заархивировать все данные и отправить на долгосрочное хранение.

В зависимости от количества ключей продолжительность бэкапа может сильно изменяться: от нескольких минут и практически до бесконечности. Ниже будет приведена таблица с примерными значениями.

Скриншоты страницы при создании трансфера и после завершения:

3. PostgreSQL

Базу в PostgreSQL достаточно забэкапить любыми доступными для этой СУБД способами не сомневаюсь, что они хорошо известны инженерам, уже работающим с PgSQL. Инструкции по выполнению операций для настройки бэкапов и восстановления данных на нужный момент времени (PITR, Point-in-Time Recovery) описаны в официальной документации проекта. Также хорошую инструкцию можно найти в этой статье от Percona.

Не останавливаясь на технических деталях по этим операциям (они уже раскрыты в многочисленных статьях), отмечу, что у PostgreSQL получился заметно более быстрый бэкап, чем у вариантов выше. Для простоты действий, мы замеряли бэкап и восстановление обычными pg_dump и pg_restore (да, это упрощенное измерение, однако использование схемы с PITR не повлияет значительно на скорость).

4. Integrated Storage (Raft)

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

Для создания снимка необходимо:

. Зайти на сервер/pod, где запущен Vault, и выполнить команду:

# vault operator raft snapshot save backup.snapshot
  1. Забрать файл backup.snapshot (заархивировать и перенести в место для хранения бэкапов).

Для восстановления команду на сервере с Vault надо заменить на:

# vault operator raft snapshot restore backup.snapshot

Как работать с Raft и со снапшотами, хорошо описано в официальной документации.

Простой бенчмарк

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

Загрузка данных в Vault

Перед началом тестирования загрузим данные в Vault. Мы для этого использовали официальный репозиторий от HashiCorp: в нем есть скрипты для вставки ключей в Vault.

Протестируем на двух коллекциях: 100 тысяч и 1 млн ключей. Команды для первого теста:

export VAULT_ADDR=https://vault.service:8200export VAULT_TOKEN=YOUR_ROOT_TOKENvault secrets enable -path secret -version 1 kvnohup wrk -t1 -c16 -d50m -H "X-Vault-Token: $VAULT_TOKEN" -s write-random-secrets.lua $VAULT_ADDR -- 100000

Эту операцию проделаем для всех инсталляций Vault, а затем повторим её для другого количества ключей.

Результаты

После загрузки данных мы сделали бэкап для всех 4 бэкендов. Бэкап для каждого hosted-бэкенда снимался на однотипной машине (4 CPU, 8 GB RAM).

Результаты сравнения по бэкапу и восстановлению:

100k backup

100k restore

1kk backup

1kk restore

Consul

3.31s

2.50s

36.02s

27.58s

PosgreSQL

0.739s

1.820s

4.911s

24.837s

GCS*

1h

1h24m

12h

16h

Raft

1.96s

0.36s

22.66s

4.94s

* Восстановление бэкапа в GCS может происходить в нескольких вариантах:

  1. Мы просто переключаем Vault на бэкапный бакет. В таком случае достаточно перезапустить Vault с новым конфигом и все сразу же заработает.

  2. Загрузить файлы бэкапа в бакет через утилиту gsutil и уже после этого переключать. Результаты для такого варианта будут зависеть от количества файлов и их размера в таблице приведен результат именно для такого варианта.

NB. В этом мини-тестировании сравниваются решения разного рода: single-экземпляр PostgreSQL против кластеров Consul и Raft против сетевого распределённого хранилища (GCS). Это может показаться не совсем корректным, потому что у таких бэкендов и разные возможности/свойства (отказоустойчивость и т.п.). Однако данное сравнение приведено исключительно как примерный ориентир для того, чтобы дать понимание порядковой разницы в производительности. Ведь это зачастую является одним из факторов при выборе того или иного способа.

Выводы

PostgreSQL занимает уверенное первое место по скорости создания бэкапа. Raft не так сильно отстает от лидера на небольшом объеме секретов, но разница заметно возрастает при увеличении количества данных. Однако в то же время Raft явно лидирует в скорости восстановления.

Если сравнивать удобство, то Raft и Consul максимально простые: для выполнения бэкапа и восстановления достаточно выполнить буквально одну команду. GCS же предоставляет встроенный функционал в UI для копирования бакетов: на мой вкус, это немного сложнее, однако для других пользователей может быть плюсом, что все действия выполняются мышкой в браузере. Но в GCS есть существенная проблема с отсутствием гарантий по времени создания снапшотов: одинаковый набор данных может бэкапиться как за 1 час, так и за 3-4 часа.

Помимо производительности и удобства есть и другой критерий надежность. Вывод, казалось бы, довольно банален: чем менее надежен бэкенд, тем легче его бэкапить. Хотя Vault сам по себе позиционируется как приложение категории cloud native, его бэкап полностью зависит от выбранного бэкенда, и во многих случаях мы получим простой, что недопустимо для такого важного сервиса:

  • В Consul можно ожидать проблем с чтением и записью при бэкапе/восстановлении данных.

  • А у PostgreSQL при восстановлении.

  • У GCS проблема другого характера: нет гарантий на скорость копирования.

Получается, что все эти решения имеют серьёзные недостатки, которые могут быть недопустимы в production. Понимая это, в HashiCorp и создали своё оптимальное решение Integrated Storage (Raft). В нём получается делать бэкапы полностью беспростойно и при этом быстро.

В итоге: если вам важна максимальная скорость для снятия и восстановления бэкапов, то подойдут PostgreSQL и Raft. В первом случае, однако, надо повозиться с удобством: чтобы все правильно настроить и автоматизировать, придется потратить время (и иметь экспертизу). Наш текущий выбор пал на Integrated Storage (Raft) как самый простой в использовании и надежный бэкенд.

P.S.

Читайте также в нашем блоге:

Подробнее..

Конфигурируем сервис с помощью Vault и Pydantic

09.12.2020 04:19:27 | Автор: admin

image


Предисловие


В данной статье я расскажу о конфигурации для вашей сервисов с помощью связки Vault (KV и пока только первой версии, т.е. без версионирования секретов) и Pydantic (Settings) под патронажем Sitri.


Итак, допустим, что у нас есть приложение superapp с заведёнными конфигами в Vault и аутентификацией с помощью approle, примерно так настроим (настройку policies для доступа к секрет-энжайнам и к самим секретам я оставлю за кадром, так как это достаточно просто и статья не об этом):


Key                        Value---                        -----bind_secret_id             truelocal_secret_ids           falsepolicies                   [superapp_service]secret_id_bound_cidrs      <nil>secret_id_num_uses         0secret_id_ttl              0stoken_bound_cidrs          []token_explicit_max_ttl     0stoken_max_ttl              30mtoken_no_default_policy    falsetoken_num_uses             50token_period               0stoken_policies             [superapp_service]token_ttl                  20mtoken_type                 default

Прим.: естественно, что если у вас есть возможность и приложение выходит в боевой режим, то secret_id_ttl лучше делать не бесконечным, выставляя 0 секунд.


SuperApp требует конфигурации: подключения к базе данных, подключение к kafka и faust конфигурации для работы кластера воркеров.


Подготовим Sitri


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


Итак, для начала сконфигурируем vault-провайдер в условном файле provider_config.py:


import hvac  from sitri.providers.contrib.vault import VaultKVConfigProvider  from sitri.providers.contrib.system import SystemConfigProvider  configurator = SystemConfigProvider(prefix="superapp")  ENV = configurator.get("env")  def vault_client_factory() -> hvac.Client:      client = hvac.Client(url=configurator.get("vault_api"))      client.auth_approle(          role_id=configurator.get("role_id"),    secret_id=configurator.get("secret_id"),    )      return client  provider = VaultKVConfigProvider(      vault_connector=vault_client_factory, mount_point=f"{configurator.get('app_name')}/{ENV}"  )

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


export SUPERAPP_ENV=devexport SUPERAPP_APP_NAME=superappexport SUPERAPP_VAULT_API=https://your-vault-host.domainexport SUPERAPP_ROLE_ID=535b268d-b858-5fb9-1e3e-79068ca77e27 # Примерexport SUPERAPP_SECRET_ID=243ab423-12a2-63dc-3d5d-0b95b1745ccf # Пример

В примере предполагается, что базовый mount_point к вашим секретам для определённой среды будет содержать имя приложения и имя среды, поэтому мы и экспортировали SUPERAPP_ENV. Путь до секретов отдельных частей приложения мы будем определять в settings-классах далее, поэтому в провайдере secret_path мы оставляем пустым.


Классы настроек


Начнём по пунктам и разнесём три класса настроек (БД, Kafka, Faust) по трём разным файлам.


Настройки БД


from pydantic import Field  from sitri.settings.contrib.vault import VaultKVSettings  from superapp.config.provider_config import provider  class DBSettings(VaultKVSettings):      user: str = Field(..., vault_secret_key="username")      password: str = Field(...)      host: str = Field(...)      port: int = Field(...)      class Config:          provider = provider          default_secret_path = "db"

Итак, как видите, конфиг. данные для базы у нас достаточно простые. Этот класс будет по-умолчанию смотреть в секрет superapp/dev/db, так, как мы указали в config классе, в остальном здесь простые pydantic поля, но в одном из них присутствует extra-аргумент vault_secret_key он нужен тогда, когда ключ в секрете не совпадает по имени с pydantic полем в нашем классе, если его не указывать, то провайдер будет искать ключ по имени поля.


Например, в нашем тестовом приложении, предполагается, что в секрете superapp/dev/db, есть ключи password и username, но мы хотим, чтобы последний был помещён в поле user для удобства и краткости.


Поместим в вышеозначенный секрет следующие данные для примера:


{  "host": "testhost",  "password": "testpassword",  "port": "1234",  "username": "testuser"}

Для первого класса из тройки, я покажу, как легко можно всё это запустить, чтобы данные собрались сами:


db_settings = DBSettings()pprint(db_settings.dict())# -> # {#     "host": "testhost",#     "password": "testpassword",#     "port": 1234,#     "user": "testuser"# }

Настройки Kafka


from typing import Dict, Any  from pydantic import Field  from sitri.settings.contrib.vault import VaultKVSettings  from superapp.config.provider_config import provider, configurator  class KafkaSettings(VaultKVSettings):      mechanism: str = Field(..., vault_secret_key="auth_mechanism")      brokers: str = Field(...)      auth_data: Dict[str, Any] = Field(...)      class Config:          provider = provider          default_secret_path = "kafka"          default_mount_point = f"{configurator.get('app_name')}/common"

В данном случае, представим, что инстанс кафки для разных сред нашего сервиса один, поэтому секрет хранится по пути superapp/common/kafka


{  "auth_data": "{\"password\": \"testpassword\", \"username\": \"testuser\"}",  "auth_mechanism": "SASL_PLAINTEXT",  "brokers": "kafka://test"}

Класс настройки поймёт комплексный тип данных Dict[str, Any] и распарсит его в словарь, то есть при заполнении наших настроек будут следующие данные:


{    "auth_data":    {        "password": "testpassword",        "username": "testuser"    },    "brokers": "kafka://test",    "mechanism": "SASL_PLAINTEXT"}

Так же, если секрет будет задан напрямую в json, например так:


{  "auth_data": {    "password": "testpassword",    "username": "testuser"  },  "auth_mechanism": "SASL_PLAINTEXT",  "brokers": "kafka://test"}

То класс настроек тоже сможет правильно разложить данные.


P.S.
Так же, secret_path и mount_point можно задавать на уровне полей, чтобы провайдер запросил конкретные значения из разных секретов (если это требуется). Приведу цитату с приоритезацией пути секрета и точки монтирования из документации:


Secret path prioritization:
  1. vault_secret_path (Field arg)
  2. default_secret_path (Config class field)
  3. secret_path (provider initialization optional arg)


Mount point prioritization:
  1. vault_mount_point (Field arg)
  2. default_mount_point (Config class field)
  3. mount_point (provider initialization optional arg)


Настройки Faust и отдельных воркеров


from typing import Dict  from pydantic import Field, BaseModel  from sitri.settings.contrib.vault import VaultKVSettings  from superapp.config.provider_config import provider  class AgentConfig(BaseModel):      partitions: int = Field(...)      concurrency: int = Field(...)  class FaustSettings(VaultKVSettings):      app_name: str = Field(...)      default_partitions_count: int = Field(..., vault_secret_key="partitions_count")      default_concurrency: int = Field(..., vault_secret_key="agent_concurrency")      agents: Dict[str, AgentConfig] = Field(default=None, vault_secret_key="agents_specification")      class Config:          provider = provider          default_secret_path = "faust"

superapp/dev/faust:


{  "agent_concurrency": "5",  "app_name": "superapp-workers",  "partitions_count": "10"}

В данном случае, по-умолчанию у нас есть глобальные значения кол-ва партиций в кафке и concurrency для агентов. Таким образом, по-умолчанию наши настройки будут выгружены так:


{  "agents": None,  "app_name": "superapp-workers",  "default_concurrency": 5,  "default_partitions_count": 10}

Например, у нас есть агент X с настройками:


{  "partitions": 5,  "concurrency": 2}

Наш секрет в связи с этим должен выглядеть следующим образом:


{  "agent_concurrency": "5",  "agents_specification": {    "X": {      "concurrency": "2",      "partitions": "5"    }  },  "app_name": "superapp-workers",  "partitions_count": "10"}

Как и ожидалось данные корректно смапились и типы значений были преобразованы так, как указано в модели AgentConfig:


{    "agents":    {        "X":        {            "concurrency": 2,            "partitions": 5        }    },    "app_name": "superapp-workers",    "default_concurrency": 5,    "default_partitions_count": 10}

Совмещаем в единый конфиг класс


from pydantic import BaseModel, Field  from superapp.config.database_settings import DBSettings  from superapp.config.faust_settings import FaustSettings  from superapp.config.kafka_settings import KafkaSettings  class AppSettings(BaseModel):      db: DBSettings = Field(default_factory=DBSettings)      faust: FaustSettings = Field(default_factory=FaustSettings)      kafka: KafkaSettings = Field(default_factory=KafkaSettings)

Совместим наши классы настроек в одну модель, применив default_factory для автоматического сбора при инициализации модели всех наших данных.


Давайте запустим наш код и проверим, как всё сработается вместе:


from superapp.config import AppSettings  config = AppSettings()  print(config)  print(config.dict())

Получаем общий вывод всей конфигурации приложения:


db=DBSettings(user='testuser', password='testpassword', host='testhost', port=1234) faust=FaustSettings(app_name='superapp-workers', default_partitions_count=10, default_concurrency=5, agents={'X': AgentConfig(partitions=5, concurrency=2)}) kafka=KafkaSettings(mechanism='SASL_PLAINTEXT', brokers='kafka://test', auth_data={'password': 'testpassword', 'username': 'testuser'})

{    "db":    {        "host": "testhost",        "password": "testpassword",        "port": 1234,        "user": "testuser"    },    "faust":    {        "agents":        {            "X":            {                "concurrency": 2,                "partitions": 5            }        },        "app_name": "superapp-workers",        "default_concurrency": 5,        "default_partitions_count": 10    },    "kafka":    {        "auth_data":        {            "password": "testpassword",            "username": "testuser"        },        "brokers": "kafka://test",        "mechanism": "SASL_PLAINTEXT"    }}

Счастье, радость, восторг!


У нас получилась такая структура тест-проекта:


superapp config    app_settings.py    database_settings.py    faust_settings.py    __init__.py    kafka_settings.py    provider_config.py __init__.py main.py

Послесловие


Как видите настройка достаточно проста с Sitri, после неё мы получаем чёткую схему конфигурации с нужными нам типами данных у значений, даже если в vault по-умолчанию они хранились строками.


Пишите комментарии по поводу либы, кода или общие впечатления. Буду рад любому отзыву!


P.S. Код из статьи я залил на github https://github.com/Egnod/article_sitri_vault_pydantic

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru