Posts about saltstack

Securing Salt file_roots

My only real problem with Salt vs Puppet is its security model for files stored in the manifest. Puppet's fileserver supports per-node export configuration, allowing for node-private file distribution. Salt, on the other hand, exposes all files to all nodes at all times.

How Puppet does it

# fileserver.conf
[mount_point]
path /path/to/files
allow *.example.com
deny *.wireless.example.com

[private]
path /data/private/%h
allow *

How salt could do it

# file_roots.sls
file_roots:
  base:
    - /srv/salt
    - /srv/salt-example.com:
      - allow: *.example.com
      - deny: *.wireless.example.com
    - 
  dev:
    - /srv/salt/dev/services
    - /srv/salt/dev/states
  prod:
    - /srv/salt/prod/services
    - /srv/salt/prod/states

Proposal

file_roots:
  base:
    - /srv/salt
  *.example.com:
    - /srv/salt-example.com

A New Firewall Salt State

My evaluation of Salt Stack is going pretty well. I've moved my main vps over to it with no ill effect, and was able to transcribe its Puppet manifest almost in its entirety. In many instances, I think the Salt version is more readable, and feels lighter than the Puppet version.

One glaring hole, though, is Salt's support for firewall configuration. I was using the Puppet Labs firewall module to maintain iptables rules for my vps. That worked pretty well; but all Salt has right now is the ability to append new rules to a chain. The existing iptables state is documented at-risk for deprecation, too, so it's a bad place to start.

It is expected that this state module, and other system-specific firewall states, may at some point be deprecated in favor of a more generic firewall state.

(Salt does have good support for iptables at the functional layer; it's just the configuration management part that's lacking.)

Since the firewall module I used before worked well enough, and I have a bunch of config based on it already, I've started reimplementing its interface in a Salt state module.

"100 salt-master":
  firewall_rule:
    - managed
    - protocol: tcp
    - ports: 4505:4506
    - action: accept

I've found developing a Salt state to be a pretty simple process so far. I really like how Salt's effective layers cleanly separate between functionality, state management, and configuration. (My firewall state makes liberal use of the existing iptables module, for example.)

I've just published the module so far on github. This module at least recognizes that my existing config exists, and would be able to rebuild it in the proper order (sorted lexically by comment) if necessary. There's a lot of functionality missing, but it's a place to start. If anyone else uses it, that will just be an excuse to make it better!

Discovering Salt Stack

I've been a pretty stalwart Puppet user since I first discovered it in 2009. At that time, my choices were, as I saw them, between the brand-new cfengine3, the I've-seen-how-the-sausage-is-made bcfg2, and Puppet. Of those choices, Puppet seemed like the best choice.

In particular, I liked Puppet's "defined state" style of configuration management, and how simple it was to describe dependencies between the various packages, files, and services to be configured.

Like I said, I've been using Puppet happily for the past 4 years; but now, I think I've been swayed by Salt Stack.

I know I looked at salt stack before; but, at the time, I think I dismissed it as just "remote execution." Salt does, after all, start from a very different place than Puppet. At its most simple, it is a mechanism for shipping Python functions to remote nodes and executing them. It seemed the very opposite of the idempotent state management that I was looking for.

But now that I've taken the time to look deeper into the documentation (or, perhaps, now that the project has grown further) I've found Salt Stack States: the state enforcement configuration management system I was looking for; and with a trivial-to-setup remote execution layer underneath it.

Salt is based on 0MQ. I don't know much about message queues; but I do know that I could never get ActiveMQ working for use with Puppet's MCollective. After only 30 minutes of hacking, I had Salt, with 0MQ, running on two OS X machines and two Debian machines, all taking to the same master, each from behind its own form of inconveniently private network.

$ sudo salt '*' test.ping
ln1.civilfritz.net:
    True
Jonathons-MacBook-Pro.local:
    True
numfar.civilfritz.net:
    True
dabade.civilfritz.net:
    True

Glorious.

Some other things that I like about Salt:

  • States are defined in YAML, so there's no proprietary (cough poorly defined cough) language to maintain.
  • The remote execution layer and state module layer help keep executable code separate from state definitions.
  • Key management is a bit less foolish. (It shows you what you're about to sign before you sign it.)

Of course, no new technology arrives without the pain of a legacy conversion. I have a lot of time and effort invested into the Puppet manifests that drive ln1.civilfritz.net; but converting them to Salt Stack States is serving as a pretty good exercise for evaluating whether I really prefer Salt to Puppet.

I've already discovered a few things I don't like, of course:

  • The abstraction of the underlying Python implementation is a bit thin. This is sometimes a good thing, as it's easier to see how a state definition maps to individual function calls; but it also means that error messages sometimes require an understanding of Python. Sometimes you even get full tracebacks.
  • Defined states don't seem to understand the correlation between uid and uidNumber. In Puppet I started specifying group ownership as 0 when I discovered that AIX uses the gid system rather than root. In Salt, this appears to try to reassign the group ownership every time.
  • All hosts in a Salt config have access to all of the files in the master.
  • YAML formatting can be a bit wonky. (Why are arguments lists of dictionaries? Why is the function being called in the same list as its arguments?)
  • No good firewall (iptables) configuration support. The iptables module isn't even present in the version of Salt I have; but the documentation warns that even it is likely to be deprecated in the future.

That said, I can't ignore the fact that, since Salt happens to be written in Python, I might actually be able to contribute to this project. I've already done some grepping around in the source code, and it seems immediately approachable. Enhancing the roots fileserver, for example, to provide node-restricted access to files, shouldn't be too bad. I might even be able to port Puppet Lab's firewall module from Ruby to Python for use as a set of Salt modules.

Time will tell, I suppose. For now, the migration continues.