Saltstack pillar

From wikinotes
Revision as of 12:11, 25 April 2019 by Will (talk | contribs) (→‎system passwords)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The pillar stores secret information that you may want to encrypt, and limit which machines have access to.

The pillar is also useful for altering the context of your statefiles. Sometimes you may find yourself wishing you could parametrize your statefiles. Using the pillar (and swapping out pillar values for different systems) you can make your states more dynamic.

For example, this is how I reuse the same statefile for a program, but use different ports on different servers.


Structure

files

Your pillar is a collection of YAML files where you can define variables, and their values. Add variables defined within one of these files to your pillar/top.sls file underneath a hostname, and that host will gain access to all of the variables defined within that file.

name description location
pillar-files .sls files under the pillar subdirectory are YAML files that let you define variables, and their values. {project}/pillar/*.sls
pillar/top.sls a special sls file that contains hostnames, and under each the path to a pillar-file. Adding a pillar-file to a hostname makes all of it's contained variables accessible to that host's salt-minion. {project}/pillar/top.sls

Example of a pillar/top.sls file:

base:                                  # the environment the pillar applies to
    '*':                               # apply to all hostnames
        - filesystem.backup.tarsnap    # includes keys defined in `{project}/pillar/filesystem/backup/tarsnap.sls`
        - passwd.service               # includes keys defined in `{project}/pillar/passwd/service.sls`

    'dev-*'                                   # apply to all hostnames with the prefix 'dev-'
        - progs.vm.virtualbox.guestadditions

format

The pillar is formatted as a nested dictionary. Beyond that, you can do just about anything. Personally, I have found the two practices to be particularly useful:

  • have your dictionary-key paths match the filesystem location of your pillar items (to help you find/change them)
  • define a base set of required_keys. You can override their values for specific machines, but this will allow your states to depend on the presence of a pillar entry.

Example of a pillarfile.

#!yaml|gpg

passwd:
    will: mypassword

encryption

See saltstack configuration for instructions.

system passwords

passwd/shadow have very specific requirements for how their passwords are stored. To generate a system password:

Linux/FreeBSD:

python   -c  "import crypt,uuid; print(crypt.crypt( 'YOURPASSWORD', crypt.mksalt(crypt.METHOD_MD5) ))"

Windows

# password entered as plaintext

NOTE:

crypt is unix-only, and depends on your system's crypt C library. You can use python passlib to produce password hashes from anywhere.

ext_pillar (databases, other)

ext_pillar docs https://docs.saltstack.com/en/latest/topics/development/external_pillars.html
ext_pillar postgres https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.postgres.html
ext_pillar mysql https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.mysql.html
ext_pillar sqlite https://docs.saltstack.com/en/latest/ref/pillar/all/salt.pillar.sqlite3.html

If your pillar's needs are more dynamic, or integrated into a system you can use various types of backends to produce youre pillar's output.

If using a traditional saltmaster setup, configuration goes into your /usr/local/etc/salt/master. If using a masterless setup, configuration goes into your /usr/local/etc/salt/minion.

CREATE TABLE users (
  id       INT, 
  first   TEXT,
  initial TEXT, 
  last    TEXT
);

INSERT INTO users (id, first, initial, last)
VALUES (1, 'will', 'j', 'pittman'),
       (2, 'alex', 'p', 'szeplaki');
# /usr/local/etc/salt/master

sqlite3:
    database: /var/tmp/test.db
    timeout:  5.0

ext_pillar:
    - sqlite3:
        MY_PEOPLE:
            query: 'SELECT id, first, last   FROM mytable   WHERE minion = ?'  # query MUST include '?', which is substituted with the minion name
            depth: 1
salt-call  pillar.get  MY_PEOPLE

# local:
#    -----------
#    1:
#        -----------
#        first: will
#        last:  pittman
#        -----------
#    2:
#        -----------
#        first: alex
#        last:  szeplaki
#        -----------

Using Pillar

refreshing pillar

Your pillar gets refreshed whenever a state is applied, but sometimes while testing keys on the commandline you'd like to refresh your pillar.

salt-call  saltutil.refresh_pillar

statefiles

Within statefiles, your pillar is exposed to jinja2.

#!stateconf

{% set my_password = pillar['passwd']['will'] %}

configfile template

You can apply your pillar as context to a configuration-file, enabling you to use both jinja AND your pillar.

I use this to more dynamically configure my sshd_config file.

./etc/ssh/sshd_config:
    file.managed:
        - source: salt://progs/netwk/openssh/files/sshd_config
        - template:
            - jinja

commandline

You can test your pillar values on the commandline, or even override pillar values while applying states to test new ones.

salt-call pillar.ls                     ## list all pillar items, accessible to this machine
salt-call pillar.get  passwd:will       ## query value of a specific pillar item.

salt-call  state.apply     my_state   \ ## manually supply pillar-values to override any
  pillar='{                           \	#  included automatically
      "ftpusername": "test",          \
      "ftppassword": "0ydyfww3giq8"   \
}'