Category Archives: Fedora

OpenSCAP XSLT performance improvements for faster SSG builds

As I contribute more and more patches to SCAP Security Guide I got increasingly frustrated with the build speeds. A full SSG build with make -j 4 took 2m21.061s and that’s without any XML validation taking place. I explored a couple of options how I could cut this time significantly. I started by profiling the Makefile and found that a massive amount of time is spent on 2 things.

Generating HTML guides

xslt_optimization_html_guide_chart

We generate a lot of HTML guides as part of SSG builds and we do that over and over for each profile of each product. That’s a lot of HTML guides in total. Generating one HTML guide (namely the RHEL7 PCI-DSS profile from the datastream) took over 3 seconds on my machine. While not a huge number this adds up to a long time with all the guides we are generating. Optimizing HTML guides the first thing I focused on.

I found that we are often selecting huge nodesets over and over instead of reusing them. Fixing this brought the times down roughly 30%. I found a couple other inefficiencies and was able to save an additional 5-10% there. Overall I have optimized it roughly 35-40% in common cases.

During the optimization I have accidentally fixed a pretty jarring bug regarding refine-value and value selectors. We used to select a big nodeset of all cdf:Value elements in the entire document, then select all their cdf:values inside and choose the last based on the selector. This is clearly wrong because we need to select the right cdf:Value with the right ID and then look at only its selectors. Fixing that make the transformation faster as well because the right cdf:Value was already pre-selected.

Old XSLTs:

$ time ../../../shared/utils/build-all-guides.py -j 1 --input ssg-rhel7-ds.xml
real 0m16.736s
user 0m16.349s
sys  0m0.397s

New XSLTs:

$ time ../../../shared/utils/build-all-guides.py -j 1 --input ssg-rhel7-ds.xml
real 0m11.203s
user 0m10.836s
sys  0m0.379s

EDIT: I found more optimization opportunities, latest data as of 2016-08-10:

real 0m3.399s
user 0m2.986s
sys  0m0.409s

I won’t be redoing the entire test-suite and all the graphs but the final savings are much better than it shows in the graph. Generating all RHEL7 SDS guides takes less than 2 seconds on my machine after the optimizations.

Transforming XCCDF 1.1 to 1.2

xslt_optimization_xccdf11_12_chart

It took 30 seconds on my machine to transform RHEL6 XCCDF 1.1 to 1.2. That is just way too much for a simple operation like that. Clearly something was wrong with the XSLT transformation. As soon as I profiled the XSLT using xsltproc --profile I found that we select the entire DOM over and over for every @idref in the tree. That is just silly. I fixed that by using xsl:key and using the very same @idref to element mapping for all lookups. This saved a lot of time.

Doing the RHEL6 XCCDF 1.1 to 1.2 transformation with old XSLTs

real 0m34.635s
user 0m34.585s
sys  0m0.047s

Doing the RHEL6 XCCDF 1.1 to 1.2 transformation with new XSLTs

real 0m0.619s
user 0m0.573s
sys  0m0.045s

The numbers were similar for the RHEL7 XCCDF 1.1 to 1.2 transformation.

Final results for the SSG build

I started with 2m21.061s and my goal was to bring that down to 50%. The final time on my machine after the optimizations with make -j 4 is 1m4.217s. Savings of roughly 55%. Most of those savings are in the XCCDF 1.1 to 1.2 transformation that we do for every product.

The savings are great on my beefy work laptop (i7-5600U) but we should benefit even more from them on our Jenkins slaves that aren’t as powerful. I have yet to test how much they would help there but I estimate it will be 10 minutes for each build.

Correctness

When I suggested to deploy these improvements on our Jenkins slaves, Jan Lieskovsky brought up an important point about correctness. We decided to diff old and new guides and old and new XCCDF 1.2s to be sure we aren’t changing behavior. Please see the attached ZIP file for a test case I created to verify that we haven’t changed behavior. During the process of creating this test case I discovered that I have accidentally fixed a bug mentioned above 🙂 To silence the diffs I have introduced just this bug into the new XSLTs I used. This made the performance slightly worse so keep that in mind when looking at the numbers.

