SaltStack: Pre-Generating Passwords for Use in Services
- Tutorial
What is the article about?
A short article on how to generate the passwords necessary for a variety of services automatically installed using SaltStack.
Difficulty generating passwords.
Very often it is necessary to automatically install services or applications that require a password to access some of its parts (for example, to a web interface or to manage its API). No less often it is necessary to configure database users, which will then be used in services using these databases, etc.
A typical problem is the generation of passwords for all such cases. There are several solutions to this problem:
1. Prescribe passwords manually in the pillar file
pillar / passwords.sls
service1:
web-access-password: '9KTE2aN11GYOJmZGOoqV'
db-access-password: '2pGbSlSFkHPY22TwqUus'
Well, then in any other pillar or in the story use the specified passwords to generate accesses.
Everything seems to be normal and understandable, but there is one thing but - if you distribute the state using the specified pillar, then the passwords will be saved in the same unchanged form. Not only that, even all servers of the same type for which this state will be applied will have the same password. Naturally, there is no point in explaining what this may threaten from the point of view of information security.
2. Generate passwords using SaltStack.
There is one interesting feature in SaltStack in the grains get_or_set_hash module , which can generate a password for later use of a certain grain. Passwords are quite complex (due to the default character set that can be overridden when called), it’s easy to use them in states (just read the corresponding grain from the minion). The only thing worth remembering is that password generation occurs only upon the first call of this function (and the password itself is placed in the / etc / salt / grains file), all subsequent ones will simply read this graine from the file as if salt [ 'grains.get'] ('stored-password-grain-name') .
One of the most significant drawbacks of this method is the inability to read the passwords generated in this way in pillar files, which is often useful when using various formulas ( SaltStack Formulas ).
3. Prev password generation in pillar file.
Another way that I use often enough is to pre-generate passwords with Jinja2.
In the general case, for prev. Generation uses minion installed on the same machine as Salt Master. If you don’t want to connect such a minion to the master itself, you can use the masterless configuration, but I prefer to use the minion connected to the master, marking it grains: roles: local-minion and creating a separate entry in the master configuration:
master / top.sls
base:
'roles:local-minion':
- match: grain
- local-minion-state
The essence of the method before. password generation is to create a jinja template for a pillar file with password (s) like this:
master / files / some-srv-password.sls.jinja2
some-srv:
password: '{{salt['random.get_str'](30)}}'
here the get_str function of the random module is used .
The next step is to describe the state for the local minion, which generates a pillar file with passwords.
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
After that, before applying the states depending on the presence of pre. generated passwords, run the described state:
~# salt-call --local state.sls local-minion-state # masterless
or
~# salt -C 'G@roles:local-minion' state.sls local-minion-state
After executing the state, we get a pillar file containing the generated password. To use it, execute include in another pillar file:
pillar / some-srv.sls
include:
- some-srv-password
some-srv:
username: Fred
. . .
As a result, when querying salt 'minion-with-some-srv-pillar-connected' pillar.items, we get something like this:
pillar:
. . .
some-srv:
. . .
username:
Fred
password:
AoEK8u4Uvo_r9MKtooSUxZV1Y_DLoy
then you can access the password data with a simple call to salt ['pillar.get'] ('some-srv: password') .
Conclusion
Due to the sufficiently large flexibility of the SaltStack system, the solution to this problem is most likely not limited to only 3 methods described in the article, it is quite possible that you will come up with a no less productive and convenient way.
In any case, I hope the description described in this article is useful to beginners and not only to SaltStack users. Good luck