
Automated compliance with Chef InSpec
Self-Regulating
IT compliance is indispensable in both small and large businesses and should be monitored wherever possible. The Chef InSpec open source framework helps admins apply rules on servers in a fully automated process by checking system status against a list of policies and alerting the admin if a system violates them. In this article, I look at setting up and using the software in a practical application.
Chef InSpec comes from a company that feels very much at home in the areas of automation and compliance: Chef, the provider behind the automation platform of the same name. The software is based on its own declarative script language (DSL), a kind of pseudo-programming language. In this language, the administrator describes the rules in a fixed syntax, which InSpec checks later.
InSpec offers the user a few simplifications. For example, it makes available ready-to-use functions for checking certain configuration files or their content (Figure 1), which helps avoid a great deal of manual work. Everyone is familiar with configuration files. They have certain basic formats (e.g., .ini
) in which they can be written. The administrator would need to retype the keywords the developers of a program use for their configurations for each service. For this reason, the InSpec developers provide the user with parsers to match a large number of common Unix services out of the box.

If you have worked with Ansible before, you will notice some similarities with InSpec. Like Ansible, the program expects input files in YAML format. Similar to Ansible playbooks, InSpec profiles offer a way to define rules for certain types of servers and apply them en bloc. The manufacturer offers the program in pre-packaged versions for various systems on its website [1], where you will also find the installation instructions. Granted, Chef has a pretty easy task, because the software is written in the Ruby script language. All you need on the target system is a functional Ruby environment, and that is easy to set up. To check whether the installation has worked, call inspec
at the command line. If inspec -v
outputs the version number, you are ready to go.
Anatomy of a Profile
The developers have made sure that InSpec profiles can be stored in a version control system. All files of InSpec profiles are written in plain text and can be stored centrally. Therefore, users are advised to work with Git from the very beginning to make it easy to manage the profiles and ensure that a reliable "single source of truth" exists for all profiles in an environment. In this way, errors are easier to identify, roll back, and fix.
The directory structure for an InSpec profile is very simple. In the profiles
repository you create the example
subdirectory to create a sample profile. In this directory you need at least one file named inspec.yml
, which defines the profile. You also need a folder named controls
in which all checks performed by the InSpec profile are stored. If desired, a folder named libraries
can be added where you establish your own resources. If the profile requires additional files, they end up in a different folder named files
.
A file named README.md
should explain the functionality of the profile you create. It is especially useful if you want to share it on GitHub. The format should be in the GitHub flavor of markdown. However, if you can do without special formatting, simply add plain text to this file.
A Simple Example
The structure of an InSpec profile can be better understood by looking at a simple example. If you need to display a notice with the General Data Protection Regulation (GDPR) to every user on the desktop for compliance reasons, the best way to do this is to use the /etc/motd
file. This file is automatically displayed by the system when each user logs in. The file
function is suitable, because it can search for specific content in text files with the keyword content
. To ensure that the GDPR string occurs in /etc/motd
, you have to combine the contains
keyword with a regular expression:
describe file('/etc/postgresql/9.1/main/pg_hba.conf') do its('content') { should match /Please observe the GDPR regulations/ }
This control checks the entire content of the /etc/motd
file for the described string. If InSpec finds the entry, the system is considered "compliant" for this control. The statement described does not yet constitute a complete control in itself because, in addition to the tests, a control also contains metadata. At the beginning, you have to specify at least a name with the syntax
control <Name> do
and add the end
entry at the end. If you leave out the metadata, InSpec complains about the missing entry in /etc/motd
. However, because the impact
keyword is not set, this does not set off the alarm bells. You can change this behavior by inserting a block with the following syntax immediately after the control
line and before describe
:
impact 'critical' title 'Verify GDPR hint exists in /etc/motd' desc 'Control tests MOTD for GDPR hint and sends out alarm if missing' tag 'gdpr'
The first InSpec test is now defined. You can save it (e.g., as dsgvo.rb
) in the controls
folder of the profile currently in use. By the same principle, you can create any number of additional files with checks in the same folder. Once the controls for a profile are ready, the next step is to create the inspec.yml
file, which turns the controls into a standards-compatible profile (Listing 1).
Listing 1: inspec.yml Sample
name: profile name: profile title: InSpec profile to check /etc/motd maintainer: Martin Gerhard Loschwitz copyright: Hutchison Drei Austria GmbH copyright_email: martin.loschwitz@drei.com license: Apache-2.0 summary: Tests whether the string "DSGVO" appears in MOTD version: 1.0.0
Applying the Profile
The final step in creating the profile is to apply it to a system. To begin, copy the entire profile to a target system and run
inspec exec <profile folder>
or use InSpec's SSH capabilities, which may be the better approach,
inspec exec Example --key-files $HOME/.ssh/id_rsa --target ssh://root@10.42.0.1
especially for large environments.
Running InSpec Centrally
A central InSpec instance that can access target systems over SSH is useful. Unfortunately, the framework does not offer an inventory function for batch mode across multiple hosts. By running InSpec from a central location, you can easily automate and monitor it: If a check on a particular system outputs a compliance warning, it can be detected automatically by a check for the respective monitoring system. If someone tampers with systems and leaves them in a state that no longer meets compliance requirements, you'll quickly notice, and you can respond quickly.
Creating Resources
The list of compliance resources provided by InSpec is long. You should find the right template for most applications. One exception could be a program developed in-house that does not exist outside of your company. In such cases, you can add your own resources to InSpec. An example, such as an application that stores its metadata in a MySQL database in an unknown, proprietary table structure, clearly illustrates this option. You can rule out a resource being provided by InSpec for the application to check the configuration for certain parameters. If you still want to use checks, your only way out is the laborious process of creating your own.
Because the framework is based on the Ruby programming language, resources in InSpec are also standard classes in Ruby. Therefore, you need to be well versed in the programming language before you start to extend InSpec. The MySQL2 library [2] by Brian Lopez is included in the Ruby repository and makes it possible to establish MySQL connections and then read from MySQL databases. With this module and the usual functions in Ruby for reading and comparing strings, a check_database
resource can be written for InSpec. Depending on the desired complexity, this resource can check whether certain keywords are present and what their values are. The template you write must use Inspec.resource(1)
as its type.
For the sake of completeness, I should mentioned that InSpec comes with its own mysql_connection
resource, with which it can establish a MySQL connection and which was designed for applications like this. The possibilities for building your own resource (Figure 2) or using existing ones (Figure 3) are manifold. As soon as the resource is ready, it needs to be stored in the libraries
folder in the respective profile; then, it can be used in profiles in the usual way.


