Skip to content
SAF InSpec Profile DeveloperSAF InSpec Profile Developer
MITRE InSpec Profile Developer Course
Course
Resources
Installation
  • Course

    • Course Overview
      • Starting the Journey
        • Studying an InSpec Profile
          • Exploring the InSpec Shell
            • Exploring the InSpec Shell
              • Entering the InSpec shell
                • Exploring the file resource
                  • Explore The nginx Resource
                • Writing InSpec Controls
                  • Generating InSpec Results
                    • Viewing and Analyzing Results
                      • InSpec Examples
                        • Profile Inheritance & Overlays
                          • From STIG to Profile

                          Exploring the InSpec Shell

                          May 22, 2022About 6 min

                          On This Page
                          • Exploring the InSpec Shell
                            • Entering the InSpec shell
                            • Exploring the file resource
                            • Explore The nginx Resource

                          # Exploring the InSpec Shell

                          Before we test our NGINX configuration, let's plan which resources and matchers we'll need.

                          When writing InSpec code, many resources are available to you.

                          • You can explore the InSpec documentationopen in new window to see which resources and matchers are available.
                          • You can examine the source codeopen in new window to see what's available. For example, you can see how file and other InSpec resources are implemented.
                          • You can also use examples, such as profiles provided on Chef Supermarketopen in new window, as a guide.

                          There's also InSpec shellopen in new window, which enables you to explore InSpec interactively. In this part, you'll use the InSpec shell to discover which resources you can use to test your NGINX configuration.

                          You're not required to use InSpec shell to develop your profiles. Some users find the InSpec shell to be a useful way to get immediate feedback and explore what's available. You can also use InSpec shell to debug your profiles.

                          # Entering the InSpec shell

                          Run inspec shell to enter the interactive session.

                          inspec shell
                          

                          Which should drop you into the shell, like this:

                          Welcome to the interactive InSpec Shell
                          To find out how to use it, type: help
                          
                          You are currently running on:
                          
                              Name:      ubuntu
                              Families:  debian, linux, unix
                              Release:   16.04
                              Arch:      x86_64
                          

                          Run help to see what commands are available.

                          help
                          

                          Which should return something like:

                          
                          inspec> help
                              You are currently running on:
                          
                                  Name:      ubuntu
                                  Families:  debian, linux, unix
                                  Release:   16.04
                                  Arch:      x86_64
                          
                              Available commands:
                          
                                  `[resource]` - run resource on target machine
                                  `help resources` - show all available resources that can be used as commands
                                  `help [resource]` - information about a specific resource
                                  `help matchers` - show information about common matchers
                                  `exit` - exit the InSpec shell
                          
                              You can use resources in this environment to test the target machine.
                          

                          Run help resources to see which resources are available.

                          help resources
                          

                          Which will return a list like:

                          inspec> help resources
                          
                                   - aide_conf
                                   - apache
                                   - apache_conf
                                   - apt
                                   - audit_policy
                                   - auditd
                                   - auditd_conf
                                   ...
                                   - file
                                   ...
                                   - xml
                                   - yaml
                                   - yum
                                   - yumrepo
                          

                          You see file and other resources listed.

                          # Exploring the file resource

                          Earlier, we saw this describe block:

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

                          Let's run a few commands from the InSpec shell to see how the file resource functions.

                          What is the difference between InSpec and Ruby?

                          Inspec is a Domain Specific Language (DSL) on top of Ruby. In other words, InSpec is built on the Ruby programming language. For example, InSpec matchers are implemented as Ruby methods.

                          Run this command to list which methods are available to the file resource.

                          file('/tmp').class.superclass.instance_methods(false).sort
                          

                          Which will give you the following output:

                          inspec> file('/tmp').class.superclass.instance_methods(false).sort
                          
                                  => [:allowed?,
                                   :basename,
                                   :block_device?,
                                   :character_device?,
                                   :contain,
                                   :content,
                                   :directory?,
                                   ...
                                   :sticky,
                                   :sticky?,
                                   :suid,
                                   :symlink?,
                                   :to_s,
                                   :type,
                                   :uid,
                                   :version?,
                                   :writable?]
                          

                          You can use the arrow or Page Up and Page Down keys to scroll through the list. When you're done, press Q.

                          What is the InSpec Shell?

                          InSpec shell is based on a tool called pry. pry is an interactive debugging environment for ruby and is one of the ruby developer's weapons against bugs.

                          Let's use the InSpec shell to explore some resources in InSpec. We will start with one of the most common elements on the system: a directory.

                          In the InSpec Shell call the file.directory? method.

                          file('/tmp').directory?
                          

                          This will return true, since /tmp is a directory on the system.

                          inspec> file('/tmp').directory?
                                  => true
                          

                          You can see that the /tmp directory exists on your workstation container.

                          To make the tests easier to read, the InSpec language uses "syntactic sugar" to turn methods into English-like phrases. For example, the Ruby language contains boolean methods ending in ? which evaluate to true or false (nil is a type of false). InSpec changes the syntax of these methods to include be_ before the method rather than ? after the method to make it more readable. For example, to check if a directory exists, Ruby would traditionally use directory? while InSpec uses be_directory.

                          Using Ruby Predicate Methods

                          Given what we have just learned, the best practice in InSpec is to return something that evaluates to true or false. The ? (or be_ in InSpec) makes your method a Ruby Predicate Method. See Ruby predicate methodsopen in new window to learn more.

                          The InSpec shell understands the structure of blocks. This enables you to run mutiline code. As an example, run the entire describe block like this.

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

                          Which will run the entire block of code in the InSpec Shell and return the result.

                          inspec> describe file('/tmp') do
                          inspec>  it { should be_directory }
                          inspec> end
                          
                          Profile: inspec-shell
                          Version: (not specified)
                          
                          File /tmp
                            βœ”  should be directory
                          
                          Test Summary: 1 successful, 0 failures, 0 skipped
                          

                          In practice, you don't typically run controls interactively this way for day to day use, but it is a great way to test out your ideas, find bugs or validate your approach before running a scan in its entirety on a target of evaluation.

                          # Explore The nginx Resource

                          Now's a good time to define the requirements for our NGINX configuration. Let's say that you require:

                          1. NGINX version 1.10.3 or later.
                          2. The following NGINX modules should be installed:
                             * `http_ssl`
                             * `stream_ssl`
                             * `mail_ssl`
                          3. The NGINX configuration file - `/etc/nginx/nginx.conf`- should:
                             * be owned by the `root` user and group.
                             * not be readable, writeable, or executable by others.
                          
                          

                          Let's see what resources are available to help define these requirements as InSpec controls.

                          Run help resources a second time.

                          help resources
                          

                          Notice InSpec provides two built-in resources to support NGINX – nginx and nginx_conf.

                          inspec> help resources
                          
                                   - aide_conf
                                   - apache
                                   - apache_conf
                                   - apt
                                   ...
                                   - nginx
                                   - nginx_conf
                                   ...
                                   - xml
                                   - yaml
                                   - yum
                                   - yumrepo
                                   - zfs_dataset
                                   - zfs_pool
                          

                          Run nginx.methods.

                          nginx.methods
                          

                          You can see the version and modules methods.

                          You will use these methods to define the first two requirements.

                          inspec> nginx.class.superclass.instance_methods(false).sort
                          
                                  => [:bin_dir,
                                   :compiler_info,
                                   :error_log_path,
                                   :http_client_body_temp_path,
                                   :http_fastcgi_temp_path,
                                   :http_log_path,
                                   :http_proxy_temp_path,
                                   :http_scgi_temp_path,
                                   :http_uwsgi_temp_path,
                                   :lock_path,
                                   :modules,
                                   :modules_path,
                                   :openssl_version,
                                   ...
                                   :to_s,
                                   :version]
                          

                          Run nginx.version to see what result you get.

                          nginx.version
                          

                          Expected Error Ahead

                          Recall that you're working on your workstation environment, which does not have NGINX installed.

                          inspec> nginx.version
                          
                                  NoMethodError: undefined method `[]' for nil:NilClass
                                  from /opt/inspec/embedded/lib/ruby/gems/2.4.0/gems/inspec-2.0.17/lib/resources/nginx.rb:39:in `block (2 levels) in <class:Nginx>'
                          

                          We can verify this with Inspec by running the following command:

                          package('nginx').installed?
                          

                          As you can see we get false - since nginx is not installed on your runner.

                          inspec> package('nginx').installed?
                          
                                  => false
                          

                          Now that we have explored and discovered the resource methods we need – version and modules – let's run InSpec shell commands against the target that does have NGINX installed to see what results we find.

                          To do so, first start by exiting your InSpec shell session.

                          inspec> exit
                          

                          Run inspec shell a second time and this time, provide the -t argument to connect the shell session to the target container.

                          First let's find our nginx container id using the docker ps command:

                          docker ps
                          

                          Which will return something like:

                          ➜  course git:(master) βœ— docker ps
                          CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                NAMES
                          d4bcef5bb9e3   nginx:latest   "/docker-entrypoint.…"   23 seconds ago   Up 22 seconds   80/tcp               nifty_shtern
                          4f0ceb9b5974   nginx:latest   "/docker-entrypoint.…"   2 months ago     Up 45 seconds   0.0.0.0:80->80/tcp   nginx
                          

                          We can then use the container id of our nginx container to target the inspec shell at that container.

                          inspec shell -t docker://CONTAINER_ID
                          

                          InSpec will then return at the Shell Prompt as before but this time we see we are on our container.

                          Welcome to the interactive InSpec Shell
                          To find out how to use it, type: help
                          
                          You are currently running on:
                          
                              Name:      debian
                              Families:  debian, linux, unix, os
                              Release:   11.2
                              Arch:      aarch64
                          
                          inspec> 
                          

                          Remember that the target does not have InSpec installed on it. Your shell session exists on the workstation; InSpec routes commands to the target instance over Docker.

                          Run the package resource a second time, this time on the target container.

                          package('nginx').installed?'
                          

                          As you can see, how the InSpec package resources returns true.

                          inspec> package('nginx').installed?
                          
                                  => true
                          

                          Now, let's get the version of NGINX that is installed on the target, run: nginx.version

                          nginx.version
                          

                          You can see that version 1.10.3 was installed on our container.

                          inspec> nginx.version
                          
                                  => "1.10.3"
                          

                          To complete the example, let's see which modules are enabled on the nginx container. Run nginx.modules to list the installed NGINX modules.

                          nginx.modules
                          

                          You see below - and hopefully on the data you got back on your container - that the required modules, http_ssl, stream_ssl, and mail_ssl, are installed.

                          inspec> nginx.modules
                          
                                  => ["http_ssl",
                                   "http_stub_status",
                                   "http_realip",
                                   "http_auth_request",
                                   "http_addition",
                                   "http_dav",
                                   "http_geoip",
                                   "http_gunzip",
                                   "http_gzip_static",
                                   "http_image_filter",
                                   "http_v2",
                                   "http_sub",
                                   "http_xslt",
                                   "stream_ssl",
                                   "mail_ssl"]
                          

                          The nginx_confopen in new window resource examines the contents of the NGINX configuration file, /etc/nginx/nginx.conf.

                          Recall that the third requirement is to check whether the NGINX configuration file is owned by root and is not readable, writeable, or executable by others. Because we want to test attributes of the file itself, and not its contents, you'll use the file resource.

                          You saw earlier how the file resource provides the readable, writeable, and executable methods. You would also see that the file resource provides the owned_by and grouped_into methods.

                          inspec> file('/tmp').class.superclass.instance_methods(false).sort
                          
                                  => [:allowed?,
                                   :directory?,
                                   :executable?,
                                   :exist?,
                                   :file,
                                   :file?,
                                   :file_version,
                                   :gid,
                                   :group,
                                   :grouped_into?,
                                   ...
                                   :owned_by?,
                                   ...
                                   :readable?,
                                   ...
                                   :to_s,
                                   :type,
                                   :uid,
                                   :version?,
                                   :writable?]
                          

                          These 5 file methods – grouped_into, executable, owned_by, readable and writeable – provide everything we need for the third requirement.

                          Exit the InSpec shell session with the exit command.

                          inspec> exit
                          
                          Edit this pageopen in new window
                          Last update: 5/24/2022, 1:31:48 AM
                          Contributors: Aaron Lippold,Emily Rodriguez
                          Prev
                          Studying an InSpec Profile
                          Next
                          Writing InSpec Controls
                          Apache-2.0 | Copyright Β© 2022 - The MITRE Corporation
                          Copyright Β© 2022 Aaron Lippold