./test_xccdf11_to_12.sh 
Doing the RHEL6 XCCDF 1.1 to 1.2 transformation with old XSLTs

real 0m34.635s
user 0m34.585s
sys  0m0.047s

Doing the RHEL6 XCCDF 1.1 to 1.2 transformation with new XSLTs

real 0m0.619s
user 0m0.573s
sys  0m0.045s

Diffing old_xslt_output/ssg-rhel6-xccdf-1.2.xml and new_xslt_output/ssg-rhel6-xccdf-1.2.xml
The files are the same.


Doing the RHEL7 XCCDF 1.1 to 1.2 transformation with old XSLTs

real 0m33.146s
user 0m33.089s
sys  0m0.050s

Doing the RHEL7 XCCDF 1.1 to 1.2 transformation with new XSLTs

real 0m0.749s
user 0m0.702s
sys  0m0.047s

Diffing old_xslt_output/ssg-rhel7-xccdf-1.2.xml and new_xslt_output/ssg-rhel7-xccdf-1.2.xml
The files are the same.
./test_html_guides.sh 
Doing the RHEL6 and 7 SDS HTML guide transformations with old XSLTs

real 0m39.104s
user 0m38.605s
sys  0m0.491s

Doing the RHEL6 and 7 SDS HTML guide transformations with new XSLTs

real 0m28.974s
user 0m28.531s
sys  0m0.433s

Diffing old_xslt_output/guides_for_diff and new_xslt_output/guides_for_diff
No differences.

UPDATE: Jenkins build times (2016-08-12)

xslt_optimization_ssg_jenkins_build_times
Here is a graph of Jenkins build times, you can see how the build times gradually went lower as optimizations got onto the Jenkins slaves. There are occasional build time spikes caused by load when multiple pull requests were submitted at once but overall the performance has been improved.

Evaluate Virtual Machines for SCAP Compliance

Recently I have been working on oscap-vm — a script that allows SCAP evaluation of virtual machines and virtual machine storage images. In a way it is similar to the other OpenSCAP wrapper utilities — oscap-ssh and oscap-docker. It was merged to OpenSCAP and will be part of 1.2.7 release, so let us introduce it.

oscap-vm mounts the storage of a VM and sets the oscap tool to scan it in offline mode. That means that you can scan a virtual machine from the host without installing OpenSCAP on it — you can perform an agent-less SCAP scan. Root rights are not required, if you are permitted to access and change the VM you are permitted to run oscap-vm on it. The virtual machine storage is mounted read-only, there is no risk of damage to the filesystem. Because of this you cannot automatically remediate a VM using this tool. If you want remediation functionality for virtual machines and containers, please tell us.

Both XCCDF and OVAL evaluation are supported. You can use plain XCCDF files, source datastreams or plain OVAL files.
Let’s go over a few use-cases. I am using a virtual machine called rhel7.2 in the following examples.

Evaluate a running VM

$ oscap-vm domain rhel7.2 xccdf eval --profile xccdf_org.ssgproject.content_profile_stig-rhel7-server-upstream /usr/share/xml/scap/ssg/content/ssg-rhel7-ds.xml 
Mounting guestfs domain 'rhel7.2' to '/tmp/tmp.c69yOdlBNZ'...
Title   Encrypt Partitions
Rule    xccdf_org.ssgproject.content_rule_encrypt_partitions
Ident   CCE-27128-8
Result  notchecked

[snip]

Title   Create Warning Banners for All FTP Users
Rule    xccdf_org.ssgproject.content_rule_ftp_present_banner
Ident   CCE-RHEL7-CCE-TBD
Result  pass

Unmounting '/tmp/tmp.c69yOdlBNZ'...

Evaluate a storage image

$ oscap-vm image /var/lib/libvirt/images/rhel7.2.qcow2 xccdf eval --profile xccdf_org.ssgproject.content_profile_stig-rhel7-server-upstream /usr/share/xml/scap/ssg/content/ssg-rhel7-ds.xml 
Mounting guestfs image '/var/lib/libvirt/images/rhel7.2.qcow2' to '/tmp/tmp.PgfWcB0R4g'...
Title   Encrypt Partitions
Rule    xccdf_org.ssgproject.content_rule_encrypt_partitions
Ident   CCE-27128-8
Result  notchecked

