Intro

Salt SSH allows you to execute commands and apply state to minions without having to install a salt-minion . The only requirement is for the minion to have python installed unless using the -r option to execute raw commands.

For reference the following software will be used in this post.

  • salt-ssh - 2018.3.1 (Oxygen)
  • Ubuntu (host) - 16.04
  • Debian (guest) - 9.4

Installation

Create and change into a working directory named salt-ssh .

cmd
mkdir /home/bradmin/salt-ssh && cd /home/bradmin/salt-ssh

I will use pipenv to manage a virtual environment and the installation of salt-ssh . If you are not using pipenv you can use pip with a virtual environment to install salt-ssh .

cmd
pipenv install salt-ssh

Activate the virtual environment.

cmd
pipenv shell

Directories

By default Salt expects its configuration files to be located in the /etc/salt directory. I am running Salt SSH as a non-root user so there are a number of directories that need to be created which are writable for my user.

cmd
mkdir -p {config,salt/{files,templates,states,pillar,formulas,pki/master,logs}}

# Directory Structure

/home/bradmin/salt-ssh
├── config
└── salt
    ├── files
    ├── formulas
    ├── logs
    ├── pillar
    ├── pki
    │   └── master
    ├── states
    └── templates

Config

The master config file has the same declarations that you would define when using Salt in master mode. Create a master config file with the following contents that points Salt SSH to the location of the previously created directories.

file
# salt-ssh/config/master

file_roots:
  base:
    - "/home/bradmin/salt-ssh/salt"

cachedir: "/home/bradmin/salt-ssh/salt/cache"

pki_dir: "/home/bradmin/salt-ssh/salt/pki/master"

Roster

The roster file is used to define remote minions and their connection parameters. I am using Vagrant for this lab so I will reuse the Vagrant user credentials. Create a roster file with the following contents.

file
# salt-ssh/config/roster

minion:
  host: "192.168.121.117"
  user: "vagrant"
  priv: "~/.vagrant.d/insecure_private_key"

Saltfile

The Saltfile allows you to set command line configuration option in a file instead of declaring them at runtime. Create a Saltfile with the following contents.

file
# salt-ssh/Saltfile

salt-ssh:
  config_dir: "/home/bradmin/salt-ssh/salt/config"
  roster_file: "/home/bradmin/salt-ssh/salt/config/roster"
  ssh_log_file: "/home/bradmin/salt-ssh/salt/logs/salt-ssh-log.txt"
  log_file: "/home/bradmin/salt-ssh/salt/logs/salt-log.txt"

For reference the final directory structure should look like the following.

cmd
# Directory Structure

/home/bradmin/salt-ssh
├── config
│   ├── master
│   └── roster
├── salt
│   ├── cache
│   ├── files
│   ├── formulas
│   ├── logs
│   ├── pillar
│   ├── pki
│   │   └── master
│   ├── state
│   └── templates
└── Saltfile

Testing

With the base configuration done, lest run a few tests. Salt SSH is controlled using the salt-ssh command. Aside from that you can use the same command line options that are available with the regular salt command.

cmd
salt-ssh '*' test.ping

# output

minion:
    True
Note
The first time you execute salt-ssh it will create SSH keys. This makes the execution time take longer than normal but subsequent runs are much faster. You may also need to accept the minions SSH key fingerprint. For more details see here.

If you successfully connected lets try install a package.

cmd
salt-ssh '*' pkg.install cowsay --sudo

# output

minion:
    ----------
    cowsay:
        ----------
        new:
            3.03+dfsg2-3
        old:
    cowsay-off:
        ----------
        new:
            3.03+dfsg2-3
        old:

Alright as a final test, lets execute a command on the minion.

cmd
salt-ssh '*' cmd.run 'cowsay im a salty moo cow'

# output

minion:
     ____________________
    < im a salty moo cow >
     --------------------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||

Troubleshooting

Most of the issues I ran into related to running Salt as a non-root users. You can run salt-ssh with the -l debug flag to get a more detailed look at the execution and errors if any.

cmd
salt-ssh '*' cmd.run 'df -h' -l debug

# output

[INFO    ] Loading Saltfile from '/home/bradmin/salt-ssh/Saltfile'
[DEBUG   ] Reading configuration from /home/bradmin/salt-ssh/Saltfile
[DEBUG   ] Reading configuration from /home/bradmin/salt-ssh/config/master
[DEBUG   ] Configuration file path: /home/bradmin/salt-ssh/config/master
[WARNING ] Insecure logging configuration detected! Sensitive data may be logged.
[DEBUG   ] LazyLoaded flat.targets
[DEBUG   ] LazyLoaded jinja.render
[DEBUG   ] LazyLoaded yaml.render
[DEBUG   ] compile template: ./config/roster
[DEBUG   ] Jinja search path: ['/home/bradmin/salt-ssh/salt/cache/files/base']
[DEBUG   ] LazyLoaded roots.envs
[DEBUG   ] Could not LazyLoad roots.init: 'roots.init' is not available.
[DEBUG   ] Updating roots fileserver cache
[PROFILE ] Time (in seconds) to render './config/roster' using 'jinja' renderer: 0.04327249526977539
[DEBUG   ] Rendered data from file: ./config/roster:
minion:
  host: "192.168.121.117"
  user: "vagrant"
  priv: "~/.vagrant.d/insecure_private_key"

[DEBUG   ] Results of YAML rendering:
OrderedDict([('test', OrderedDict([('host', '192.168.121.117'), ('user', 'vagrant'), ('priv', '~/.vagrant.d/insecure_private_key')]))])
[PROFILE ] Time (in seconds) to render './config/roster' using 'yaml' renderer: 0.0015110969543457031
[DEBUG   ] Matched minions: {'test': {'host': '192.168.121.117', 'user': 'vagrant', 'priv': '~/.vagrant.d/insecure_private_key'}}
[DEBUG   ] LazyLoaded roots.envs
[DEBUG   ] Could not LazyLoad roots.init: 'roots.init' is not available.
[DEBUG   ] Updating roots fileserver cache
[DEBUG   ] LazyLoaded local_cache.prep_jid
[DEBUG   ] Adding minions for job 20180616115608058884: ['minion']
[DEBUG   ] Could not LazyLoad cmd.run: 'cmd.run' is not available.
[DEBUG   ] Performing shimmed, blocking command as follows:
cmd.run df -h
[DEBUG   ] Executed SHIM command. Command logged to TRACE
[DEBUG   ] Child Forked! PID: 27215  STDOUT_FD: 10  STDERR_FD: 12
[DEBUG   ] VT: Salt-SSH SHIM Terminal Command executed. Logged to TRACE
[DEBUG   ] RETCODE 192.168.121.117: 0
[DEBUG   ] LazyLoaded nested.output
minion:
    Filesystem      Size  Used Avail Use% Mounted on
    udev            2.0G     0  2.0G   0% /dev
    tmpfs           396M  5.4M  391M   2% /run
    /dev/vda1       9.2G  1.4G  7.3G  17% /
    tmpfs           2.0G     0  2.0G   0% /dev/shm
    tmpfs           5.0M     0  5.0M   0% /run/lock
    tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
    tmpfs           396M     0  396M   0% /run/user/1000

Outro

Salt SSH is a nice alternative for minions where it is not possible and/or convenient to install a salt-minion . Common uses for running Salt SSH include managing IOT devices and bootstrapping minions with Salt to manage them in master mode.

# salt