Linking Profiles
In everyday life you might work with different classes of servers within a large environment – for example, a cloud based on OpenStack, which usually has at least controller nodes, compute nodes, and servers for distributed object storage with Ceph. These devices each have their own compliance requirements and require individual testing. At the same time, you need a number of basic tests that you have to run on all systems. One option would be to include the respective resource definitions of the profiles in each role individually. However, this would have the distinct disadvantage that code for the same task would be out there several times, and you would have to maintain it in several places.
To put a stop to this mess, InSpec allows you to connect profiles in series and make them dependent on each other to ensure a workflow with one profile per class, which loads a certain number of other common profiles but also uses profiles specific to itself. The keyword depends
used for this purpose supports a multitude of possible sources of profiles to be included. The easiest example is probably path
, which references a local directory:
depends: - name: basics-profile path: /home/inspec/profiles/basics
Alternatively, depends
can load profiles directly from Git, retrieve them as tarballs from the Internet, or fetch them from a connected Chef Compliance Server. However, the depends
directive is not sufficient to ensure that the controls are executed. The control directive in profile 1 has to have an include_controls
statement for the control directives from role 2 that are to be called there. If a remote role comprises several control directives, these must be added individually to the include role.
Discover Possibilities
The examples referenced thus far have deliberately been kept as simple as possible so as not to unnecessarily stress InSpec newcomers. The feature scope of the software is fairly large, as you can see by looking at the list of resources [3] already included with InSpec. These resources include line-by-line interpretation of most common configuration file formats, as well as sample code for classical Linux services, along with ready-made modules for a variety of services from the systemd universe (e.g., for firewalld). The health state of the packaging system can be checked on RPM- and DEB-based distributions with the yum
and apt
directives. Many resources for legacy security topics like SELinux are also included. With on-board tools, InSpec can test automatically whether an administrator has switched SELinux to permissive
mode on a target system (i.e., whether it has effectively been disabled).
The newer InSpec versions, in particular, offer many features for public cloud environments. Compliance extends over several levels. Both the account in the cloud environment and the workload running under the account need to be compliant. For AWS, Google Cloud, and Microsoft Azure, various factors of the cloud environment can be checked automatically for compliance.
Don't Reinvent the Wheel
Up to this point I have described how InSpec works and how to create profiles for your environment. However, before you start from scratch and build a complete environment, you might first want to step back. New code is rarely more stable than its predecessors, and InSpec has many prebuilt profiles online that offer a basic set of features, thanks mainly to the DevSec project, a group of admins who offer basic compliance checks in the form of their baseline
directories for both Windows and Linux. For some additional services such as PostgreSQL, the project's GitHub contains additional baseline
modules that also check basic facts. Even better, if you discover that your systems do not or do not fully meet the current compliance standards in Linux, you will also find Cookbooks for Chef or Playbooks for Ansible that help you resolve the worst problems.
InSpec can't do everything (e.g., define compliance rules that the software needs to monitor). In larger companies, the majority of the specifications will come from central policies, and some places even have InSpec profiles for internal rules. Where this is not the case, the admin needs to put some thought into creating profiles. However, you do not have to reinvent the wheel. The Linux Foundation offers a free manual [4] for compliance on Linux systems, which contains many important basic rules, along with many other instructions and tips for compliance under Linux on the Internet, especially in the context of certifications such as government-mandated auditing procedures, IT security standards for cloud computing, or the Payment Card Industry Data Security Standard (PCI DSS), which has a detailed manual [5] from Chef (Figure 4).

Conclusions
InSpec proves to be a practical tool for automated monitoring of compliance on systems. The tool makes compliance easy for the admin. Chef delivers InSpec with ready-to-use parsers for the configuration files of common services, and the framework's declarative script language is quickly learned because it is very intuitive. The major part of the admin work consists of mapping your own compliance requirements. And even here, the baseline repositories with basic compliance tests do part of this work. If you are gearing your compliance for specific certifications, local compliance institutions or Chef can help you set up additional protections.