О чем статья?
Короткая статейка о том, как сгенерировать пароли необходимые для разнообразных сервисов автоматически устанавливаемых с помощью SaltStack.
Трудности генерации паролей.
Очень часто приходится автоматически устанавливать сервисы или приложения, которые требуют указания паролей для доступов к каким-то своим частям (например, к web интерфейсу или к управлению своим API). Не менее часто приходится конфигурировать пользователей баз данных, которые будут затем использоваться в сервисах использующих эти базы и т. д.
Типичная проблема, — генерация паролей для всех подобных случаев. Есть несколько решений этой проблемы:
1. Прописать пароли вручную в pillar файл
pillar/passwords.sls
service1:
web-access-password: '9KTE2aN11GYOJmZGOoqV'
db-access-password: '2pGbSlSFkHPY22TwqUus'
Ну и потом в любом другом пилларе или в стейте использовать указанные пароли для генерации доступов.
Все вроде бы нормально и понятно, — но есть одно но — если вы будете распространять стейт использующий указанный пиллар, то пароли будут сохраняться в том же неизменном виде. Мало того, — даже все однотипные серверы, для которых будут применен этот стейт будут иметь одинаковый пароль. Естественно нет смысла объяснять чем это может грозить с точки зрения информационной безопасности.
2. Сгенерировать пароли средствами SaltStack.
Есть одна интересная ф-ция в SaltStack в модуле grains get_or_set_hash, которая может сгенерировать пароль для последующего использования определенного grain. Пароли получаются достаточно комплексными (из-за дефолтного набора символов, которые можно переопределить при вызове), использовать их в стейтах легко (просто считать соответствующий grain с миниона). Единственное, о чем стоит помнить, — генерация пароля происходит только при первом вызове этой ф-ции (и сам пароль помещается в /etc/salt/grains файл), все последующие — будут просто читать этот грейн из файла как если бы вызывался salt['grains.get']('stored-password-grain-name').
Один из самых существенных недостатков этого способа — отсутствие возможности читать сгенерированные таким образом пароли в pillar файлах, что часто бывает полезно при использовании разнообразных формул (SaltStack Formulas).
3. Пред. генерация паролей в pillar файле.
Еще один способ, который я использую достаточно часто — предварительное генерирование паролей с помощью Jinja2.
В общем случае, для пред. генерации используется minion установленный на той же машине что и Salt Master. Если не хочется подключать такой minion к самому мастеру, можно воспользоваться masterless конфигурацией, но я предпочитаю использовать минион подключенным к мастеру, обозначив его grains:roles:local-minion и создав отдельную запись в конфигурации мастера:
master/top.sls
base:
'roles:local-minion':
- match: grain
- local-minion-state
Суть способа пред. генерации паролей заключается в том, чтобы создать jinja шаблон pillar файла с паролем(-лями) примерно такого вида:
master/files/some-srv-password.sls.jinja2
some-srv:
password: '{{salt['random.get_str'](30)}}'
тут используется ф-ция get_str модуля random.
Следующим шагом будет описание стейта для локального миниона, который генерирует pillar файл с паролями.
master/local-minion-state.sls
passwords-file:
file.managed:
- name: /srv/salt/pillar/some-srv-password.sls # или другое место, где pillar файлы могут быть считаны мастером
- source: salt://files/some-srv-password.sls.jinja2
- template: jinja
После этого, перед применением стейтов зависящих от наличия пред. генерированных паролей, запускаем описанный стейт:
~# salt-call --local state.sls local-minion-state # masterless
or
~# salt -C 'G@roles:local-minion' state.sls local-minion-state
После исполнения стейта, получим pillar файл содержащий сгенерированный пароль. Для его использования выполним include в другом pillar файле:
pillar/some-srv.sls
include:
- some-srv-password
some-srv:
username: Fred
. . .
В итоге, при запросе salt 'minion-with-some-srv-pillar-connected' pillar.items получим примерно такое:
pillar:
. . .
some-srv:
. . .
username:
Fred
password:
AoEK8u4Uvo_r9MKtooSUxZV1Y_DLoy
затем доступ к данным пароля можно получить простым вызовом salt['pillar.get']('some-srv:password').
Заключение.
Из-за достаточно большой гибкости системы SaltStack решение этой задачи скорее всего не ограничивается только лишь 3-мя способами описанными в статье, — вполне возможно, что Вы придумаете не менее продуктивный и удобный способ.
В любом случае — надеюсь описанное в статье пригодится начинающим и не только пользователям SaltStack. Удачи!