Configuring Salt Minions to Return to Mongo

Overview

For a recent compliance project, we needed to start tracking when an instance became out of compliance and how soon the issue was remediated. The idea our team came up with was to kick off state.highstate test=true jobs every 15 minutes via cron, but to send the return data to a database. The information could be stored there and the dev team could whip up a simple GUI for use to view the changes between runs.

With that in mind, I needed to start sending state.highstate test=true returns, to a database. In this instance, we choose to use Mongo. So first thing, I needed a Mongo instance where I could store this data. Now as I’m just proving this out, I went with a docker container to start.

Basic Docker Setup

My docker compose file is based on the one found at https://hub.docker.com/_/mongo

With that written out on the docker host instance, execute docker-compose -f stack.yaml up.
This will bring up two containers. One is our Mongo database. The other is a Mongo-Express container, which is a basic web UI to interface with the Mongo database in the other container.

Minion Direct To Mongo

The next step is to create a user which the minions will use to connect to the mongo database.
On the docker host instance, execute the following:

docker exec -it mongo bash

That command connects to the Mongo container and opens a bash shell. Now lets connect through it to the mongo shell.

root@19ca06917037:/# mongosh

Now that we are in the Mongo shell, we need to create a new database and credentials for the minions to authenticate with when trying to store returns.

use salt-minions
db.createUser({user: "minion", pwd: "testpassword", roles: ["readWrite"]})

By “use”ing the database before issuing the command, we are doing a couple of different things.

  1. This causes Mongo to create the database.
  2. It tells Mongo that the credentials we are creating should use the salt-minions database as it’s authentication store. This is important as we could create the user in a different authentication store and it would be a different user even though both would have the same user name.

In order for a minion to return results to a Mongo database, it must be able to speak Mongo. To that end install the pymongo package onto the minions.

pip3 install pymongo

Make The Credentials Available To The Minions

To make the mongo configuration available to all minions, we can store the key/values in a file on each minion in the /etc/salt/minion.d directory. The file can be named anything, but should end with the file extension .conf. I named mine /etc/salt/minion.d/mongo.conf.

This file should look like:

mongo.db: salt-minions
mongo.host: mongo-hostname.yourdomain.com
mongo.port: 27017
mongo.user: minion
mongo.password: testpassword

Once the file is written, restart the salt-minion process so it will read the new config file.

Another way to pass the necessary configuration and credentials data is via grains.
On your master, in the _grains directory, create a new file mongo-grains.py.
For this example, I’ve made it as simple as I can:

Lastly, you can pass the same data through pillar as well. Create a pillar file and assign it via top.sls to any minions that need it.
The pillar should look like:

mongo:
db: salt-minions
host: mongo-hostname.yourdomain.com
port: 27017
user: minion
password: testpassword

Send Data To Mongo

With those steps out of the way, lets try to send some data to the Mongo database.
On the minion, execute:

salt-call test.ping --return mongo

Now, log into mongo-express and navigate to the salt-minionsdatabase. You should see a collection called saltResults. In that collection, you should see the result of the test.ping issued on your minion.

Climber, surfer, yogi, dad who does some IT on the side to get by.