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
Create Credentials For The Minions To Connect With
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.
- This causes Mongo to create the database.
- 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.
Minion Pre-Requisites
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
Conf File
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.
Grains
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:
Pillar
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-minions
database. You should see a collection called saltResults
. In that collection, you should see the result of the test.ping
issued on your minion.