Salt 101: A Beginner's Perspective

By Alex Rothman

September 30, 2019

As soon as my first day interning at EITR Technologies began, I could tell that Salt was something special. My boss, Nicholas Hughes, introduced it to me with such passion and respect that I was genuinely excited to learn all about it. Having just finished my sophomore year of college, I had no experience working with anything like the Salt platform because my coursework so far had consisted primarily of programming courses in Java, C, and Ruby. Salt would be my first real world step into the computer science industry and into Python.

Following Nick’s initial introduction to the platform, I knew I would need to research more into Salt to really make sure I understood what I would be doing. Luckily, there are plenty of online Salt tutorials for beginners that can be found with a simple Google search. SaltStack has published their own nice, short walkthrough that goes over the most important aspects of their platform and links to additional relevant documentations. The documentation provides a great way to examine the magnitude of Salt’s capabilities. All of those online articles refer to Salt differently, but the general consensus is that Salt is primarily used as a platform for automation, orchestration, infrastructure deployment, and configuration management. Salt is a very complex and sizable platform, which is why I have outlined features below that I believe are most important for a Salt beginner to understand.

The Basics

The most important thing to know about Salt is that it is open source software. This means that it is constantly improved upon and updated. If you think there is a feature missing or broken, you can easily fix it yourself or request it from a community member. Salt was designed with a remote execution engine that can swiftly and securely communicate between different systems via the ZeroMQ messaging bus. This communication structure allows Salt to efficiently distribute instructions, log events, and more. The default configuration consists of minions, which are client agents on remote systems that receive commands over the messaging bus from a Salt master. The Salt master serves as the brains of the operation and it is how a user can control any associated agents. The master can instruct the minion to do practically whatever the user chooses, whether it is simply printing the time or deploying advanced cloud infrastructure. The master is capable of targeting all or specific minions for certain tasks and can even perform those commands itself. A quick and easy way to get this configuration set up is to simply run SaltStack’s bootstrap script.

Salt States

Salt States are the core to the Salt configuration management system. A Salt State (written as an SLS, or SaLt State, file) is a representation of the intended end state of the system or application configuration being managed. By default, SLS files are written in YAML to make the configuration process even easier. The SLS files also allow for templating languages to be used. SLS files allow you to input any necessary data required for the configuration of an application or service. Some potential uses of Salt States include installing packages, configuring application and system settings, and ensuring that specific services are running. Below is an example Salt State.


    - channel: '#testchannel'
    - from_name: 'Salty'
    - message: 'Salt successfully sent a message on Slack!'
    - api_key: 'key_value'

The example above is a Salt State that posts a message in a Slack Channel called ‘#testchannel’ when applied. A Salt State is composed of multiple parts. Each SLS file must have at least one state declaration, which is a section of the state file that is made up of a unique ID, a state function, and any additional arguments that the function may require. The entire code above is composed of just one state declaration. The ID is a string that is used to identify the state declaration and is usually named after the function or the result of the function. The ID in the example above is ‘SlackMessage’. After the ID, a function must be specified along with the Salt Module that the function originates from. A Salt Function is the command that the Salt Master or Minion will be executing using the given arguments. In the above example ‘slack’ is the Salt Module and the function is ‘post_message’. The arguments for the function are ‘channel’, ‘from_name’, ‘message’, and ‘api_key’.


Pillar is an interface that allows Salt users to store configuration data within the Salt Master. The Salt Master is capable of distributing the data to the Salt minions. The data stored in Pillar can be anything, whether it is sensitive secrets or general data. Pillar data is stored in tree-like structures and is written inside of SLS files. The default source directory for Pillar is /srv/pillar. Pillar utilizes a top.sls file to specify to the Salt Master which minions or systems can access certain data. The following is an example top.sls file that allows for all minions to have access to the configs.sls pillar file and only allows a minion named ‘minion1’ to have access to the secrets.sls file.


    - config
    - secrets

Here is an example pillar file called secrets.sls which stores the usernames and passwords of multiple users.


  tim: password1
  ali: password2
  john: password3

Using Jinja templating, which is discussed in the next section, a user can input this data directly from the pillar file into a state file being applied by a minion.

Jinja Templating

Jinja is the default language for templating in SLS files. A templating language is a scripting language that gets embedded within another document in order to render it into another form. Users can leverage Salt to assist them in enforcing workflow control in state files with the help of loops, conditional statements, and more. In addition, users can access pillar data, minion configuration values, and execution modules. Additional documentation for Jinja and how to use it can be found here. The following is an example of how Jinja templating can be used in a Salt State. The state declaration will only be applied if the password retrieved from pillar for the user named john is equivalent to ‘password3’.


{%- set password = salt.pillar.get('users:john', ' ') %}
{%- if password == 'password3' %}
Install packages:
    - wget
    - curl
    - git
{% endif -%}


The Salt Reactor system is one of my favorite aspects of the platform. Any time Salt interacts with the system, whether it is via Salt-API calls, the Salt Master, Salt Minions, etc., an event is logged on the ZeroMQ event bus. Every event that is logged on the bus is given a tag, which can be used to access additional details and data regarding the event. The Reactor System can trigger actions, such as the application of a Salt State that will utilize the event data, based on the firing of a specific event or tag. The following code is an example of the reactor configuration file. If Salt creates any new cloud instance, then a file named response.sls would be applied on the system by a minion.


  - 'salt/cloud/*/created':
    - '/srv/reactor/response.sls'


The one thing I want to stress about my experience with Salt is that I never fully understood how important and useful all of its features were until I actually put them to use. I was shocked over how easy it was to create demonstration cloud infrastructure on Microsoft Azure using Salt. I was in awe watching the reactor system apply different states based upon internal or external conditions at that very moment. The ability to run a command and have your master and/or minions deploy orchestration or perform any necessary configuration is truly amazing.

I had the pleasure of spending this entire summer working with the open-source platform, and it really allowed me to utilize and expand upon my prior computer science knowledge. I went from having never heard of Salt to actually becoming a contributor to the project. Looking back now, I completely understand why Nick seemed so passionate about Salt.