Leveraging Configuration Management

10.2. Leveraging Configuration Management

With the ability to install Kali on multiple computers very quickly, you will need some help in managing those machines post-installation. You can leverage configuration management tools to manage machines or configure replacement computers to any desired state.

Kali Linux contains many popular configuration management tools that you might want to use (ansible, chef, puppet, saltstack, etc.) but in this section, we will only cover SaltStack.

https://saltstack.com

10.2.1. Setting Up SaltStack

SaltStack is a centralized configuration management service: a salt master manages many salt minions. You should install the salt-master package on a server that is reachable by all the hosts that you want to manage and salt-minion on the hosts that you wish to manage. Each minion must be told where to find their master. Simply edit /etc/salt/minion and set the master key to the DNS name (or IP address) of the Salt master. Note that Salt uses YAML as format for its configuration files.

Each minion has a unique identifier stored in /etc/salt/minion_id, which defaults to its hostname. This minion identifier will be used in the configuration rules and as such, it is important to set it properly before the minion opens its connection to the master:

When the salt-minion service is running, it will try to connect to the Salt master to exchange some cryptographic keys. On the master side, you have to accept the key that the minion is using to identify itself to let the connection proceed. Subsequent connections will be automatic:

10.2.2. Executing Commands on Minions

As soon as minions are connected, you can execute commands on them from the master:

This command asks all minions (the '*' is a wildcard targeting all minions) to execute the ping function from the test execution module. This function returns a True value on success and is a simple way to ensure that the connection is working between the master and the various minions.

You can also target a specific minion by giving its identifier in the first parameter, or possibly a subset of minions by using a less-generic wildcard (such as '*-scratch' or 'kali-*'). Here is an example of how to execute an arbitrary shell command on the kali-scratch minion:

Salt Module Reference


There are many execution modules available for all sorts of use cases. We won't cover them all here, but the full list is available at https://docs.saltstack.com/en/latest/ref/modules/all/index.html. You can also obtain a description of all the execution modules and their available functions on a given minion with the salt minion sys.doc command. Running this command returns a very long list of functions, but you can filter the list by passing the name of a function or module prefixed by its parent module as a parameter:

One of the most useful modules is pkg, which is a package manager abstraction relying on the appropriate package manager for the system (apt-get for Debian and its derivatives like Kali). The pkg.refresh_dbcommand updates the package list (that is, it performs apt-get update) while pkg.upgrade installs all the available updates (it performs apt-get upgrade or apt-get dist-upgrade, depending on the options received). The pkg.list_upgrades command lists the pending upgrade operations (that would be performed by the pkg.upgrade dist_upgrade=True command).

The service module is an abstraction of the service manager (systemd in the case of Kali), which lets you perform all the usual systemctl operations: service.enable, service.disable, service.start, service.stop, service.restart, and service.reload:

As a more concrete sample, you could easily set up a distributed Nmap scan with dnmap. After having installed the package on all the minions, you start the server in a first terminal:

Assuming that the server IP is 1.2.3.4, you can next tell all minions to start a client process that connects to the server:

Note that the example uses cmd.run_bg to run the dnmap_client command in the background. Don't wait until it finishes, since it is a long-running process. Unfortunately, it doesn't kill itself properly when you interrupt the server so you might have to clean it up:

10.2.3. Salt States and Other Features

While remote execution is an important building block, it is only a tiny fraction of what SaltStack can do.

When setting up a new machine, you often run many commands and tests to determine the details of the system prior to installation. These operations can be formalized in re-usable configuration templates called state files. The operations described in state files can then be performed with a single state.apply salt command.

To save some time, you can rely on many ready-to-use state files that have been created by the community and which are distributed in "Salt formulas":

https://docs.saltstack.com/en/latest/topics/development/conventions/formulas.html

There are many other features that can be combined:

  • Scheduled execution of actions
  • Defining actions in response to events triggered by minions
  • Collecting data out of minions
  • Orchestration of a sequence of operations across multiple minions
  • Applying states over SSH without installing the salt-minion service
  • Provisioning systems on cloud infrastructures and bringing them under management
  • And more

SaltStack is quite vast and we can't possibly cover all the features here. In fact, there are books dedicated entirely to SaltStack and the online documentation is very extensive as well. Check it out if you want to learn more about its features:

https://docs.saltstack.com/en/latest/

If you manage a significant number of machines, you would be well advised to learn more about SaltStack as you can save a significant amount of time when deploying new machines and you will be able to maintain a coherent configuration throughout your network.

To give you a taste of what it looks like to work with state files, we will cover a simple example: how to enable the APT repository and install a package that you create in Section 10.3.3, "Creating a Package Repository for APT" and Section 10.3.2, "Creating Configuration Packages". You will also register a SSH key in root's account so that you can login remotely in case of problems.

By default, state files are stored in /srv/salt on the master; they are YAML structured files with a .slsextension. Just like for running commands, applying a state relies on many state modules:

https://docs.saltstack.com/en/latest/topics/tutorials/starting_states.html

https://docs.saltstack.com/en/latest/ref/states/all/

Your /srv/salt/offsec.sls file will call three of those modules:

The offsec_repository state relies on the pkgrepo state module. The example uses the managed function in that state module to register a package repository. With the key_url attribute, you let salt know that the (ASCII armored) GPG key required to verify the repository's signature can be fetched from /srv/salt/offsec-apt-key.asc on the salt master. The require_in attribute ensures that this state is processed before the offsec-defaults, since the latter needs the repository correctly configured to be able to install the package.

The offsec-defaults state installs the package of the same name. This shows that the name of the key is often an important value for states, although it can always be overridden with a name attribute (as done for the former state). For simple-cases like this one, this is both readable and concise.

The last state (ssh_key_for_root) adds the SSH key given in the name attribute to /root/.ssh/authorized_keys (the target user is set in the user attribute). Note that we have shortened the key for readability here, but you should put the full key in the name attribute.

This state file can next be applied to a given minion:

It can also be permanently associated to the minion by recording it in the /srv/salt/top.sls file, which is used by the state.highstate command to apply all relevant states in a single pass: