You just finished configuring a new Fedora server
You have the services running, the firewall locked down, and the users created. Before you hand the keys to the team or expose the machine to the internet, you need proof that the configuration matches your security policy. You find a reference to CIS benchmarks and OpenSCAP, but the documentation reads like a compliance manual written by lawyers. You need a working command that checks the system and tells you exactly what to fix.
What is actually happening
OpenSCAP is a command-line scanner that implements the Security Content Automation Protocol. The protocol standardizes how security checks are written and how results are reported. You feed it a data stream file, which contains a collection of rules written in XCCDF format. Each rule checks one specific system state. A rule might verify that a service is disabled, confirm that a package version meets a minimum threshold, or check that a password policy enforces complexity requirements. The scanner runs every rule against your live system, records pass or fail, and compiles the results into an HTML or PDF report.
Think of it as an automated building inspector. The inspector carries a standardized checklist, walks through every room, marks violations, and hands you a report before you sign the occupancy permit. The checklist is the XCCDF profile. The inspector is the oscap binary. The report is your compliance evidence.
Fedora ships the SCAP Security Guide as a separate package. The guide contains community-maintained rules that track Fedora releases. The rules are updated frequently to match new kernel features, systemd changes, and package updates. You do not need to write your own checks unless you have highly specific internal policies. The default guide covers CIS, NIST, and DISA STIG benchmarks out of the box.
Run the scanner from a stable terminal session. A botched scan can leave temporary files in /var/tmp/ and clutter your working directory. Keep your scans organized in a dedicated folder.
The fix and how to run it
Start by installing the scanner and the official security guide. Fedora keeps the SCAP content separate so the base system stays lean. Run the installation command first.
sudo dnf install -y openscap-scanner scap-security-guide
# openscap-scanner provides the oscap binary and runtime libraries
# scap-security-guide contains the XCCDF rules and data streams for Fedora
# -y skips the interactive confirmation prompt for automated scripts
Next, run the evaluation. The default data stream lives in /usr/share/xml/scap/ssg/content/. You will select a profile that matches your environment. The CIS profile is strict and targets production servers. The standard profile is lighter and targets desktops. Run the evaluation with the profile flag and the report flag.
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis \
--report /tmp/security-audit-report.html \
--results /tmp/security-audit-results.xml \
/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml
# --profile selects the specific checklist to run against the system
# --report generates a human-readable HTML summary for quick review
# --results saves machine-readable XML for CI/CD pipelines or archiving
# The final argument points to the Fedora SCAP data stream file
The scanner will take a few minutes. It reads configuration files, checks running services, and verifies package versions. When it finishes, it drops the HTML report in your specified directory. Open it in a browser to see the breakdown. The report lists every rule, its result, and a remediation script if one exists. You can click the remediation button to generate a shell script that fixes the failing rules automatically. Review the script before running it. Automated fixes modify system files and can break custom configurations.
Convention aside: dnf upgrade --refresh is the normal weekly maintenance command. dnf system-upgrade is for crossing major Fedora releases. They are different commands. Don't conflate them. Run a refresh before scanning to ensure your package metadata is current. Stale metadata causes false failures on version checks.
Trust the package manager. Manual file edits drift, snapshots stay.
Verify it worked
The command returns a zero exit code on success. A non-zero exit code means the scanner crashed or encountered a fatal configuration error. Check the exit code immediately after the run.
echo $?
# Prints 0 if the scan completed without fatal errors
# Prints 1 or higher if the binary encountered a crash or missing dependency
# Always check this before opening the HTML report
You can also verify the report structure by checking the file size and opening the summary section. The report lists every rule, its result, and a remediation script if one exists. Run a quick grep on the HTML to count failures.
grep -c "result=\"fail\"" /tmp/security-audit-results.xml
# Counts how many rules explicitly failed the check
# result="pass" means the system meets the requirement
# result="notapplicable" means the rule does not apply to this configuration
# result="error" means the scanner could not read the required file or service
You can cross-reference the XML results with the HTML report. The XML is structured for parsing. The HTML is structured for reading. Keep both. Archive the XML in your version control system or ticket tracker. Archive the HTML for human review.
Check the exit code before opening the report. A silent failure wastes more time than a loud one.
Common pitfalls and what the error looks like
The scanner requires root privileges to read system files and check service states. Running it without sudo will cause dozens of false failures and print Rule result: notapplicable for anything that requires elevated access. You will also see Error: Cannot open file if the data stream path is wrong. Fedora packages the content under /usr/share/xml/scap/ssg/content/. Never edit files in /usr/lib/ or /usr/share/. Those paths ship with the package and get overwritten on the next dnf upgrade --refresh. Keep your custom overrides in /etc/ if you are writing custom rules.
Another common issue is profile mismatch. The CIS profile checks for controls that desktop users rarely need, like disabling USB storage or enforcing strict password aging. Running the wrong profile floods the report with irrelevant failures. Match the profile to the workload. If the report shows hundreds of failures, you picked the wrong checklist.
SELinux denials can also interrupt the scan. The scanner reads files across the system and may trigger an AVC denial if the context is mislabeled. Check the audit log before disabling the security module.
sudo journalctl -t setroubleshoot | tail -n 20
# Shows SELinux denial summaries with one-line explanations
# The x flag in journalctl -xe adds explanatory text to each line
# Most sysadmins type journalctl -xeu <unit> muscle-memory style
# Read the denial before running restorecon or changing booleans
False positives happen when the scanner checks a service that you intentionally disabled. The report will flag sshd.service as failed if you are running a custom SSH daemon on a non-standard port. You can suppress specific rules by generating a tailoring file, but that requires XCCDF knowledge. The faster path is to accept the finding and document the exception in your compliance tracker.
Convention aside: systemctl status <unit> shows recent log lines AND state in one view. Always check status before restart. The scanner does not restart services. It only reads their current state. If a service is masked, the scanner will report it as disabled. That is expected behavior.
If the boot menu is gone, GRUB rescue is your friend, not your enemy.
When to use this versus alternatives
Use OpenSCAP when you need a standardized, auditable compliance report that maps to CIS, NIST, or DISA STIG benchmarks. Use manual grep and systemctl checks when you only need to verify two or three specific settings and want immediate feedback. Use a configuration management tool like Ansible when you want to enforce the fixes automatically across a fleet of machines. Stay on the SCAP Security Guide if you want community-maintained rules that track Fedora releases.
Convention aside: firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge. The scanner checks the persistent firewall rules. If you changed rules in the runtime only, the report will show the old state. Reload the firewall before scanning.
Snapshot the system before the upgrade. Future-you will thank you.