Salt beacons and reactors explained, with safe examples
Beacons let a Salt minion report what happens on its machine; reactors let the master act on those events. How they work, a working example, the security trap most examples fall into, and when to use a console instead.
Salt has an event bus. Every job, every return, and every minion start is an event on it, and you can add your own. Two features turn that bus into automation:
- Beacons run on the minion. Each one watches something on the machine (a service, a file, disk usage, logins) and sends an event to the master when it changes.
- Reactors run on the master. A reactor matches event tags and runs a job in response.
Together they let a machine report a problem and the master fix it in seconds, with no polling and no inbound connection to the machine.
A beacon: watch a service#
Beacons are configured in the minion's configuration or in pillar. This watches nginx and reports only when its state changes:
beacons:
service:
- services:
nginx:
onchangeonly: True
- interval: 10When nginx stops, the minion fires an event tagged salt/beacon/<minion id>/service/nginx with data that says it is no longer running.
A reactor: restart it#
On the master, map the tag to a reactor file:
reactor:
- 'salt/beacon/*/service/*':
- /srv/salt/reactor/restart.slsA minimal reactor that restarts the service on the machine that reported it:
{% set mid = data['id'] %}
{% set svc = data['service_name'] %}
restart_service:
local.service.start:
- tgt: {{ mid }}
- args:
- name: {{ svc }}It works. It is also the example most people copy, and it has a security problem.
The trap: trusting what the minion sent#
Everything in a beacon event comes from the minion. A compromised or misbehaving minion can send any tag and any data. The minimal reactor above trusts both:
tgtcomes from the event, so a minion can name another machine, or a glob such as*.svccomes from the event, so a minion can name any service to start, anywhere it can target.
A safer reactor:
- Targets only the minion named in the tag, and checks that it matches the event's own
id. - Uses an exact list target (
tgt_type: list), never a glob. - Checks names against a strict pattern (letters, digits, dots, dashes).
- Acts only on services an admin chose to watch, read from configuration the minion cannot change, not from the event.
- Emits values as quoted strings, so nothing in the event can change the structure of the generated YAML.
Add rate limits too: a service that flaps should not flood your logs or your pager.
When to use a console instead#
Beacons and reactors are worth learning, and for a handful of rules they are fine by hand. Once you have many rules, several people changing them, and auditors asking what fired when, a console that manages them for you saves time.
Gardience turns the common cases into event rules with no YAML: restart a stopped service, warn when a disk fills, and apply a saved state to a machine the first time it joins. It writes the beacon configuration and a hardened reactor for you, checks every event as described above, rate-limits the audit entries, and records every firing in a tamper-evident audit log. See self-healing servers.
Questions#
Do beacons work on Windows?#
Many do, including the service and disk usage beacons. Check each beacon's documentation for platform support.
Do beacons need extra Python packages?#
Some do (for example, inotify-based file watching on Linux). The service and disk usage beacons work with a standard Salt install.
How fast does a reactor respond?#
As fast as the beacon interval plus a moment for the job: with a 10-second interval, a stopped service is usually restarted within seconds.
Try Gardience on your own machines
One supported console for Windows and Linux on open-source Salt: patching, a scored STIG/CIS-aligned baseline, drift repair, event-driven automation, two-person approval and a tamper-evident audit log. Flat yearly pricing, not per node.
Free 90-day trial (25 nodes)See it work Compare