Skip to main content

3. Study an InSpec Profile - NGINX Example

Aaron LippoldAbout 4 min

Studying an InSpec profile

Let's start by creating a profile that will contain NGINX tests.

At your terminal, type:

InSpec Init Command
inspec init profile my_nginx

Understanding the profile structure

Let's take a look at how the profile is structured. We'll start with how a profile's files are structured and then move to what makes up an InSpec control.

First, run tree to see what's in the my_nginx profile.

Tree Command
tree my_nginx

Here's the role of each component.

  • README.md provides documentation about the profile, including what it covers and how to run it.
  • The controls directory contains files which implement the InSpec tests.
  • inspec.yml provides metadata, or information, about the profile. Metadata includes the profile's description, author, copyright, and version.
  • You may optionally have a libraries directory. The libraries directory contains resource extensions. A resource extension enables you to define your own resource typesopen in new window. The Advanced Security Automation Developer Class teaches about defining your own resources.

Understand a control's structure

Let's take a look at the default control file, controls/example.rb.

title 'sample section'

# you can also use plain tests
describe file('/tmp') do
  it { should be_directory }
end

# you add controls here
control 'tmp-1.0' do                        # A unique ID for this control
  impact 0.7                                # The criticality, if this control fails.
  title 'Create /tmp directory'             # A human-readable title
  desc 'An optional description...'
  describe file('/tmp') do                  # The actual test
    it { should be_directory }
  end
end

Tip for developing profiles

When creating new profiles use the existing example file as a template

This example shows two tests. Both tests check for the existence of the /tmp directory. The second test provides additional information about the test. Let's break down each component.

  • control (line 9) is followed by the control's name. Each control in a profile has a unique name.
  • impact (line 10) measures the relative importance of the test and must be a value between 0.0 and 1.0.
  • title (line 11) defines the control's purpose.
  • desc (line 12) provides a more complete description of what the control checks for.
  • describe (lines 13 β€” 15) defines the test. Here, the test checks for the existence of the /tmp directory.

In Ruby, the do and end keywords define a block. An InSpec control always contains at least one describe block. However, a control can contain many describe blocks.

More information on a block in Ruby

Ruby's block syntaxopen in new window

Understand a describe block's structure

As with many test frameworks, InSpec code resembles natural language. Here's the format of a describe block.

describe <entity> do
  it { <expectation> }
end

An InSpec test has two main components: the subject to examine and the subject's expected state. Here, <entity> is the subject you want to examine, for example, a package name, service, file, or network port. The <expectation> specifies the desired result or expected state, for example, that a port should be open (or perhaps should not be open.)

Let's take a closer look at the describe block in the example.

describe file('/tmp') do
  it { should be_directory }
end

Because InSpec resembles human-readable language, you might read this test as "/tmp should be a directory." Let's break down each component.


file

fileopen in new window is an InSpec resourceopen in new window. Resources are written as Ruby classes to describe a part of the system, providing attributes that are easy to call upon within the InSpec test. For example, the InSpec file resource tests for file attributes, including a file's owner, mode, and permissions. The example examines the /tmp directory.

Note

If you're familiar with Chef, you know that a resource configures one part of the system. InSpec resources are similar.


it

The it statement validates one of your resource's features. A describe block contains one or more it statements. it enables you to test the resource itself. You'll also see its, which describes some feature of the resource, such as its mode or owner. You'll see examples of both it and its shortly.

it vs. its

Important! Just like in English grammar, pay attention to the difference between the thing (it) and the possessive word (its).

it is used to describe an action or the expected behavior of the subject/resource in question.
e.g. it { should be_owned_by 'root' }

its is used to specify the expectation(s) of an attribute of the subject/resource.
e.g. its("signal") { should eq "on" }


should

should describes the expectation. should asserts that the condition that follows should be true. Alternatively, should_not asserts that the condition that follows should not be true. You'll see examples of both shortly.


be_directory

be_directory is an example of a matcheropen in new window. A matcher compares a resource's actual value to its expected value. InSpec provides several predefined matchers. The file resource provides the be_directory matcher.

Comprehension Check!

Look at the 4 file structures below. Determine which are valid InSpec Profiles!

A
folder_A
β”œβ”€β”€ README.md
β”œβ”€β”€ controls
β”‚   β”œβ”€β”€ example-control-1.rb
β”‚   β”œβ”€β”€ example-control-2.rb
β”‚   └── example-control-3.rb
└── inspec.yml

2 directories, 5 files
Which of the folders above (A, B, C, and D) are valid InSpec profiles?

A and D are valid InSpec profiles!

INVALID PROFILES:

  • B is not a profile because it is missing the inspec.yml file!
  • C is not a profile because it does not have a controls directory!

VALID PROFILES:

  • A is a profile!
  • D is a profile! A profile can have extra things like a Gemfile and a libraries folder as long as it has the controls directory and the inspec.yml file!

TIP: inspec check

To see if you have a valid InSpec profile, you can run inspec check <path-to-inspec-profile-folder>