Configure automated compliance scanning with OpenSCAP and audit reporting

Intermediate 25 min May 13, 2026 62 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up OpenSCAP security compliance scanning with automated systemd timers, generate HTML and XML audit reports, and configure SCAP security profiles for continuous compliance monitoring.

Prerequisites

  • Root or sudo access
  • Basic Linux command line knowledge
  • Understanding of compliance frameworks

What this solves

OpenSCAP provides automated security compliance scanning against industry standards like CIS benchmarks, NIST 800-53, and PCI DSS. This tutorial shows you how to install OpenSCAP, configure security profiles, set up automated scanning with systemd timers, and generate detailed compliance reports in HTML and XML formats for audit trails.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest OpenSCAP tools and dependencies.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install OpenSCAP and dependencies

Install the core OpenSCAP scanner, utilities, and security content packages that contain the compliance profiles.

sudo apt install -y libopenscap8 openscap-utils scap-security-guide ssg-debderived ssg-base
sudo dnf install -y openscap openscap-utils scap-security-guide

Verify OpenSCAP installation

Check that OpenSCAP is installed correctly and view the available scanning capabilities.

oscap --version
oscap --help

Locate security content profiles

Find the installed SCAP security content that contains compliance profiles for different standards.

ls -la /usr/share/xml/scap/ssg/content/
oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
ls -la /usr/share/xml/scap/ssg/content/
oscap info /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml

List available compliance profiles

View all available security profiles to choose the appropriate compliance standard for your environment.

oscap info --profiles /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
oscap info --profiles /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml

Create compliance scan directories

Set up directories to store scan results, reports, and configuration files with proper permissions.

sudo mkdir -p /var/lib/openscap/{reports,results,logs}
sudo mkdir -p /etc/openscap/profiles
sudo chmod 755 /var/lib/openscap
sudo chmod 755 /var/lib/openscap/{reports,results,logs}

Run initial compliance scan

Perform a test scan using the CIS benchmark profile to verify everything works correctly.

sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis_level1_server \
  --results /var/lib/openscap/results/initial-scan-results.xml \
  --report /var/lib/openscap/reports/initial-scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml
sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis \
  --results /var/lib/openscap/results/initial-scan-results.xml \
  --report /var/lib/openscap/reports/initial-scan-report.html \
  /usr/share/xml/scap/ssg/content/ssg-almalinux9-ds.xml

Configure SCAP security profiles

Create custom profile configuration

Set up a configuration file to define which profiles to scan and customize scanning parameters.

# OpenSCAP Compliance Configuration

Profile selection and scanning parameters

Default profile for automated scanning

DEFAULT_PROFILE="xccdf_org.ssgproject.content_profile_cis_level1_server"

Content location

CONTENT_PATH="/usr/share/xml/scap/ssg/content/ssg-ubuntu2004-ds.xml"

Results and reports directories

RESULTS_DIR="/var/lib/openscap/results" REPORTS_DIR="/var/lib/openscap/reports" LOGS_DIR="/var/lib/openscap/logs"

Report formats to generate

GENERATE_HTML="true" GENERATE_XML="true" GENERATE_ARF="false"

Retention policy (days)

RETENTION_DAYS="30"

Email notifications

EMAIL_ALERTS="false" EMAIL_ADDRESS="admin@example.com"

Create compliance scanning script

Build an automated script that reads the configuration and performs compliance scans with proper logging.

#!/bin/bash

OpenSCAP Compliance Scanner Script

Automated compliance scanning with reporting

set -euo pipefail

Source configuration

CONFIG_FILE="/etc/openscap/profiles/compliance-config.conf" if [[ -f "$CONFIG_FILE" ]]; then source "$CONFIG_FILE" else echo "Configuration file not found: $CONFIG_FILE" exit 1 fi

Generate timestamp for unique filenames

TIMESTAMP=$(date +"%Y%m%d-%H%M%S") HOSTNAME=$(hostname -s)

Define output files

RESULT_FILE="$RESULTS_DIR/compliance-results-$HOSTNAME-$TIMESTAMP.xml" REPORT_FILE="$REPORTS_DIR/compliance-report-$HOSTNAME-$TIMESTAMP.html" LOG_FILE="$LOGS_DIR/compliance-scan-$TIMESTAMP.log"

Logging function

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" } log "Starting OpenSCAP compliance scan" log "Profile: $DEFAULT_PROFILE" log "Content: $CONTENT_PATH"

Check if content file exists

if [[ ! -f "$CONTENT_PATH" ]]; then log "ERROR: Content file not found: $CONTENT_PATH" exit 1 fi

Run the compliance scan

