Introduction

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.


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.


pipenv install salt-ssh
            

Activate the virtual environment.


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.


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.


# 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.


# 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.


# 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.


# 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.


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.


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.


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.


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
            

Summary

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.

Links

https://docs.saltstack.com/en/getstarted/ssh/index.html
https://docs.saltstack.com/en/latest/topics/ssh/






















Published: 2018-06-16