Skip to main content
CleanStart

Knowledge Hub

OpenSCAP: Automated Compliance Assessment and Hardening

Running OpenSCAP Scans Against Container Images

OpenSCAP (Security Content Automation Protocol) provides automated scanning for CIS, STIG, and other compliance frameworks. CleanStart integrates OpenSCAP for continuous compliance verification.

What OpenSCAP Does

OpenSCAP (Security Content Automation Protocol) is the industry-standard automated compliance tool. It analyzes container images by comparing them against CIS Benchmark controls, DISA STIG security controls, and OVAL (Open Vulnerability and Assessment Language) definitions. During the scan, OpenSCAP evaluates each control, generates a comprehensive report, and calculates an overall compliance score. The output is delivered in standardized formats including XCCDF, JSON, and HTML reports.

Installation

Install OpenSCAP tools by running sudo apt-get install -y openscap-scanner scap-security-guide. Verify installation by checking the version with oscap --version and downloading STIG and CIS profiles by running sudo oscap info /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml.

CIS Docker Benchmark Scan

Run CIS Scan

Scan an image for CIS Docker Benchmark compliance using:

# Scan image for CIS Docker Benchmark complianceoscap xccdf eval \  --profile xccdf_org.ssgproject.content_profile_docker_cis \  --report cis-report.html \  --results cis-results.xml \  /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml # Output: HTML report with CIS findings

CIS Scan Output

A CIS Docker Benchmark scan generates a detailed report organized by control. Control 4.1 (User) checks the docker_non_root_user rule and should pass with the rationale that the container runs as non-root. Control 4.2 (Image) evaluates the docker_minimal_image rule, which passes when the base image is under 50MB. Control 5.28 (Capabilities) checks whether all capabilities are dropped via the docker_drop_all_capabilities rule—this commonly fails if capabilities are not explicitly dropped in the Dockerfile. The summary line shows that 87 out of 94 controls passed, representing 92% compliance.

STIG Scanning

Run STIG Scan

Scan for DISA STIG compliance with Docker containers by running:

# Scan for DISA STIG compliance (Docker)oscap xccdf eval \  --profile xccdf_org.ssgproject.content_profile_stig \  --report stig-report.html \  --results stig-results.xml \  /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml

STIG Report Differences

STIG reports are more stringent than CIS reports in several ways. STIG defines more controls (150+ vs 94 for CIS), provides less flexibility in configurations, includes military-specific requirements, and may flag acceptable CIS configurations as non-compliant.

OVAL Definitions

OVAL (Open Vulnerability and Assessment Language) defines specific checks using XML. Here's an example OVAL definition that checks for non-root user:

<!-- Example OVAL definition: Check for non-root user --><definition class="compliance" id="oval:org.ssgproject.content:def:docker_non_root_user" version="1">  <metadata>    <title>Check Docker container runs as non-root user</title>    <description>Verify the container's USER directive is not root</description>  </metadata>  <criteria>    <criterion comment="USER is not root" test_ref="oval:org.ssgproject.content:tst:docker_user_test"/>  </criteria></definition> <tests>  <file_test id="oval:org.ssgproject.content:tst:docker_user_test" check="all">    <object object_ref="oval:org.ssgproject.content:obj:dockerfile_user_object"/>    <state state_ref="oval:org.ssgproject.content:ste:user_state"/>  </file_test></tests> <objects>  <file_object id="oval:org.ssgproject.content:obj:dockerfile_user_object">    <path>/Dockerfile</path>    <filename>Dockerfile</filename>    <pattern operation="pattern match">^USER\s+(?!root).*$</pattern>  </file_object></objects> <states>  <entity_state id="oval:org.ssgproject.content:ste:user_state">    <entity_check>all_exist</entity_check>  </entity_state></states>

Custom OVAL Definitions

Create custom checks by defining your own OVAL definitions in XML files, for example:

