Skip to Content

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):

  1. Command line (-e "var=value")
  2. Playbook vars
  3. host_vars/<hostname>/
  4. group_vars/<child_group> (environment specific e.g. testing, production)
  5. group_vars/all/ - common baseline
  6. 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

VariableDefaultDescription
ciq_run_audittrueRun compliance audit before/after
ciq_allow_reboottrueAllow automatic reboot after hardening
Note

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:

VariableDefaultDescription
ciq_run_rlchtrueGates 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_fipstrueEnable FIPS mode (STIG requirement)
Note

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

VariableDefaultDescription
rhel9stig_cat1_patchtrueApply Category I (High) controls
rhel9stig_cat2_patchtrueApply Category II (Medium) controls
rhel9stig_cat3_patchtrueApply Category III (Low) controls

CIS controls

VariableDefaultDescription
rhel9cis_servertrueServer profile (vs workstation)
Note

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

VariableDefaultDescription
ciq_enable_lkrgtrueEnable Linux Kernel Runtime Guard
ciq_enable_hardened_malloctrueEnable hardened memory allocator
ciq_enable_usbguardfalseEnable 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

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"