When I first got started with Bandolier, I thought the bulk of the value would be in the security checks of the control system application itself. Getting to this information involves digging into how the app works, identifying the most secure configuration, and finally writing the appropriate compliance check. What I’ve found, however, is that there is a lot of value in something much simpler — identifying operating system best practices tailored to work specifically with the application in question.

Best practices are often compiled for such broad (or narrow, depending on your perspective) applicability that trying to mold them to work with a complex control system can be a difficult task. Add to that vendor support issues and the fear of breaking critical processing and best practice gets ignored in favor of a default configuration that works. Simply put, there is sometimes a gap between “industry best practice” and what works with a particular application. The Bandolier compliance checks are not a silver bullet for these problems, but they certainly will help by identifying a more secure configuration and providing a way to audit it.

Let’s look at a real-world example of how we can use information from the application to dictate the reporting about OS level issues. For many of the applications that we have looked at, the server type is defined in a configuration file. We are able to read those value(s) and determine what checks to run that may be different between server types. Here’s a simplified code snippet from an audit file that highlights this point:

# Check if this is a Historian by looking at the ServerType configuration file

<if>
<condition type: “and”>
<custom_item>
type: FILE_CONTENT_CHECK
description: “Test for HIS in configuration file”
file: “/scada/conf/ServerType”
regex: “HIS”
expect: “HIS”
</item>
</condition>
<then>

# Report the server type

<custom_item>
type: FILE_CONTENT_CHECK
description: “BANDOLIER Application Checks: (INFORMATION) This appears to be an HIS server.”
file: “/scada/conf/ServerType”
regex: “HIS”
expect: “HIS”

# Verify that smb is not running

<custom_item>
type : PROCESS_CHECK
description : “BANDOLIER Application Checks: SMB is not required for operation of the HIS server. This check verifies that it is not running.”
name : “smb”
status : OFF
</custom_item>

# Verify that the crond service is enabled

<custom_item>
type: CHKCONFIG
description: “BANDOLIER Application Checks: The crond service is required for proper operation of the HIS server. This check verifies that it is enabled.”
service: “crond”
levels: “2345”
status: ON
</custom_item>

# Verify that the tcp_max_syn_backlog kernel parameter is set appropriately for the HIS server

<custom_item>
type : FILE_CONTENT_CHECK
description : “BANDOLIER Application Checks: This check examines the tcp_max_syn_backlog setting in /etc/sysctl.conf”
file : “/etc/sysctl.conf”
expect : “net.ipv4.tcp_max_syn_backlog.*”
regex : “net.ipv4.tcp_max_syn_backlog.*=.*4096”
</custom_item>
</item>
</then>
</if>

Even if we never got into application-specific settings, the results from this type of auditing are very meaningful compared to a generic industry standard such as those available from the Center for Internet Security. Those are great benchmarks and certainly serve a purpose but there is something to be said for knowing that the recommended configuration has been tested with the cooperation of the respective application vendors.

Don’t worry, we’re still diving into the juicy details of the control system applications themselves and will be auditing settings there. And we’ll also be doing baseline OS checks that are more global in nature. I just couldn’t help sharing this bit of enlightenment about the “tailored OS checks” I encountered along the way.