log "Executing compliance scan..." if oscap xccdf eval \ --profile "$DEFAULT_PROFILE" \ --results "$RESULT_FILE" \ --report "$REPORT_FILE" \ "$CONTENT_PATH" >> "$LOG_FILE" 2>&1; then SCAN_STATUS="SUCCESS" else SCAN_STATUS="COMPLETED_WITH_FINDINGS" fi log "Scan completed with status: $SCAN_STATUS" log "Results saved to: $RESULT_FILE" log "Report saved to: $REPORT_FILE"

Generate summary

if [[ -f "$RESULT_FILE" ]]; then TOTAL_RULES=$(oscap xccdf generate report "$RESULT_FILE" | grep -o 'Rule.*:' | wc -l || echo "0") log "Total rules evaluated: $TOTAL_RULES" fi

Cleanup old files based on retention policy

find "$RESULTS_DIR" -name "*.xml" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true find "$REPORTS_DIR" -name "*.html" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true find "$LOGS_DIR" -name "*.log" -mtime +"$RETENTION_DAYS" -delete 2>/dev/null || true log "Compliance scan completed successfully" exit 0

Make the script executable

Set proper permissions on the scanning script to allow execution by root and the system.

sudo chmod 755 /usr/local/bin/openscap-compliance-scan.sh
sudo chown root:root /usr/local/bin/openscap-compliance-scan.sh

Update content path for distribution

Modify the configuration file to use the correct content path for your Linux distribution.

sudo sed -i 's|ssg-ubuntu2004-ds.xml|ssg-ubuntu2004-ds.xml|g' /etc/openscap/profiles/compliance-config.conf
sudo sed -i 's|ssg-ubuntu2004-ds.xml|ssg-almalinux9-ds.xml|g' /etc/openscap/profiles/compliance-config.conf
sudo sed -i 's|xccdf_org.ssgproject.content_profile_cis_level1_server|xccdf_org.ssgproject.content_profile_cis|g' /etc/openscap/profiles/compliance-config.conf

Set up automated scanning with systemd timers

Create systemd service unit

Define a systemd service that runs the compliance scanning script with proper environment and security settings.

[Unit]
Description=OpenSCAP Compliance Scanner
After=network.target
Wants=network.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/usr/local/bin/openscap-compliance-scan.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=openscap-compliance

Security settings

NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=/var/lib/openscap

Resource limits

TimeoutSec=1800 MemoryMax=512M [Install] WantedBy=multi-user.target

Create systemd timer unit

Set up a timer to run compliance scans automatically on a regular schedule.

[Unit]
Description=Run OpenSCAP compliance scan
Requires=openscap-compliance.service

[Timer]

Run daily at 2 AM

OnCalendar=daily Persistent=true

Add randomization to avoid system load spikes

RandomizedDelaySec=1800

Ensure timer doesn't accumulate if system was down

AccuracySec=1h [Install] WantedBy=timers.target

Enable and start the systemd timer

Activate the automated scanning timer and verify it's scheduled correctly.

sudo systemctl daemon-reload
sudo systemctl enable openscap-compliance.timer
sudo systemctl start openscap-compliance.timer
sudo systemctl status openscap-compliance.timer

Test the automated scan

Run the service manually to verify the automation works correctly before relying on the timer.

sudo systemctl start openscap-compliance.service
sudo systemctl status openscap-compliance.service
sudo journalctl -u openscap-compliance.service -n 20

Check timer schedule

Verify when the next automated scan is scheduled to run.

sudo systemctl list-timers openscap-compliance.timer

Generate HTML and XML compliance reports

Create report generation script

Build a script to generate comprehensive reports from existing scan results in multiple formats.

#!/bin/bash

OpenSCAP Report Generator

Generate reports from existing scan results

set -euo pipefail

Configuration

RESULTS_DIR="/var/lib/openscap/results" REPORTS_DIR="/var/lib/openscap/reports" LOGS_DIR="/var/lib/openscap/logs"

Check if results directory exists

if [[ ! -d "$RESULTS_DIR" ]]; then echo "Results directory not found: $RESULTS_DIR" exit 1 fi

Find the most recent result file

LATEST_RESULT=$(find "$RESULTS_DIR" -name "*.xml" -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-) if [[ -z "$LATEST_RESULT" ]]; then echo "No scan results found in $RESULTS_DIR" exit 1 fi echo "Processing results from: $LATEST_RESULT"

Generate timestamp for reports

TIMESTAMP=$(date +"%Y%m%d-%H%M%S") HOSTNAME=$(hostname -s)

Generate HTML report

HTML_REPORT="$REPORTS_DIR/compliance-report-$HOSTNAME-$TIMESTAMP.html" echo "Generating HTML report..." oscap xccdf generate report "$LATEST_RESULT" > "$HTML_REPORT" echo "HTML report saved: $HTML_REPORT"

