How to configure Kensa once so daily scans need almost no flags
Configure Kensa's rules directory, policy variables, host inventory, and results database once so everyday check and remediate commands need almost no flags.

What you'll accomplish
Set Kensa up so your everyday check and remediate commands carry only a host
name. After this, Kensa finds its rules on its own, applies your organization's
policy values instead of the built-in defaults, knows your fleet from an inventory,
and writes results to a path you chose. No -r, no long --var lists, no repeated
flags.
The whole scheme rests on one directory Kensa auto-detects. Set that up first, everything else drops into it.
Before you start
- Kensa and its rules installed from hanalyx.com/download.
Install the
kensaandkensa-rulespackages together. - SSH access to your hosts. Kensa uses your system OpenSSH, so
~/.ssh/config,known_hosts, jump hosts, and your SSH agent all apply. - Your policy baseline in hand. Know the values your organization enforces (SSH
MaxAuthTries, password length, and so on). Kensa ships STIG-leaning defaults; you will override the ones that differ.
Step 1: let Kensa find its rules
Installing the kensa-rules package lands the rule corpus where Kensa looks by
default. Confirm a scan finds them with no -r flag:
kensa check -H web01.example.com -u admin --sudo
If that reports "No rules found," the rules package is not installed; install it, or
pass --rules-dir <path> explicitly. With the package in place you never pass -r
again.
Step 2: create the config directory Kensa auto-detects
Kensa looks for a configuration directory in this order and uses the first one that exists:
--config-dir <path>(explicit flag)$KENSA_CONFIG_DIR$XDG_CONFIG_HOME/kensa~/.config/kensa/etc/kensa
For personal daily work, ~/.config/kensa is the sweet spot: no flag, no root.
mkdir -p ~/.config/kensa/conf.d
Anything you put here is picked up automatically. For a shared host where every
operator should get the same policy, use /etc/kensa instead (same layout).
Step 3: set your policy variables once
About thirty rules in the corpus are templated with variables like
ssh_max_auth_tries and pam_pwquality_minlen. Kensa ships built-in defaults for
all of them (STIG-leaning), so scans work out of the box. Where your policy differs,
override the value once in a file Kensa reads.
Create ~/.config/kensa/defaults.yml with only the keys you want to change:
variables: ssh_max_auth_tries: 3 pam_pwquality_minlen: 14 banner_text: | Authorized uses only. Activity is monitored.
Now every scan uses your values, no --var needed. You do not copy the whole
default set; you list only your overrides. Anything you leave out keeps its built-in
default.
Kensa resolves each variable through these tiers, later winning on a collision:
built-in defaults → defaults.yml → conf.d/*.yml → groups/<group>.yml → hosts/<host>.yml → --var
You do not have to use every tier. defaults.yml alone covers most teams. The rest
exist for when one fleet needs more than one policy.
Step 4: layer overrides for groups and single hosts
When part of your fleet needs different values, override per scope instead of maintaining separate configs:
conf.d/*.yml— organization-wide overrides, merged alphabetically so you can order them (10-base.yml,50-org.yml,99-local.yml). Later files win.groups/<group>.yml— values for one inventory group. A host in the[web]group picks upgroups/web.yml.hosts/<hostname>.yml— values for one host, named by the address in your inventory (hosts/web01.example.com.yml).
One rule to remember: a variable's base value must live in a global tier
(defaults.yml, conf.d/, or the built-in defaults). The groups/ and hosts/
files override an existing variable; they cannot introduce a brand-new one that
has no global default. Since every templated corpus variable already has a built-in
default, overriding any of them per group or per host works. Inventing a new variable
name only in groups/ will error with "undefined variable" (see the last section).
Step 5: put your fleet in an inventory
Instead of naming one host per command, list them once in an Ansible-style
inventory. Group hosts under [section] headers; the group names line up with your
groups/*.yml files:
# fleet.ini [web] web01.example.com ansible_user=admin web02.example.com ansible_user=admin [db] db01.example.com ansible_user=admin
Scan the whole fleet, or a slice of it, in one command:
# Every host in the inventory, 10 at a time kensa check --inventory fleet.ini --workers 10 --sudo # Only the web group kensa check --inventory fleet.ini --limit web --sudo
--limit takes the same glob and group syntax as Ansible (--limit 'web*,!web02.example.com').
--workers sets how many hosts run concurrently.
Step 6: choose one place for results
By default Kensa writes its transaction log to .kensa/results.db in the current
directory, which moves with your shell. Pin it to one stable path so history and
rollback always find the same records:
kensa --db ~/.local/share/kensa/results.db check --inventory fleet.ini --sudo
The --db flag is global, so it goes before the subcommand. Point every command at
the same file and your whole audit trail lives in one database.
Verify
Confirm the configuration is wired by running the barest possible command, no -r,
no --var, against one host:
kensa check -H web01.example.com -u admin --sudo
Two things prove the setup took:
- It runs the full corpus rather than reporting "No rules found." The rules directory resolved on its own.
- No "undefined variable" error appears. Your variable tiers resolved; the templated rules got their values.
To confirm a specific override is live, scan just the rule it affects and read the
row. For the SSH MaxAuthTries value you set in Step 3:
kensa check -H web01.example.com -u admin --sudo --control cis-rhel9:5.1.16
The verdict reflects the value Kensa resolved, which is now yours.
If it didn't work
- "No rules found." The
kensa-rulespackage is not installed, so the default rules directory is empty. Install it, or pass--rules-dir <path>. - Your config directory is ignored. Kensa uses the first directory that exists
in the Step 2 list. If you put files in
/etc/kensabut also have a~/.config/kensa, the personal one wins and shadows the system one. Remove the one you don't want, or name the intended one explicitly with--config-dir. - "undefined variable" in an inventory scan. You defined a variable only in
groups/orhosts/. Give it a base value indefaults.ymlorconf.d/(the per-group or per-host file then overrides it). - An override isn't taking effect. Check the tier order: a value in
conf.d/beatsdefaults.yml, and a--varon the command line beats every file. If you set the same key in two places, the later tier wins.
Related guides
- How to scan a Linux host for compliance without installing anything on the host target — the read-only scan this configuration streamlines.
- How to remediate one control and roll it back — applying changes once your policy values are in place.
For the full flag and file reference, see the documentation.