Configuration
Variable file structure
The RPM installs the ctrliq.rlch9_lockdown collection into ansible-core's default collections path, not a directory you own. Running ciq-lockdown-collection-init <destination> (see Quick Start) copies read-only reference group_vars/ templates from the collection into an operator-editable working directory - everything Ansible actually loads lives there:
~/ciq-lockdown/ ← Ansible loads from here (once you cd in)
├── ansible.cfg # Written by ciq-lockdown-collection-init
├── inventory/
│ ├── hosts.yml # Created by operator (copy from hosts.yml.example)
│ └── group_vars/
│ ├── all/
│ │ ├── ciq_defaults.yml # Common baseline (edit to tune defaults)
│ │ ├── rlch9_profile_alignment.yml # Profile-specific rule alignment
│ │ ├── vault.yml # Created by operator - depot creds, grub2_password
│ │ └── zz_local_overrides.yml.example # Scratch file for ad hoc local overrides
│ ├── testing/
│ │ └── lockout_prevention.yml # Disables lockout-causing rules (testing hosts)
│ └── production/
│ └── compliance_strict.yml # Full compliance settings (production hosts)
└── .vault_pass # Created by operator
Variable precedence
Ansible loads variables in this order (highest wins):
- Command line (
-e "var=value") - Playbook vars
host_vars/<hostname>/group_vars/<child_group>(environment specific e.g. testing, production)- group_vars/all/ - common baseline
- Role defaults
Environments
Testing
Hosts in the testing inventory group load group_vars/testing/lockout_prevention.yml. Its purpose is narrow: keep the specific rules disabled that would otherwise force an SSH lockout during iterative work (for example, rules that set PermitRootLogin no). FIPS mode, crypto policy, and account lockout (except root) are enabled the same as production - testing is not a lighter-security mode, just a lockout-safe one. Use for development, iterative testing, and debugging.
Production
Hosts in the production inventory group load group_vars/production/compliance_strict.yml, tuned for maximum compliance (per the file's own targets: STIG 91-93%, CIS 94-96% on cloud VMs without separate partitions; higher with proper partitioning). It keeps the same lockout-safe PermitRootLogin handling as testing rather than the stricter upstream default, since flipping that setting is an explicit, deliberate choice an operator makes for their environment (see Recommended settings by environment) - not something either environment file should force.
The production settings ship with cloud VM compatibility: partition rules, USBGuard, smart card, and GNOME/GUI rules are disabled by default because cloud VMs typically use a single root partition and have no USB or PIV/CAC hardware. See Compliance Scores for the score impact.
Key variables
The most commonly-needed variables. See the Variable Reference for the full list by profile.
Run behavior
| Variable | Default | Description |
|---|---|---|
ciq_run_audit | true | Run compliance audit before/after |
ciq_allow_reboot | true | Allow automatic reboot after hardening |
ciq_deployment_mode is set as a descriptive fact (convert vs drift) by some playbooks but isn't read by any conditional - it doesn't change behavior. See Drift remediation for the real, functional drift workflow.
Framework selection
Which framework runs is determined by which playbook you invoke (rlch9_stig, rlch9_cis, rlch9_cui, or rlch9_combined), not by a variable toggle. Only two variables affect this behavior:
| Variable | Default | Description |
|---|---|---|
ciq_run_rlch | true | Gates the CIQ meta-package install step (rlc-h, and rlc-fips on LTS) in every playbook. Set to false to skip it. LKRG, hardened_malloc, and the rest of RLC-H infrastructure hardening have their own dedicated toggles: see ciq_enable_lkrg, ciq_enable_hardened_malloc, and ciq_enable_rlch_hardening in the Variable Reference. |
ciq_enable_fips | true | Enable FIPS mode (STIG requirement) |
ciq_run_stig only has an effect inside rlch9_combined, where it tells CIS's rule set whether to defer to STIG's equivalents on overlapping controls. It does not enable or disable STIG itself: run the rlch9_stig playbook for that.
STIG controls
| Variable | Default | Description |
|---|---|---|
rhel9stig_cat1_patch | true | Apply Category I (High) controls |
rhel9stig_cat2_patch | true | Apply Category II (Medium) controls |
rhel9stig_cat3_patch | true | Apply Category III (Low) controls |
CIS controls
| Variable | Default | Description |
|---|---|---|
rhel9cis_server | true | Server profile (vs workstation) |
rhel9cis_level_1 and rhel9cis_level_2 exist in the upstream CIS role's defaults but are audit-fact metadata only - real level selection there is by Ansible tag, which rlch9_cis never applies. The playbook runs the full CIS Level 1 + Level 2 rule set unconditionally; these two variables don't change what runs.
RLC-H specific
| Variable | Default | Description |
|---|---|---|
ciq_enable_lkrg | true | Enable Linux Kernel Runtime Guard |
ciq_enable_hardened_malloc | true | Enable hardened memory allocator |
ciq_enable_usbguard | false | Enable USB device control |
Individual rule toggles
Every STIG and CIS rule can be individually enabled or disabled:
# STIG pattern: rhel_09_XXXXXX: true/false
rhel_09_255040: false # Example: disable SSH PermitRootLogin rule
# CIS pattern: rhel9cis_rule_X_X_X: true/false
rhel9cis_rule_5_1_7: false # Example: disable SSH AllowUsers check
Rule overrides belong in inventory/group_vars/all/ciq_defaults.yml (all hosts) or the environment-specific files, relative to the working directory you scaffolded in Quick Start.
Common configurations
Run from inside your scaffolded working directory (e.g. ~/ciq-lockdown) - no ANSIBLE_CONFIG export needed, since Ansible auto-loads the ansible.cfg there. Playbooks are invoked by FQCN:
# Skip FIPS mode
ansible-playbook ctrliq.rlch9_lockdown.rlch9_combined -e "ciq_enable_fips=false"
# Disable a specific rule
ansible-playbook ctrliq.rlch9_lockdown.rlch9_stig -e "rhel_09_255040=false"
# Skip automatic reboot
ansible-playbook ctrliq.rlch9_lockdown.rlch9_combined --skip-tags auto_reboot
Recommended settings by environment
Cloud/VM production
# Customize inventory/group_vars/production/compliance_strict.yml:
ciq_enable_usbguard: false # No USB on cloud
rhel9cis_rule_5_3_3_1_3: false # Don't lock root account
On-premise production
ciq_enable_usbguard: true # Enable USB control
rhel_09_611150: true # Require smart card (if PIV)
Bootloader password (maximum compliance)
Set the plaintext password in the vault; the role hashes it at runtime and writes /boot/grub2/user.cfg itself, so no manual grub2-mkpasswd-pbkdf2 step is needed:
# In inventory/group_vars/all/vault.yml
grub2_password: "YourPassword"
grub2_username defaults to bootadmin and only needs setting if you want a different GRUB admin username. See Troubleshooting if this control is unexpectedly skipped.
Verifying variable loading
# See which vars apply to a host
ansible server1 -m debug -a "var=hostvars[inventory_hostname]"
# Check a specific variable
ansible server1 -m debug -a "var=rhel9cis_rule_5_1_1"
# Show resolved ansible.cfg values
ansible-config dump | grep -E "roles_path|inventory|vault_password"