40. The control catalog, profiles and frameworks
This guide describes Lawliet 1.5.14.s (the current release). Screens, commands and procedures may change in later versions; the usage guide is updated with each release. Check the version your server runs under Settings > Platform or with ./lawliet version, and see the Releases page for what changed.
Every hardening and compliance control Lawliet checks or fixes is one record in the control catalog. The catalog is the base of the whole hardening and compliance program: scans read their checks from it, the planner orders and guards its fixes (chapter 41), the do-not-disrupt baseline compares its declared effects with each host (chapter 42), framework scores and signed reports roll its results up (chapter 43), and exports turn it into Group Policy, Ansible or a shell bundle (chapter 44).
This chapter explains what is in the catalog, how the role profiles and their levels work, where a control applies, how the catalog is protected, and how to read it.
Permissions:
| Task | Permission | Four-eyes |
|---|---|---|
| Read the catalog, its controls and the profiles | View compliance | - |
| Scan a host against a profile | Run scans | no |
| Create, change or delete a customer profile | Change compliance profiles | yes - critical action "Change a compliance profile" |
40.1 What the catalog holds#
The catalog shipped with this release has 1,401 controls:
| Platform | Content |
|---|---|
| Windows workstations (Windows 10 and 11) | 410 controls in 16 families: every Attack Surface Reduction rule as its own control (audit first, then block), Microsoft Defender Antivirus, BitLocker for system, fixed and removable drives, firewall logging, SmartScreen, exploit protection, virtualization-based security and memory integrity, Office macro policy, Edge and Chrome policy, removable storage and device installation, advanced audit policy and event log sizes, Windows Update, sign-in screen and screen lock, local accounts, software installation, telemetry and privacy |
| Windows member servers and domain controllers | 284 controls (srv-* and dc-* families): user rights, security options, the server audit set, SChannel (TLS) settings, SMB 3 encryption and dialects, features and services to remove, IIS, Windows LAPS, remote registry; on domain controllers Kerberos policy, LDAP signing and channel binding, anonymous directory access, DSRM, DNS zone transfers and secure updates, and Active Directory checks (machine account quota, delegation, Protected Users, AdminSDHolder, Recycle Bin, standing Enterprise/Schema Admins, tier-0 accounts on lower tiers, NTDS/SYSVOL/GPO permissions) |
| Windows sign-in and remote management | 53 controls (auth-* families): WinRM, NTLM on a host and across the domain, Kerberos armoring and AES, credential theft (Credential Guard, Remote Credential Guard, LSASS, CredSSP, UAC), relay and coercion (LDAP client signing, EFSRPC and DFSNM RPC filters, Print Spooler, WebClient, SMB SPN validation, AD CS Web Enrollment, Netlogon), remote administration (RDP over TLS, PowerShell transcription, auditing) |
| Ubuntu Server 20.04, 22.04 and 24.04 | 316 controls in 20 families: filesystem, boot, AppArmor, devices, network, kernel, auditd, logging, time, SSH, PAM, sudo, accounts, cron, services, firewall, permissions, packages, AIDE, banners |
| The controls of earlier releases | The 93 Windows and 112 Linux controls of 1.5.12.s, kept under their old ids, so scans, history, heatmap and trends are unchanged |
| VMware vSphere | 99 host, VM and port group controls (chapter 46) |
| AWS | 34 account controls (chapter 47) |
Each control states, in plain words, what is wrong, why it matters and what may break. It carries:
| Part | What it means for you |
|---|---|
| Id | A stable name such as WIN-WINRM-HTTP-LISTENER or UBU-SSH-ROOT-LOGIN. Older ids still match through the control's legacy id |
| Severity | critical, high, medium or low |
| Roles and OS versions | Where it applies: workstation, member server, domain controller, server; the Windows or Ubuntu versions it covers |
| Levels | strict, and also standard when the control belongs in the lighter level (see 40.2) |
| Stage | enforce (fixed directly), audit_then_enforce (an audit step runs first; 41.5) or report_only (checked and reported; the fix is a manual runbook) |
| Requires / conflicts | Controls that must pass first, and controls that cannot both be enforced |
| Guards | Safety checks the planner runs before an enforce (41.4) |
| Telemetry | The usage signals the planner reads to predict breakage (chapter 45) |
Effects (affects) | The services, ports, packages, protocols, processes, kernel modules and scheduled tasks the change touches; compared with the host's do-not-disrupt baseline (chapter 42) |
| Lockout | Whether the change can lock you out of the host, and the recovery artifact to issue first (26.5) |
| Check, fix, rollback | The check, the remediation (which records the value it replaces) and the rollback (which puts exactly that value back, and says so when it could not) |
| Mappings | The framework requirements it satisfies: CIS, DISA STIG, NIST SP 800-53 Rev. 5, ISO/IEC 27001:2022, PCI DSS 4.0.1, GDPR, FSTEC, GOST R 57580.1, NIS2, DORA (and for cloud and virtualisation: AWS Foundational Security Best Practices, CIS AWS Foundations, the VMware vSphere Security Configuration Guide) |
Some Windows controls are report-only by design because the change is irreversible or a judgement call: the krbtgt password reset, the AD Recycle Bin and directory permission repairs. They are checked and reported, and their runbook is in the control's text.
Framework mappings#
A control maps to framework requirements directly, and through topics (for example remote-admin-encryption): a control tagged with a topic reports against every framework id of that topic. The requirement lists shipped with this release:
| Framework | Requirements |
|---|---|
| NIST SP 800-53 Rev. 5 | 1014 controls and enhancements |
| ISO/IEC 27001:2022 Annex A | 93 |
| PCI DSS 4.0.1 | 280 |
| GDPR security articles | 10 |
| NIS2 Art. 21(2), with the Annex of Implementing Regulation 2024/2690 | 63 |
| DORA Art. 9, 10 and 12, with the ICT risk RTS 2024/1774 | 128 |
| FSTEC orders 17, 21, 117 and 239 | 113, 109, 38 and 152 |
| GOST R 57580.1 | 406 measures |
Requirement ids are the public identifiers; titles are short wording of our own. FSTEC Order 117 replaced Order 17 on 1 March 2026; Order 17 stays for systems still certified under it, and everything mapped to Order 17 also reports against Order 117 through a transition table (our analysis; FSTEC published no official one). Checks that only test that a tool is installed count as "manual / evidence upload", not as automated.
The existing "PCI DSS v4.0" checks now carry their PCI DSS 4.0.1 numbers (for example password complexity is 8.3.6, not 8.2.3; firewall findings 1.3.1/1.3.2, not 1.2.1). Scan results stored before the upgrade keep their old numbers and still open the right check.
40.2 Role profiles and levels#
A profile is the set of catalog controls for one kind of host. Four are built in:
| Profile | Framework code (Framework registry) | Hosts |
|---|---|---|
| Windows workstation | lawliet_windows_workstation | Windows 10/11 endpoints |
| Windows member server | lawliet_windows_member_server | Domain-joined Windows Server |
| Windows domain controller | lawliet_windows_domain_controller | Active Directory domain controllers |
| Ubuntu server | lawliet_ubuntu_server | Ubuntu 20.04/22.04/24.04 servers |
Each profile has two levels:
| Level | Content |
|---|---|
| strict (the default) | Every catalog control of the platform that applies to the role. The strictest baseline: a control is relaxed only by an approved exception (25.2) |
| standard | Only the controls marked standard. Every standard control is also in strict |
There is no separate CIS "Level 1 / Level 2" switch. Each control carries its CIS and DISA STIG references (shown in exports and reports), and the benchmark frameworks of earlier releases - for example cis_windows_workstation, cis_windows_server, stig_windows, cis_linux, stig_linux - stay in Compliance > Overview > Framework registry for scanning. A profile is scanned like any framework: choose its code in the scan form (22.2).
The planner offers both levels (the Profile list on Hardening > Planner); the exports offer both (the Level list on Compliance > Exports). A level is not stored per host: you choose it each time.
Customer profiles#
A customer profile derives from one built-in profile: the same controls at the level you choose, plus controls you add from the same platform. It never drops a control - a control that does not fit a host is an exception, which is time-limited, approved by a second person and reported as accepted risk. A customer profile becomes a framework of its own (code lawliet_profile_<id>, name "Profile: <name>") that scans, the fix plan and hardening use like any other.
There is no console screen for customer profiles in this release; they are managed through the API (40.5).
40.3 Where a control applies, and "not applicable"#
Every catalog check and change first checks the host's role and OS version (and, for Ubuntu content, that the host is Ubuntu). On a host outside its scope:
- a scan reports the control as not applicable, and the result is left out of the score;
- hardening refuses to run it there.
"Not applicable" is accepted only from a control that can be inapplicable on that host: the host has another role, a version the control does not cover, or a feature the control needs is absent - and the catalog says so explicitly for that control. Anywhere else a "not applicable" answer is scored as not met. A later scan that finds a control not applicable takes its older result out of framework scores. Three server checks (SMB encryption, SMB unencrypted access, legacy TLS usage) answer not assessed - not "not applicable" - when they cannot read the setting or have no evidence.
What this changes after an upgrade from 1.5.13.s: 31 of the migrated Windows controls (45 framework entries: 14 in CIS workstation, 21 in CIS server, 10 in STIG) now decline hosts outside their role or version - the server-only ones on workstations, and the local account policy and user-rights ones on domain controllers, whose Group Policy would revert a local change. Their scores on those hosts no longer count them.
A host whose role cannot be read is not guessed: role-specific controls are not run there until the agent reports the role (domain controller, member, standalone).
40.4 How the catalog is protected#
The catalog is signed with the vendor's release key when a bundle is built, and checked each time the product starts. A catalog changed after signing is refused.
The signature also covers the helper files under <platform>/lib/: the Group Policy library for Windows and, since 1.5.14.s, ubuntu/lib/lwfw.py.txt, the model of ufw's rule store that the Ubuntu firewall controls use. It is kept once there and put into each firewall script when the script is sent (to an agent, over SSH, into the shell bundle or the Ansible role); what runs on the host is the same as before.
What you see if the check fails: the catalog API answers 503 with the reason, and the built-in and customer profiles have no controls to scan. Scans of the older benchmark frameworks are not affected.
What to do: never edit the control catalog's files in the installation directory. Re-apply the release you run (sudo ./lawliet update <bundle> with the same bundle, chapter 4), or restore the installation directory from your backup, then contact [email protected] with the output of sudo ./lawliet diag if it persists.
40.5 Reading the catalog and managing customer profiles (API)#
The catalog has no console browser in this release. Its controls show up where they are used: scan results, the Fix plan, the planner, framework requirements and exports. To list or search it, use the API (any account with View compliance; a service-account key with the Read only scope works for reads, 15.7):
| Call | Returns |
|---|---|
GET /api/v1/compliance/catalog | Controls, filtered by platform (windows, ubuntu, linux), role (workstation, member_server, domain_controller, server), family, framework (a mapping key such as cis, stig, nist_800_53, fstec) with optional mapping_id, severity, level (strict, standard), stage, os_version, legacy, q (text in the id or title); limit (at most 2000) and offset. An unknown filter value is refused (422), never silently empty |
GET /api/v1/compliance/catalog/meta | The catalog version and counts |
GET /api/v1/compliance/catalog/controls/{control_id} | One control: its mappings, relations and commands |
GET /api/v1/compliance/catalog/profiles | The built-in and customer profiles with their control counts |
GET /api/v1/compliance/catalog/profiles/{ref} | One profile and its controls (a built-in slug such as windows-workstation, or custom-<id>) |
Example, every high-severity domain controller control mapped to NIST AC-17:
curl -H "Authorization: Bearer lwk_..." \
"https://<server>/api/v1/compliance/catalog?role=domain_controller&severity=high&framework=nist_800_53&mapping_id=AC-17"Procedure: create, change or delete a customer profile#
Permission: Change compliance profiles (administrator roles). Four-eyes: yes - the critical action "Change a compliance profile". API keys cannot reach these calls; they are made with an administrator's signed-in session.
Risk: a profile decides what is checked and enforced on its hosts. Adding a control that breaks a workload shows up as failing results, and hardening it still goes through the planner's guards and approval. Rollback: change the profile again (remove the added control or change the level), or delete it; its scan history stays.
| Call | Body |
|---|---|
POST /api/v1/compliance/catalog/profiles | name (unique), description, base (one of windows-workstation, windows-member-server, windows-domain-controller, ubuntu-server), level (strict or standard), add_controls (catalog ids of the same platform, at most 500, none twice) |
PATCH /api/v1/compliance/catalog/profiles/{profile_id} | Any of name, description, level, add_controls (the full new list). The base cannot change |
DELETE /api/v1/compliance/catalog/profiles/{profile_id} | - |
- Send the call. An invalid body is refused at once (422) - before anything is held for approval - with the reason, for example "not windows catalog controls: ...".
- With dual control on, the call answers that the request is held for approval (HTTP 428). A second administrator approves it in Approvals > Waiting for me.
- Open Approvals > My requests and press Execute now within the execution window.
What you see: the profile, with its framework code lawliet_profile_<id>. It appears in the Framework registry as "Profile: <name>" and can be scanned at once. A deleted profile can no longer be scanned; its framework and scan history stay.
If it fails:
| Message | Cause | Fix |
|---|---|---|
| 409 "A profile with that name exists" | Names are unique | Choose another name |
| 422 "base must be one of ..." | Unknown base | Use one of the four built-in slugs |
| 422 "a ... control twice" / "not ... catalog controls" | A duplicate, or a control of another platform | Correct add_controls |
| 403 | No Change compliance profiles | Ask an administrator |