[snip]

Title   Enable SSH Warning Banner
Rule    xccdf_org.ssgproject.content_rule_sshd_enable_warning_banner
Ident   CCE-27314-4
Result  fail

Title   Create Warning Banners for All FTP Users
Rule    xccdf_org.ssgproject.content_rule_ftp_present_banner
Ident   CCE-RHEL7-CCE-TBD
Result  pass

Unmounting '/tmp/tmp.PgfWcB0R4g'...

Check VM for CVE vulnerabilities

$ wget http://www.redhat.com/security/data/oval/Red_Hat_Enterprise_Linux_7.xml
$ oscap-vm domain rhel7.2 oval eval Red_Hat_Enterprise_Linux_7.xml 
Mounting guestfs domain 'rhel7.2' to '/tmp/tmp.NbvfmaKHbZ'...
Definition oval:com.redhat.rhsa:def:20151852: false
Definition oval:com.redhat.rhsa:def:20151840: false
Definition oval:com.redhat.rhsa:def:20151834: false
Definition oval:com.redhat.rhsa:def:20151793: false
[snip]
Definition oval:com.redhat.rhsa:def:20140685: false
Definition oval:com.redhat.rhsa:def:20140684: false
Definition oval:com.redhat.rhsa:def:20140680: false
Definition oval:com.redhat.rhsa:def:20140679: false
Definition oval:com.redhat.rhsa:def:20140678: false
Definition oval:com.redhat.rhsa:def:20140675: false
Evaluation done.
Unmounting '/tmp/tmp.NbvfmaKHbZ'...

SCAP Security Guide now has an HTML guide for each profile

In the past the SCAP Security Guide project built one or just a few HTML guides for some chosen profiles. The build system also used a special profile called allrules which is no longer supported since OpenSCAP 1.1.0. This caused issues when building SSG against new versions of OpenSCAP.

To fix it once and for all I have created a pull request that has been merged and has been released as part of SSG 0.1.24. Since then SSG builds one guide for each profile and provides an index file that allows user to switch between the profiles. The reasoning for building so many guides is that if we ship a profile it is important enough to warrant shipping an HTML guide for it as well.

Here is how the new profile switcher looks like:

ssg_new_guides

I have uploaded the RHEL6 guides with the profile switcher to fedorapeople, take a look:

https://mpreisle.fedorapeople.org/ssg_new_guides/ssg-rhel6-guide-index.html

We plan to install these guides in downstream packages (e.g. Fedora). Instead of bundling them with the main package we will create a subpackage -doc with the guides and other optional documentation material.

Feedback appreciated! Do you think we should upload these guides somewhere for people to browse? Are there any features missing?

Customizing HTML reports and guides in OpenSCAP 1.1.0 and higher

Introduction

OpenSCAP 1.1.0 introduced brand new HTML5 report and guide styles. These were a result of an almost complete rewrite of all the XSLT code. See openscap HTML report redesign for more info.

This rewrite changed the way the reports and guides can be customized. This blog post will go through all the steps necessary to customize the reports from both the downstream packager perspective and the user perspective. We will focus on branding because this is the most requested customization. Users will be able to change the logo, header and footer of reports and guides.

Downstream branding

After installing openscap of version 1.1.0 or higher, let us look at various files in /usr/share/openscap/xslt.

$ ls -1 /usr/share/openscap/xsl/

legacy-fixtpl-bash.xml
legacy-fix.xsl
legacy-xccdf-share.xsl
oval-results-report.xsl
xccdf_1.1_remove_dangling_sub.xsl
xccdf_1.1_to_1.2.xsl
xccdf-branding.xsl
xccdf-guide-impl.xsl
xccdf-guide.xsl
xccdf-report-impl.xsl
xccdf-report-oval-details.xsl
xccdf-report.xsl
xccdf-resources.xsl
xccdf-share.xsl