<!-- custom-checks.oval.xml --><?xml version="1.0" encoding="UTF-8"?><oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5">  <definition id="custom:def:app_version_check" class="compliance" version="1">    <metadata>      <title>Application version is current</title>      <description>Verify app version matches approved baseline</description>    </metadata>    <criteria>      <criterion comment="App version >= 2.0.0" test_ref="custom:tst:version_test"/>    </criteria>  </definition>   <tests>    <file_test id="custom:tst:version_test" check="at least one">      <object object_ref="custom:obj:version_file"/>      <state state_ref="custom:ste:version_state"/>    </file_test>  </tests></oval_definitions>

XCCDF Profiles

XCCDF (Extensible Configuration Checklist Description Format) groups controls into profiles. Here are examples of standard and custom profiles:

<!-- Standard profiles --><Profile id="xccdf_org.ssgproject.content_profile_docker_cis">  <title>CIS Docker Benchmark</title>  <description>Security hardening based on CIS Docker Benchmark</description>  <select idref="xccdf_org.ssgproject.content_rule_docker_non_root_user" selected="true"/>  <select idref="xccdf_org.ssgproject.content_rule_docker_minimal_image" selected="true"/>  <!-- ... more rules ... --></Profile> <!-- Custom profile for your organization --><Profile id="custom:profile:company_docker_security">  <title>Company Docker Security Standard</title>  <description>Custom hardening rules for company workloads</description>  <refine-value idref="docker_version" selector="1.24+"/>  <!-- Select specific rules relevant to your organization -->  <select idref="xccdf_org.ssgproject.content_rule_docker_non_root_user" selected="true"/>  <select idref="xccdf_org.ssgproject.content_rule_docker_drop_all_capabilities" selected="true"/></Profile>

Kubernetes SCAP Scanning

Scan Kubernetes Configuration

Scan Kubernetes configurations using OpenSCAP by running:

# Download Kubernetes SCAP contentsudo oscap info /usr/share/xml/scap/ssg/content/ssg-kubernetes-ds.xml # Scan Kubernetes manifestsoscap xccdf eval \  --profile xccdf_org.ssgproject.content_profile_k8s \  --report k8s-report.html \  --results k8s-results.xml \  /usr/share/xml/scap/ssg/content/ssg-kubernetes-ds.xml

Kubernetes Checks

Kubernetes-specific OVAL definitions check for network policies and other security requirements:

<!-- Kubernetes-specific OVAL: Check for network policies --><definition id="k8s:def:network_policy_enforced" class="compliance">  <criteria>    <criterion comment="Network policies are defined" test_ref="k8s:tst:network_policy_test"/>  </criteria></definition>

Integration with CI/CD

GitHub Actions Scanning

Integrate OpenSCAP scanning into your CI/CD pipeline using GitHub Actions:

name: OpenSCAP Compliance Check on: [push, pull_request] jobs:  openscap-scan:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4       - name: Install OpenSCAP        run: |          sudo apt-get update          sudo apt-get install -y openscap-scanner scap-security-guide       - name: Build image        run: docker build -t myapp:${{ github.sha }} .       - name: Save Dockerfile for scanning        run: cp Dockerfile /tmp/Dockerfile       - name: Run OpenSCAP CIS scan        run: |          oscap xccdf eval \            --profile xccdf_org.ssgproject.content_profile_docker_cis \            --report cis-report.html \            /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml       - name: Check for failures        run: |          if grep -q "FAIL" cis-report.html; then            echo "OpenSCAP found compliance issues"            exit 1          fi       - name: Upload report        uses: actions/upload-artifact@v3        with:          name: openscap-report          path: cis-report.html

Kubernetes Admission Controller

Configure a Kubernetes admission controller to validate compliance:

apiVersion: admissionregistration.k8s.io/v1kind: ValidatingWebhookConfigurationmetadata:  name: openscap-validationwebhooks:- name: openscap.company.com  failurePolicy: Fail  sideEffects: None  clientConfig:    service:      name: openscap-validator      namespace: default      path: "/validate"  rules:  - operations: ["CREATE", "UPDATE"]    apiGroups: [""]    apiVersions: ["v1"]    resources: ["pods", "deployments"]

Scanning Results Parsing

