Last updated: March 22, 2026

How to Set Up OpenSCAP for Compliance Scanning

OpenSCAP is the open-source implementation of the SCAP (Security Content Automation Protocol) standard. It scans your system against published security baselines. CIS Benchmarks, DISA STIGs, PCI DSS profiles. produces scored HTML reports, and generates Bash remediation scripts that automatically fix failures. This guide uses RHEL/CentOS 9 and Ubuntu 24.04.

What OpenSCAP Checks


  1. Install OpenSCAP
RHEL / CentOS / Fedora
sudo dnf install -y openscap openscap-scanner openscap-utils scap-security-guide

Ubuntu / Debian
sudo apt install -y libopenscap8 openscap-scanner python3-openscap ssg-base ssg-debderived

Verify
oscap --version

  1. List Available Profiles

The SCAP Security Guide (SSG) ships XML data stream files containing multiple profiles:

RHEL / CentOS
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Ubuntu
oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2404-ds.xml

Sample output:
Profiles:
    Title: CIS Red Hat Enterprise Linux 9 Benchmark for Level 1 - Server
        Id: xccdf_org.ssgproject.content_profile_cis_server_l1
    Title: DISA STIG for Red Hat Enterprise Linux 9
        Id: xccdf_org.ssgproject.content_profile_stig

  1. Run Your First Scan
RHEL. CIS Level 1 Server profile
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --results /tmp/scan-results.xml \
  --report /tmp/scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Ubuntu. CIS Level 1
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_level1_server \
  --results /tmp/scan-results.xml \
  --report /tmp/scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-ubuntu2404-ds.xml

echo "Report generated: /tmp/scan-report.html"

Open the HTML report in a browser. it shows pass/fail for each rule with explanations and references.


  1. Read the Results
Quick summary from the XML results
oscap xccdf generate guide \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml \
  > /tmp/guide.html

Count passes and failures
grep -o '<result>.*</result>' /tmp/scan-results.xml | sort | uniq -c

List only failed rules
oscap xccdf results-arf /tmp/scan-results.xml 2>/dev/null || \
python3 - <<'EOF'
import xml.etree.ElementTree as ET
ns = {'xccdf': 'http://checklists.nist.gov/xccdf/1.2'}
tree = ET.parse('/tmp/scan-results.xml')
root = tree.getroot()
for result in root.iter('{http://checklists.nist.gov/xccdf/1.2}rule-result'):
    outcome = result.find('{http://checklists.nist.gov/xccdf/1.2}result')
    if outcome is not None and outcome.text == 'fail':
        print(result.attrib.get('idref', ''))
EOF

  1. Generate and Apply Remediation Scripts
Generate a Bash script that fixes all failures
sudo oscap xccdf generate fix \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --result-id "" \
  --fix-type bash \
  --output /tmp/remediation.sh \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

REVIEW the script before running. some fixes restart services
less /tmp/remediation.sh

Run remediation (test on non-production first)
sudo bash /tmp/remediation.sh 2>&1 | tee /tmp/remediation.log

Re-scan after remediation to verify improvements
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --results /tmp/post-remediation-results.xml \
  --report /tmp/post-remediation-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

  1. Ansible Playbook Remediation (Infrastructure as Code)

For automated fleet compliance:

Generate Ansible playbook instead of shell script
sudo oscap xccdf generate fix \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --fix-type ansible \
  --output /tmp/remediation-playbook.yml \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Run on a remote host
ansible-playbook -i "targethost," -u root \
  /tmp/remediation-playbook.yml

  1. Scan a Specific Rule (Targeted Checks)
List rule IDs
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml \
  | grep "Id:" | grep -v profile

Scan only the SSH hardening rules
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --rule xccdf_org.ssgproject.content_rule_sshd_disable_root_login \
  --rule xccdf_org.ssgproject.content_rule_sshd_set_max_sessions \
  --rule xccdf_org.ssgproject.content_rule_sshd_use_strong_macs \
  --results /tmp/ssh-results.xml \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

  1. Scan Docker Container Images

OpenSCAP can scan container images offline:

Install container scanning plugin
sudo dnf install -y openscap-containers   # RHEL

Pull and scan a container image
docker pull registry.access.redhat.com/ubi9/ubi
oscap-docker image-cve registry.access.redhat.com/ubi9/ubi \
  --report /tmp/container-report.html

Scan running container
oscap-docker container-cve <container_id> \
  --report /tmp/container-cve.html

  1. DISA STIG Scan (Government/DoD Compliance)
DISA STIG for RHEL 9
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_stig \
  --results /tmp/stig-results.xml \
  --report /tmp/stig-report.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Generate STIG Viewer compatible XCCDF results
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_stig \
  --results-arf /tmp/stig-arf.xml \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Import /tmp/stig-arf.xml into the DISA STIG Viewer tool for checklist generation.


  1. Automate with Cron
Daily compliance scan, report emailed to security team
sudo tee /etc/cron.d/openscap > /dev/null <<'EOF'
0 2 * * * root /usr/bin/oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --results /var/log/oscap/results-$(date +\%Y\%m\%d).xml \
  --report /var/log/oscap/report-$(date +\%Y\%m\%d).html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml \
  && mail -s "OpenSCAP Report $(date +\%Y-\%m-\%d)" \
    -A /var/log/oscap/report-$(date +\%Y\%m\%d).html \
    security@example.com < /dev/null
EOF

sudo mkdir -p /var/log/oscap

Interpreting the Score

Score Range Posture
90, 100% Strong compliance; investigate remaining failures
70, 89% Moderate; address high-severity failures first
50, 69% Weak; systematic hardening needed
Below 50% Critical; remediate before production exposure

Focus on severity=high failures first. Many low-severity failures are cosmetic or context-dependent.


Related Reading


Built by theluckystrike. More at zovo.one