OpenSCAP Compliance Scanning
Applies to CentOS Stream 9 & 10 / AlmaLinux 9.x & 10.x / Rocky Linux 9.x & 10.x
Compliance checks often mean walking through a checklist of hundreds of items, verifying your system configuration one by one. OpenSCAP automates this: it reads a standardized security baseline, scans your system, tells you which items pass and which fail, and can even remediate them for you.
What You Will Learn
Section titled “What You Will Learn”- What the SCAP standard and its components (XCCDF, OVAL, datastream) are
- How to install OpenSCAP and find the baseline content for your distribution
- How to scan a system with CIS, DISA STIG, and other profiles and generate a readable HTML report
- How to interpret scan results and run automatic remediation safely
- How to apply a baseline at install time, scan container images, and set up periodic compliance checks
Prerequisites
Section titled “Prerequisites”- A system running EL 9.x or EL 10.x
- sudo privileges
- Access to DNF repositories (baseline content packages install from the default repos)
- Strongly recommended: work on a test machine or VM snapshot first before applying to production
What SCAP and OpenSCAP Are
Section titled “What SCAP and OpenSCAP Are”SCAP (Security Content Automation Protocol) is a set of standards maintained by NIST that describe “security compliance checks” in a machine-readable format, so that different tools can exchange and execute the same baseline. It consists of several components:
| Component | Role |
|---|---|
| XCCDF | The checklist format, describing individual rules, profiles, and how pass/fail is determined |
| OVAL | The detection logic, defining “how to actually check the system state” (e.g., whether a file’s permissions are 600) |
| datastream | The packaging format (*-ds.xml) that bundles XCCDF, OVAL, and other content into a single file |
OpenSCAP (oscap) is the open-source implementation of SCAP on EL — the command-line tool that performs scans and remediation. The actual baseline content is provided by the SCAP Security Guide (SSG) project, which packages CIS, DISA STIG, and other baselines for each distribution.
Installation
Section titled “Installation”$ sudo dnf install openscap-scanner scap-security-guideopenscap-scannerprovides theoscapcommand.scap-security-guideprovides the datastream content for each distribution.
If you also need to scan container images, install openscap-utils (which provides oscap-podman).
Find Your Datastream
Section titled “Find Your Datastream”SSG installs content under a fixed directory:
$ ls /usr/share/xml/scap/ssg/content/Each distribution has its own datastream file. Choosing the wrong one leads to mismatched rules, so match yours up first:
| Distribution | Datastream file |
|---|---|
| RHEL 9 | ssg-rhel9-ds.xml |
| CentOS Stream 9 | ssg-cs9-ds.xml |
| AlmaLinux 9 | ssg-almalinux9-ds.xml |
| Rocky Linux 9 | ssg-rl9-ds.xml |
| RHEL 10 | ssg-rhel10-ds.xml |
List Available Profiles
Section titled “List Available Profiles”A single datastream contains multiple profiles, each corresponding to a compliance standard. First, see which ones are available:
$ oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xmlThe Profiles: section of the output lists the title and ID of each profile, similar to:
Profiles: Title: CIS Red Hat Enterprise Linux 9 Benchmark for Level 2 - Server Id: xccdf_org.ssgproject.content_profile_cis Title: DISA STIG for Red Hat Enterprise Linux 9 Id: xccdf_org.ssgproject.content_profile_stig Title: PCI-DSS v4 Control Baseline for Red Hat Enterprise Linux 9 Id: xccdf_org.ssgproject.content_profile_pci-dssThat xccdf_org.ssgproject.content_profile_... is the profile ID you will use in later commands.
Common profiles:
| Standard | Description |
|---|---|
| CIS | CIS Benchmark, with Level 1/Level 2 and Server/Workstation variants |
| DISA STIG | The U.S. Department of Defense Security Technical Implementation Guide, the strictest |
| PCI-DSS | Payment Card Industry Data Security Standard |
| HIPAA | U.S. healthcare information protection |
| ANSSI-BP-028 | The French national cybersecurity agency baseline, with minimal/intermediary/enhanced/high levels |
| CUSP | A general-purpose baseline new in EL 10 (Custom Profile), positioned as a moderate, universal starting point |
Evaluation Scan
Section titled “Evaluation Scan”Once you have your datastream and profile ID, run an evaluation scan:
$ sudo oscap xccdf eval \ --profile xccdf_org.ssgproject.content_profile_cis \ --results scan-results.xml \ --report report.html \ /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xmlParameter notes:
--profile: the profile ID to apply.--results: saves the machine-readable XML results (needed later to generate remediation scripts).--report: generates a human-readable HTML report.
When the scan finishes, open report.html in a browser to see each rule’s pass status, severity, and remediation advice.
Interpreting Results
Section titled “Interpreting Results”Each rule in the report has a result status:
| Status | Meaning |
|---|---|
| pass | Passed, compliant with the baseline |
| fail | Failed, needs remediation |
| notapplicable | Not applicable (e.g., the rule targets software that is not installed) |
| notchecked / error | Not checked or the check errored |
Remediate in order of severity: handle high first, then medium, then low. The summary chart at the top of the report lets you quickly see the distribution of failures. Do not chase 100% pass — some rules may conflict with your business needs (for example, disabling a service you actually use); such items need manual evaluation and a documented exception.
Automatic Remediation
Section titled “Automatic Remediation”OpenSCAP can automatically bring failing items into compliance, in two ways.
Apply remediation in the same pass as the scan:
$ sudo oscap xccdf eval \ --profile xccdf_org.ssgproject.content_profile_cis \ --remediate \ --results scan-results.xml \ --report report.html \ /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xmlThis is the fastest but least controllable approach; only recommended for throwaway test environments.
The safer approach is to scan for results first, then generate a remediation script from the results, review it, and run it:
$ sudo oscap xccdf generate fix \ --fix-type bash \ --profile xccdf_org.ssgproject.content_profile_cis \ scan-results.xml > remediate.shOpen remediate.sh and review it line by line, confirming there are no changes that would break your workloads before running it. You can also generate an Ansible playbook to fold into your existing configuration-management workflow:
$ sudo oscap xccdf generate fix \ --fix-type ansible \ --profile xccdf_org.ssgproject.content_profile_cis \ scan-results.xml > remediate.ymlAfter remediation, scan again and compare whether the fail count dropped to confirm the changes took effect.
Apply a Baseline at Install Time
Section titled “Apply a Baseline at Install Time”If you use Kickstart for automated installs, you can bring the system into compliance during installation and skip remediation afterward. Anaconda provides the org_fedora_oscap addon:
%addon org_fedora_oscap content-type = scap-security-guide profile = xccdf_org.ssgproject.content_profile_cis%endThe installer applies the specified profile during provisioning, so a new machine is already hardened on first boot. This is a common practice for keeping baselines consistent across large-scale deployments.
Scan Container Images
Section titled “Scan Container Images”Compliance is not only about the host — container images need checking too. After installing openscap-utils, use oscap-podman to scan an image directly (without starting a container):
$ sudo oscap-podman registry.access.redhat.com/ubi9/ubi:latest \ xccdf eval \ --profile xccdf_org.ssgproject.content_profile_cis \ --report container-report.html \ /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xmlPut this step in your CI pipeline to block non-compliant builds before an image is published.
Periodic Compliance Checks
Section titled “Periodic Compliance Checks”Compliance is not a one-time thing — configuration drifts over time. Use a systemd timer to scan periodically and archive the reports so you can continuously track system state.
-
Write a scan script that archives reports by date:
/usr/local/sbin/compliance-scan.sh $ sudo tee /usr/local/sbin/compliance-scan.sh <<'EOF'#!/bin/bashset -euo pipefailDS=/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xmlPROFILE=xccdf_org.ssgproject.content_profile_cisOUT=/var/log/complianceDATE=$(date +%Y%m%d)mkdir -p "$OUT"oscap xccdf eval --profile "$PROFILE" \--results "$OUT/results-$DATE.xml" \--report "$OUT/report-$DATE.html" \"$DS" || trueEOF$ sudo chmod +x /usr/local/sbin/compliance-scan.shThe trailing
|| trueprevents the non-zero exit code from rule failures from marking the timer as failed. -
Create the service and timer units to run it weekly. See Timers for the exact syntax.
Common Issues
Section titled “Common Issues”Datastream File Not Found
Section titled “Datastream File Not Found”If /usr/share/xml/scap/ssg/content/ is empty or missing, the baseline content package is not installed:
$ sudo dnf install scap-security-guideNote that it and openscap-scanner are two different packages — installing the scanner does not install the content.
I Do Not Know What the Profile ID Is
Section titled “I Do Not Know What the Profile ID Is”The profile ID is that xccdf_org.ssgproject.content_profile_... string, not the human-readable title. Use oscap info <datastream> to view the full list and copy the Id: value.
The Scan Is Too Slow
Section titled “The Scan Is Too Slow”A full scan runs through hundreds of OVAL checks and can take several minutes on slow disks or resource-constrained machines, which is normal. If you only want to validate a few rules, use --rule <rule_id> to run just the specified rules, which is much faster.
Remediation Broke My System
Section titled “Remediation Broke My System”This is exactly why “test on a snapshot first” is emphasized repeatedly. If a production system is already broken: rolling back from a VM snapshot or backup is the most reliable fix. So before running --remediate, always confirm you have a restore point to roll back to.