SaltStack Configuration with Python — Core Concepts

What Salt does differently

All configuration management tools solve the same problem: keeping servers in a known, consistent state. Salt’s distinguishing features are speed and real-time communication.

While Ansible connects to servers via SSH on demand, Salt maintains persistent connections through a message bus. This architectural choice means Salt can:

  • Execute commands on 10,000 servers in under 5 seconds
  • React to events in real time (file changed, service crashed, disk full)
  • Stream data from minions continuously, not just during scheduled runs

VMware acquired SaltStack in 2020, and it now integrates with the broader VMware infrastructure management ecosystem.

Architecture

Salt Master — the central control server. Stores configuration, authenticates minions, and sends commands.

Salt Minion — a lightweight agent installed on managed servers. Maintains a ZeroMQ connection to the master and executes commands locally.

ZeroMQ — the messaging library (written in C with Python bindings) that handles communication. It provides pub/sub messaging for broadcasts and request/reply for targeted commands.

Pillar — secure per-minion data (passwords, API keys, per-host settings). Data is encrypted in transit and only the intended minion can access its pillar.

Grains — static system information (OS, CPU, memory, IP addresses). Similar to Ansible facts but always available without a gathering step.

States: the configuration language

Salt states describe the desired system configuration in YAML (called SLS files):

# /srv/salt/webserver/init.sls
nginx:
  pkg.installed: []
  service.running:
    - enable: True
    - watch:
      - file: /etc/nginx/nginx.conf

/etc/nginx/nginx.conf:
  file.managed:
    - source: salt://webserver/files/nginx.conf
    - template: jinja
    - user: root
    - mode: 644

This ensures Nginx is installed, the config file matches the template, and the service restarts when the config changes. States are idempotent — running them repeatedly is safe.

The Python connection

Salt’s Python roots run deeper than most tools:

Execution modules are Python functions callable from any minion. Salt ships with hundreds, and writing custom ones is straightforward:

# /srv/salt/_modules/myapp.py
def health_check(port=8000):
    """Check if the application is responding."""
    import requests
    try:
        resp = requests.get(f"http://localhost:{port}/health", timeout=5)
        return {"healthy": resp.status_code == 200, "status": resp.status_code}
    except requests.RequestException as e:
        return {"healthy": False, "error": str(e)}

Call it from the command line: salt '*' myapp.health_check port=8080

State modules define new state types. Returner modules send execution results to databases or monitoring systems. Pillar modules pull secret data from external sources like Vault or AWS Secrets Manager. All are Python.

The Salt API exposes Salt functionality over HTTP, letting web applications and dashboards trigger Salt operations programmatically.

Targeting servers

Salt’s targeting is powerful and flexible:

  • Glob: salt 'web*' state.apply — all servers whose name starts with “web”
  • Grain: salt -G 'os:Ubuntu' pkg.upgrade — all Ubuntu servers
  • Pillar: salt -I 'role:database' state.apply db — servers with a specific pillar value
  • Compound: salt -C 'G@os:CentOS and web*' test.ping — combining criteria
  • Nodegroup: predefined groups in the master config

This targeting system means you can run commands against precisely the servers you need without maintaining separate inventory files.

Common misconception

Many people think Salt requires more setup than Ansible because of the master-minion architecture. While Salt does need initial agent installation, tools like salt-ssh provide an agentless mode similar to Ansible. And once agents are installed, the persistent connection model pays for itself through faster execution and real-time event-driven automation.

When Salt fits best

Salt excels when you manage hundreds or thousands of servers, need real-time reactions to infrastructure events, or want sub-second command execution across your fleet. For smaller environments (under 50 servers) with infrequent changes, Ansible’s simpler setup may be more practical.

The one thing to remember: Salt’s persistent Python agents and ZeroMQ messaging give it speed and real-time capabilities that make it the go-to choice for managing large server fleets.

pythonsaltstackconfigurationdevops

See Also