The xccdf-report.xsl is the entry point to the XSLT stylesheet, it specifies which parameters are needed and does some initial negotiation like guessing which benchmark the user wants to generate for. The xccdf-report-impl.xsl is the most interesting file, it contains most of the logic. xccdf-share.xsl contains various template code needed in both guide and report, to avoid code duplication.

Let us focus on a file called xccdf-branding.xsl. This file was designed specifically to help with downstream branding. If we look inside we will see 5 named templates:

  • xccdf-branding-logo
  • xccdf-report-header
  • xccdf-report-footer
  • xccdf-guide-header
  • xccdf-guide-footer

Their meaning should be self explanatory. The downstreams can patch those to insert a different logo or even different texts. Changes to this file will affect every user that runs oscap xccdf generate guide or oscap xccdf generate report.

Example of changed xccdf-report-header – different header:

<xsl:template name="xccdf-report-header">
    <nav class="navbar navbar-default" role="navigation">
        <div class="navbar-header" style="float: none">
            <a class="navbar-brand" href="#">
                <xsl:call-template name="xccdf-branding-logo"/>
            </a>
            <div><h1>Security Compliance Report</h1></div>
        </div>
    </nav>
</xsl:template>

Example of changed xccdf-report-footer – downstream ticket system hint:

<xsl:template name="xccdf-report-footer">
    <footer id="footer">
        <div class="container">
            <p class="muted credit">
                Please report any issues to the <a href="https://bugs.my-cool-distro.tld">ticket system</a>. Generated using <a href="http://www.open-scap.org">OpenSCAP</a>
                <xsl:if test="$oscap-version">
                    <xsl:value-of select="concat(' ', $oscap-version)"/>
                </xsl:if>
            </p>
        </div>
    </footer>
</xsl:template>

The OpenSCAP team would really appreciate if you kept some link to the upstream but the license does not enforce or even require that.

User branding

Sometimes you might want to change the branding just for this one use-case without affecting all users on the system.

This is not commonly used and as such may have more issues than when using the system-wide XSLTs!

Let us copy the XSLTs as they are into a folder where we will do all the changes we need.

cp -r /usr/share/openscap/xsl ~/custom-oscap-xsl
cd ~/custom-oscap-xsl

We can now do all the customizations similarly to the previous section. Lets change the header from OpenSCAP Evaluation Report to Security Compliance Report in xccdf-branding.xsl. Save the changes and proceed to generate a report. Instead of using oscap xccdf generate report we have to use oscap xccdf generate custom --stylesheet $OUR_STYLESHEET

cd ~/custom-oscap-xsl
oscap xccdf generate custom --stylesheet ~/custom-oscap-xsl/xccdf-report.xsl arf.xml > report.html
firefox report.html

We can see that the report has “Security Compliance Report” as heading instead of “OpenSCAP Evaluation Report”.

The oscap xccdf generate custom code path in the oscap tool does not offer as many parameters as generate report or generate guide do. There parameters may have to be passed in a different way, even hard-coded into the XSL template if necessary! It all depends on the use-case.

What about OpenSCAP 1.0.x?

The method outlined in User branding also works with OpenSCAP 1.0.x. While the new reports are not regularly tested with OpenSCAP 1.0.x they seem to work fine. Use at your own risk!

$ cd ~/custom-oscap-xsl
$ oscap --v
OpenSCAP command line tool (oscap) 1.0.11
Copyright 2009--2015 Red Hat Inc., Durham, North Carolina.
...

oscap xccdf generate custom --stylesheet ~/custom-oscap-xsl/xccdf-report.xsl arf.xml > report.html
firefox report.html

Scanning remote machines with OpenSCAP

Introduction

oscap-ssh has recently been merged into OpenSCAP 1.2.x and is available in the OpenSCAP 1.2.3 release, see https://github.com/OpenSCAP/openscap/pull/69. This new tool enables painless transparent remote machine scanning with the familiar oscap argument syntax. The functionality was inspired by SCAP Workbench remote scan.

Prerequisites