Generate detailed XML report

XML_REPORT="$REPORTS_DIR/compliance-detailed-$HOSTNAME-$TIMESTAMP.xml" echo "Generating detailed XML report..." cp "$LATEST_RESULT" "$XML_REPORT" echo "XML report saved: $XML_REPORT"

Generate summary statistics

SUMMARY_FILE="$REPORTS_DIR/compliance-summary-$HOSTNAME-$TIMESTAMP.txt" echo "Generating compliance summary..." { echo "OpenSCAP Compliance Summary" echo "Generated: $(date)" echo "Hostname: $HOSTNAME" echo "Source: $LATEST_RESULT" echo "" # Extract rule results echo "Rule Results:" oscap xccdf generate report "$LATEST_RESULT" | grep -E "(pass|fail|error|unknown|notapplicable|notchecked)" | \ sed 's/<[^>]*>//g' | sort | uniq -c | sort -rn || echo "Unable to extract rule statistics" echo "" echo "Report files generated:" echo " HTML: $HTML_REPORT" echo " XML: $XML_REPORT" echo " Summary: $SUMMARY_FILE" } > "$SUMMARY_FILE" echo "Summary saved: $SUMMARY_FILE" echo "Report generation completed successfully" exit 0

Make report generator executable

Set appropriate permissions on the report generation script.

sudo chmod 755 /usr/local/bin/openscap-report-generator.sh
sudo chown root:root /usr/local/bin/openscap-report-generator.sh

Generate reports from existing scans

Run the report generator to create HTML and XML reports from your compliance scan results.

sudo /usr/local/bin/openscap-report-generator.sh

View generated reports

List the generated reports and check their contents to verify successful generation.

ls -la /var/lib/openscap/reports/
head -20 /var/lib/openscap/reports/compliance-summary-$(hostname -s)-*.txt

Set up web server for report viewing

Configure a simple web server to view HTML reports through a browser interface.

sudo apt install -y nginx
sudo systemctl enable --now nginx
sudo dnf install -y nginx
sudo systemctl enable --now nginx
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

Configure Nginx for compliance reports

Create a virtual host to serve compliance reports securely with basic authentication.

server {
    listen 80;
    server_name compliance.example.com;
    
    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name compliance.example.com;
    
    # SSL configuration (replace with your certificates)
    ssl_certificate /etc/ssl/certs/compliance.crt;
    ssl_certificate_key /etc/ssl/private/compliance.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    
    # Document root for compliance reports
    root /var/lib/openscap/reports;
    index index.html;
    
    # Basic authentication
    auth_basic "Compliance Reports Access";
    auth_basic_user_file /etc/nginx/.htpasswd-compliance;
    
    # Security headers
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Serve HTML reports
    location ~* \.html$ {
        try_files $uri =404;
        expires 1h;
    }
    
    # Deny access to XML files and logs
    location ~* \.(xml|log)$ {
        deny all;
        return 404;
    }
    
    # Logging
    access_log /var/log/nginx/compliance-reports.access.log;
    error_log /var/log/nginx/compliance-reports.error.log;
}

Verify your setup

Check that all components are working correctly and compliance scanning is automated.

# Check OpenSCAP installation
oscap --version

Verify systemd timer is active

sudo systemctl status openscap-compliance.timer sudo systemctl list-timers openscap-compliance.timer

Check recent scan results

ls -la /var/lib/openscap/results/ ls -la /var/lib/openscap/reports/

View compliance service logs

sudo journalctl -u openscap-compliance.service -n 20

Test manual scan execution

sudo /usr/local/bin/openscap-compliance-scan.sh

Verify report generation

sudo /usr/local/bin/openscap-report-generator.sh

Check disk space usage

du -sh /var/lib/openscap/

Common issues

SymptomCauseFix
Scanner fails with "content not found" Incorrect path to SCAP content files Check /usr/share/xml/scap/ssg/content/ and update config file paths
Permission denied writing reports Incorrect directory permissions sudo chmod 755 /var/lib/openscap/{reports,results,logs}
Systemd timer not running Timer unit not enabled sudo systemctl enable --now openscap-compliance.timer
HTML reports show formatting errors Malformed XML results file Re-run scan with --oval-results flag and check content file integrity
Scan takes too long and times out Resource constraints or large profile Increase TimeoutSec in service unit and add memory limits
Old reports not being cleaned up Retention policy not working Check script has write access to directories and RETENTION_DAYS setting

Next steps

Running this in production?

Need this managed at scale? Setting up OpenSCAP compliance scanning once is straightforward. Keeping it updated with new security profiles, managing compliance across multiple environments, and maintaining audit trails is the harder operational work. See how we run infrastructure like this for European teams with compliance requirements.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.