3. Study an InSpec Profile - NGINX Example
Studying an InSpec profile
Let's start by creating a profile that will contain NGINX tests.
At your terminal, type:
inspec init profile my_nginx
βββββββββββββββββββββββββββ InSpec Code Generator βββββββββββββββββββββββββββ
Creating new profile at /workspaces/saf-training-lab-environment/my_nginx
β’ Creating file inspec.yml
β’ Creating directory /workspaces/saf-training-lab-environment/my_nginx/controls
β’ Creating file controls/example.rb
β’ Creating file README.md
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 my_nginx
my_nginx
βββ README.md
βββ controls
β βββ example.rb
βββ inspec.yml
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. Thelibraries
directory contains resource extensions. A resource extension enables you to define your own resource types. 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
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
file is an InSpec resource. 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 matcher. 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!
folder_A
βββ README.md
βββ controls
β βββ example-control-1.rb
β βββ example-control-2.rb
β βββ example-control-3.rb
βββ inspec.yml
2 directories, 5 files
folder_B
βββ README.md
βββ controls
βββ example-control-1.rb
βββ example-control-2.rb
βββ example-control-3.rb
2 directories, 4 files
folder_C
βββ README.md
βββ example-control-1.rb
βββ example-control-2.rb
βββ example-control-3.rb
βββ inspec.yml
1 directories, 5 files
folder_D
βββ Gemfile
βββ README.md
βββ controls
β βββ example-control-1.rb
β βββ example-control-2.rb
β βββ example-control-3.rb
βββ inspec.yml
βββ libraries
βββ my_resource.rb
3 directories, 7 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>