Saltstack configuration

From wikinotes


salt-renderers: gpg


file description
macos:     /usr/local/etc/saltstack/master  # NOT OFFICIALLY SUPPORTED
bsd:       /usr/local/etc/salt/master
linux:     /etc/salt/master
macos:     /opt/local/etc/salt/master
win:       None
configure the salt-master
macos:     /usr/local/etc/saltstack/minion
bsd:       /usr/local/etc/salt/minion
linux:     /etc/salt/minion
macos:     /opt/local/etc/salt/minion
win:       C:/salt/conf/minion
               # OR
           C:/ProgramData/Salt Project/Salt/conf
configure the salt-minion
macos:     /usr/local/etc/saltstack/gpgkeys/
bsd:       /usr/local/etc/salt/gpgkeys/
macos:     /opt/local/etc/salt/gpgkeys/
linux:     /etc/salt/gpgkeys/
win:       None
salt-master's gpg home-directory (to encrypt/decrypt pillar entries)
bsd:       /usr/local/etc/salt/grains
linux:     /etc/salt/grains
macos:     /opt/local/etc/salt/grains
win:       C:/salt/conf/grains
define custom grains for the managed server.
salt communication ports



The saltmaster is a central server that you will communicate with to receive instructions. The master contains your statefiles, and your encrypted data (passwords, configurations, etc).

Salt lets you organize your statefiles and pillar into different environments. Generally they think of these in terms of base (production), dev (development) and anything else you may find you need. Since I'm working alone, I've been quite happy using simply base.

user: salt                 # user to run salt as

file_roots:                # root of salt-states and salt:// files
        - /srv/salt

pillar_roots:              # root of salt-pillar
        - /srv/pillar

Running as Non-Root

Saltmaster can be run as non-root, but make sure that all of it's files are accessible to the user it is configured to use:



Pillar Encryption

Configure gpg dir

You may need to verify/configure your gpg dir is set for salt.

# /usr/local/etc/salt/master

gpg_keydir: /usr/local/etc/salt/gpgkeys

Generate GPGkey

Your pillar is designed to store secret information like passwords, keys, etc. If you have any advantage of taking advantage of this, you should setup a gpg key to allow your pillar to store encrypted info.

create saltmaster's gpgkey

gpg --expert --gen-key --homedir /usr/local/etc/salt/gpgkeys

add saltmaster's public-key to your login user, so that it is easy to encrypt information for the saltmaster. Note that unless you add the private key, your user will only be able to encrypt information, and not decrypt it.

# export saltmaster's gpgkey
gpg --armor --homedir /usr/local/etc/salt/gpgkeys  \
    --armor --export saltmaster  /usr/local/etc/salt/

# import gpgkey into your user
# (imports gpgkey into current user's ~/.gnupg)
gpg --import /usr/local/etc/salt/

# trust the key by issuing the following
# command, and then choosing the options
# that follow in the interactive prompt.
gpg --edit saltmaster
   # trust
   # 5
   # quit

Backup GPGKey

Export your saltmaster private-key, and back this up somewhere safe. Otherwise your pillar will be useless when you rebuild your machine.

gpg --armor --homedir /usr/local/etc/salt/gpgkeys \
    --armor --export-secret-keys \
    saltmaster > /usr/local/salt/gpgkeys/saltmaster.prv

You can add this key (public/private) to a user if you need to (although this generally isn't necessary).

# user you are importing keys into
gpg --allow-secret-key-import --import /usr/local/salt/gpgkeys/saltmaster.prv

# now clear the passphrase that was automatically set during import
gpg --edit-key saltmaster
    > <existing passphrase>
    > <enter>
    > <enter>
    > <quit>


Encrypt as your login-user

# encrypt the text 'mypassword', and write to 'encrypted_password.gpg'
echo -n "mypassword" \
    | gpg --armor --encrypt -r saltmaster \
    > encrypted_password.gpg

Decrypt using saltmaster

# decrypt the encrypted fake-password
cat encrypted_password.gpg \
    | gpg --homedir /usr/local/etc/salt/gpgkeys

Adding to Pillar

Make sure to add the shebang #!yaml|gpg. This indicates the order that the file should be parsed (first with yaml, then with gpg).

#### /usr/local/etc/salt/pillars/passwd/mysql/somehost.sls

    root: |
        -----BEGIN PGP MESSAGE-----

        -----END PGP MESSAGE-----

    user: |
        -----BEGIN PGP MESSAGE-----

        -----END PGP MESSAGE-----


After you've completed the above, you can check that the value is properly being retrieved by one of your salt-minions.

From a host with access to a pillar entry:

sudo salt-call   pillar.get   passwd:mysql:root   # where passwd:mysql:root is a YAML dictionary address.

System Passwords


salted_password=$( python -c "import crypt,uuid; print( crypt.crypt( 'your-password',  '\$6\$;+ uuid.uuid4().hex ) )" )
echo -n "${salted_password}" | gpg --armor --encrypt -r saltmaster
# outputs encrypted, salted password


# simply use a plaintext password.


The minion is the worker process. If your machine is targeted on the master, it communicates with the salt-minion. The salt-minion can also request an update from the master.


minion with master

id:     my-minion       # handle assigned to your machine. defaults to hostname
master:   # the ip-address of your salt-master.

masterless minion

file_client: local

file_roots:               # root-location of salt-states, and salt://
    - /srv/salt/states
pillar_roots:             # root-location of salt-pillar files
    - /srv/salt/pillars

You can now apply states using

salt-call --local state.highstate

pre-authenticated keys

If you are provisioning a server, you can generate and store pre-authenticated minion keys. This way, you never need to accept keys on the master.


custom grains

Grains are facts about the system being managed by the salt-minion. Most of these are obtained automatically, but you can add your own custom grains to a minion if you find you need to.