The script is designed to be as lean as possible. It is usable even outside the openscap context. It requires just bash, ssh, scp and mktemp to perform OVAL and XCCDF evaluation of remote machines. These tools are readily available on all Linux distributions, BSDs, MacOS X and even Windows via Cygwin.

The remote machine has to have oscap installed and in $PATH. This can be accomplished by installing openscap-scanner (or openscap-utils if openscap-scanner is not available) on the remote machine. On the local machine in most cases you just need to download the script and chmod +x it.

What follows is a walk through a typical usage of the script. The output has been shortened for brevity. OVAL evaluation would be very similar, the documentation included in the script should be enough to get it working.

Usage

oscap-ssh user@host SSH_PORT --v
oscap-ssh user@host SSH_PORT info INPUT_CONTENT
oscap-ssh user@host SSH_PORT xccdf eval INPUT_CONTENT
oscap-ssh user@host SSH_PORT oval eval INPUT_CONTENT

Example 1

The following command evaluates a remote Fedora machine as root. HTML report is written out as report.html on the local machine. Can be executed from any machine that has ssh, scp and bash. The local machine does not need to have openscap installed.

$ oscap-ssh root@192.168.1.13 22 xccdf eval --profile xccdf_org.ssgproject.content_profile_common --report report.html /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml

The output:

Connecting to 'root@192.168.1.13' on port '22'...
root@192.168.1.13's password:
Connected!
Copying input file '/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml' to remote working directory '/tmp/tmp.yEsdWV54ry'...

Starting the evaluation...
Title   gpgcheck Enabled In Main Yum Configuration
Rule    xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Result  pass

Title   gpgcheck Enabled For All Yum Package Repositories
Rule    xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled
Result  fail

[snip]

Title   Enable the NTP Daemon
Rule    xccdf_org.ssgproject.content_rule_service_ntpd_enabled
Result  fail

Title   Specify a Remote NTP Server
Rule    xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server
Result  fail

oscap exit code: 2
Copying back requested files...

Removing remote temporary directory...
Disconnecting ssh and removing master ssh socket directory...

report.html is now on the local machine and can be opened there. The connection to the remote machine is closed, no temporary data remains on the remote machine.

Example 2

A more full example, uses a tailoring file and also copies back ARF and XCCDF results. The tailoring file is automatically copied from local machine to remote.

$ oscap-ssh root@192.168.1.13 22 xccdf eval --profile xccdf_org.ssgproject.content_profile_common --report report.html --results results.xml --results-arf arf.xml --tailoring-file ssg-fedora-ds-tailoring.xml /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml

The output:

Connecting to 'root@192.168.1.13' on port '22'...
root@192.168.1.13's password:
Connected!
Copying input file '/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml' to remote working directory '/tmp/tmp.yVy6snyC88'...

Copying tailoring file 'ssg-fedora-ds-tailoring.xml' to remote working directory '/tmp/tmp.yVy6snyC88'...

Starting the evaluation...
Title gpgcheck Enabled In Main Yum Configuration
Rule xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Result pass

Title gpgcheck Enabled For All Yum Package Repositories
Rule xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled
Result fail

[snip]

Title Enable the NTP Daemon
Rule xccdf_org.ssgproject.content_rule_service_ntpd_enabled
Result fail

Title Specify a Remote NTP Server
Rule xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server
Result fail

oscap exit code: 2
Copying back requested files...

Removing remote temporary directory...
Disconnecting ssh and removing master ssh socket directory...

Future plans

Most if not all SCAP content requires root access to evaluate. So it is expected that the user will login as root to a remote machine. At the same time the guidances recommend to disallow root ssh access. This creates ironic situations where remote scanning and remediating the machine cuts of the access.

We hope to solve this in the future by logging in as normal user and running sudo before scanning.

Conclusion

Scanning remote machines is now almost as easy as scanning local ones. For use-cases where the user has public-key authentication setup the scanning is truly painless.

I believe this script might be very valuable for content authors and auditors. In the future I expect SCAP Workbench to use this script instead of its own code for remote scanning. The migration will have to wait until OpenSCAP 1.2.3+ is available on platforms where Workbench ships.