Auditing OS level resources with Chef InSpec

Many of Qxf2‘s clients store their Infrastructure as Code. This means that new infrastructure is spun using code and then the application is deployed. So, as testers, we now have to verify that the right infrastructure was spun up and configured correctly. In this post, I will show you how to use Chef InSpec – a tool to write tests for your infrastructure. It will help you catch annoying errors like misconfigurations, dead services, etc.

1.Introduction

Chef InSpec is an open source framework tool used for testing and auditing applications and infrastructure. The tool:

a) compares the actual state of the system with desired state
b) validates configurations and behaviour of your systems
c) identifies compliance and security violations
d) generates a detailed report for further analysis and action

The good news is that Chef InSpec is easy to pick up. It offers a rich collection of ready-to-use resources, and also you can write custom code to extend it.

2.Purpose of this post

The decision to write this post on the Chef InSpec tool, is to cater to testers who are eager to learn how to test infrastructure, especially when it is stored as code. In a previous client project, I utilized Chef InSpec to test deployments by the TestOps team. However, my ability to delve deeply into test creation was limited at that time, due to limited access to resources. This limitation has motivated me to explore this tool further and to share my acquired knowledge.

I will cover testing a server that has been setup with an application in this post. We do this with something called OS resources. In a following post, I will delve into testing the configuration of AWS resources. These sequential discussions are primarily intended for beginners who possess an interest in familiarizing themselves with the Chef InSpec tool.


3.Setup

Users can download Chef InSpec from the official website and choose between Operating Systems of MacOS, Windows, and Linux.

3.1 MacOS:

It is available as a standalone Homebrew package. Run the following command.

brew install chef/chef/inspec
3.2 CLI:

You can download using curl script. Run the following command.

curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec
3.3 Windows:

Download the latest package and click the .msi file to launch the installer and follow the prompts.

3.4 Linux:

The following command used to install it on Ubuntu and Red Hat Enterprise Linux.

curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec

4.Keywords

In the next sections, you will encounter the following technical words: controls, resource and profiles. Here is an inaccurate but useful mental-model for these words:

a) resource: “infrastructure” we want our tests to interact with. Example: OS, AWS, GCP, Azure, etc.
b) controls: a directory where our tests go
c) profile: helps you organize and partition your tests at a higher level (example: one profile per app, or profile per service and so on)

Additionally, each profile will be associated with a inspec.yml file that stores the meta-information about the profile.

5.Profiles

Profiles play an important role in Chef InSpec as it encompasses a collection of controls, with each control representing individual tests targeting specific system aspects. The Chef InSpec profile maintains a standalone structure that necessitates the inclusion of both the inspec.yml a metadata file and the controls folder. Both are mandatory.
-The inspec.yml metadata file gives information about the profile. While only the Name field is mandatory, all other profile settings are optional. It is possible to specify the targeted platform (example: Ubuntu) for running tests within this file. Additionally, one can list all the dependencies required for the tests. The path from which the profile is accessible can also be defined; this could be a local path, a URL (HTTP/HTTPS), or a Git repository.
-The Controls folder is where you store all your tests. By default, it contains a sample test file created during the profile creation. To initiate the creation of a new profile, execute the command below.

Command to create standard profile:
inspec init profile test_profile

This command will create a new profile named test_profile with default structure.

Command to verify the profile creation:
inspec check [profile_name]

When run against profile, it will pop up errors, warnings if any


6.Test to verify OS resources

The following section describes the syntax and shows some simple examples of using Chef InSpec’s OS resources. It would be nice if you could follow along and practice against some server that you work with. The Chef InSpec language is Ruby DSL(domain-specific languages) for writing audit controls, which includes audit resources. As testers we need to write tests for Infrastructure as Code.

6.1 File resource:

We sometimes want to make sure that certain files exist (or do not exist) after a deploy. Using File Chef InSpec auditing resource to test system file types including directories, symbolic links.
Example: Test if a configuration file exists and has specific permissions.

describe file('/etc/hosts') do
  it { should exist }
  it { should be_readable.by('owner') }
end

I will try to explain the code using Chef InSpec glossary.
Each line within the resource block begins with “it” and is used to access resource-specific matchers like { should exist } . Matcher { should be_readable } tests if the existing file is readable. The Matchers perform the actual assertion against resource or the properties of the resource.


6.2 Package resource:

Package resource holds significance to confirm the installation of specific packages and validate their corresponding versions. This task can be accomplished through the utilization of the package auditing resource.
Example: Test the package ‘nginx’ is installed and its version using the package resource.

describe apt('nginx') do
  it { should be_installed }
  its('version') { should eq '1.9.5' }
end

6.3 Docker container resource:

Testing of the existence and operational state of a deployed Docker image is vital. docker_container auditing resource can be used to validate this.
Example: Test if a specific docker container is running.

describe docker_container('myapp') do
  it { should exist }
  it { should be_running }
end

6.4 HTTP resource:

http auditing resource can be used to perform a health check before commencing testing of the web application.
Example:Test if specific domain is accessible and returns a specific status code.

describe http('http://example.com') do
  its('status') { should cmp 200 }
end

A universal matcher is a matcher that can be used on the properties of a resource. Universal matchers are always used with the “its” keyword. In this example used against a property of a resource. “cmp” matcher is used to check the value of the properties.


6.5 Nginx resource:

Nginx, an open-source web server software, is commonly utilized for hosting applications. Validating the availability of Nginx is significant. This can be achieved by using nginx auditing resource.
Example: Test Nginx service is running and enabled.

describe service('nginx') do
  it { should be_enabled }
  it { should be_running }
end

6.6 Passwd resource:

Using the passwd auditing resource allows you to test the contents of the ‘/etc/passwd’ file.
Example: test if ‘root’ and ‘www-data’ users exist and count is equal to one.

describe passwd.uids(0) do
    its('users') { should cmp 'root' }
    its('count') { should eq 1 }
end
describe passwd.where { user == 'www-data' } do
    its('uids') { should cmp 33 }
    its('count') { should eq 1 }
end

6.7 Service resource:

When testing Infrastructure, it is essential to assess the status of the services. The service auditing resource serves this purpose by enabling the testing of specific services for installation, running status, and activation. In few cases, to verify specific service manager by using one of the service manager specific resources like “systemd_resource”, “launchd_service”.
Example: test if mysql systemd service and prometheus launchd service are installed, enabled and in running status.

describe systemd_service('MYSQL') do
    it { should_not be_enabled }
    it { should_not be_installed }
    it { should_not be_running }
end
describe launchd_service('prometheus') do
    it { should_not be_enabled }
    it { should_not be_installed }
    it { should_not be_running }
end

Command to execute Chef InSpec test:
inspec exec  [profile_name]
Sample run of service resource test:

Chef InSpec test output


To wrap up this post, Chef InSpec is a good tool to test compliance and security of the infrastructure. I like it’s user-friendly syntax. It not only lets us use predefined resources out of the box. But it also allows us to customize the resources and extend them. My intention is to inspire each one of you to take into the world of testing infrastructure using Chef Inspec. Let’s have more secure, reliable, and compliant infrastructure with Chef InSpec!


Hire technical testers from Qxf2

Hire Qxf2 testers for testing your infrastructure. Our testers possess deep technical expertise and practical experience in testing modern technical stacks. Gain access to skilled testers who can navigate the intricacies of Infrastructure as Code by partnering with Qxf2.


References:

https://docs.chef.io/inspec/

Leave a Reply

Your email address will not be published. Required fields are marked *