Parse XCCDF Results

Parse OpenSCAP results programmatically using Python:

# Parse OpenSCAP resultsimport xml.etree.ElementTree as ET tree = ET.parse('cis-results.xml')root = tree.getroot() # Extract test resultsfor result in root.findall('.//{http://checklists.nist.gov/xccdf/1.2}test-result'):    test_id = result.get('id')    end_time = result.get('end-time')     for rule_result in result.findall('{http://checklists.nist.gov/xccdf/1.2}rule-result'):        rule_id = rule_result.get('idref')        result_val = rule_result.find('{http://checklists.nist.gov/xccdf/1.2}result')        status = result_val.text         print(f"{rule_id}: {status}") # Generate compliance reportpassed = sum(1 for r in results if r.status == "pass")failed = sum(1 for r in results if r.status == "fail")print(f"Compliance: {passed}/{passed+failed} ({100*passed/(passed+failed):.1f}%)")

Custom XCCDF Profiles

Create organization-specific profiles by defining your own XCCDF benchmark file:

<!-- company-docker-profile.xml --><?xml version="1.0" encoding="UTF-8"?><Benchmark xmlns="http://checklists.nist.gov/xccdf/1.2">  <Profile id="custom:profile:company_docker">    <title>Company Docker Security Baseline</title>    <description>Hardening profile for company production workloads</description>     <!-- CIS controls we require -->    <select idref="cis_4.1" selected="true"/>  <!-- Non-root user -->    <select idref="cis_4.2" selected="true"/>  <!-- Minimal image -->    <select idref="cis_5.1" selected="true"/>  <!-- CPU limits -->    <select idref="cis_5.4" selected="true"/>  <!-- Read-only root -->    <select idref="cis_5.28" selected="true"/> <!-- Drop capabilities -->     <!-- CIS controls we don't require -->    <select idref="cis_4.11" selected="false"/>  <!-- SSH (N/A for containers) -->     <!-- Custom controls -->    <select idref="custom:rule:app_signed" selected="true"/>  <!-- Image signed -->    <select idref="custom:rule:no_secrets" selected="true"/>  <!-- No hardcoded secrets -->  </Profile></Benchmark>

Use your custom profile by running:

oscap xccdf eval \  --profile custom:profile:company_docker \  --report company-report.html \  company-docker-profile.xml

OpenSCAP Best Practices

Several best practices ensure effective compliance scanning. Create an organization-specific profile rather than using generic profiles. Scan every build, not just releases, to catch compliance issues early. Track compliance trends over time to identify patterns and improvements. Document and approve exceptions through a formal process. Re-baseline when security guidance changes to stay current with evolving standards.

Troubleshooting

OpenSCAP Says "No Applicable Items"

If OpenSCAP reports no applicable items, verify the profile exists, check profile syntax, and list available profiles:

# Verify profile existsoscap info /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml # Check profile syntaxoscap xccdf validate-rules company-docker-profile.xml # List available profilesoscap xccdf list-profiles /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml

Custom OVAL Not Loading

If custom OVAL definitions aren't loading, validate the OVAL syntax and check namespace declarations:

# Validate OVAL syntaxoscap oval validate custom-checks.oval.xml # Check namespace declarations in XMLxmllint --schema /usr/share/xml/xsd/oval-definitions-5.11.xsd custom-checks.oval.xml

Compliance Reporting

Generate detailed compliance reports for documentation and auditing:

# Generate detailed compliance report (machine-readable)oscap xccdf eval \  --profile xccdf_org.ssgproject.content_profile_docker_cis \  --report cis-report.html \  --results cis-results.xml \  --rfsession session-id-123 \  /usr/share/xml/scap/ssg/content/ssg-docker-ds.xml # Convert to JSON for automationoscap xccdf-results export-json cis-results.xml > cis-results.json

See Also

CIS Hardening: cis-hardening.md — CIS controls explained. STIG Hardening: stig-hardening.md — DISA STIG controls. Compliance Verification: ../runtime-evidence/ebpf-falco-integration.md — Runtime verification.