Content for blog.jerryaldrichiii.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

164 lines
5.4 KiB

---
layout: post
title: Writing InSpec Wrapper Profiles
category: chef_inspec
tags: [inspec, cis, security]
summary: No one is fully compliant, here's how you write a profile fits your environment
---
## What is a wrapper profile?
Chef InSpec groups controls and tests in a standalone artifact known as a
profile. These profiles can include other profiles and bundle/vendor those
profiles to be executed at runtime.
A wrapper profile is just that, a profile that includes controls/resources from
another profile.
## Why would I use a wrapper profile?
In addition to adding custom resources, wrapping profiles allows you to
customize the exact set of controls that are executed during runtime.
Additionally, it is possible to modify the included controls to reduce the
severity/impact or redefine/modify tests. Most commonly, wrapper profiles are
used to implement a strict compliance posture in a way that allows you to
audit/track only the items you care about.
For example, it is very difficult to comply entirely with DISA/NIST/CIS
standards. By using wrapper profiles you can take advantage of the majority of
the security benefits being offered without cluttering up your reports with
items that are not relevant to you or your organization.
---
## Creating a Wrapper Profile
Creating a wrapper profile is a simple as adding a dependency to your
profile's `inspec.yml` file and using `include_controls` or `require_controls`.
## Defining dependencies
When defining dependencies two things are needed:
1. A name, this is used when referencing a dependent profile in your profile
2. A source to fetch the dependent profile
As of the time of this writing, sources can be any of the following:
- A local path on disk (`path:`)
- A URL to a tar/zip (`url:`)
- A GitHub repository (`github:`)
- A Chef Automate server (`compliance:`)
For more information on how to use each of these see:
[https://www.inspec.io/docs/reference/profiles/#defining-the-dependencies](https://www.inspec.io/docs/reference/profiles/#defining-the-dependencies)
## Including/Requiring controls
Controls are included from dependant profiles by using either
`include_controls` or `require_controls`. The main difference between these two
is that `include_controls` includes all controls from the dependent profile
whereas `require_controls` only includes the controls specified within the
`do`/`end` block.
### `include_controls`
Using `include_controls` will include all controls from the referenced profile.
Certain controls can be excluded from this inclusion by using: `skip_control`.
For example, let's say you wanted to include all controls from `some-profile`
but skip the `some-strict-control` (defined via `control
'some-strict-control`).
Do the following:
```ruby
# `some_profile` corresponds to `name:` in the `inspec.yml` `depends:` section
include_controls 'some-profile' do
skip_control 'some-strict-control'
end
```
### `require_controls`
Using `require_conrols` will only execute the controls you specify from the
dependant profile.
For example, let's say you want to include some specific controls from a
dependent profile, but not include all the controls from that profile.
Do the following:
```ruby
# `some_profile` corresponds to `name:` in the `inspec.yml` `depends:` section
require_controls 'some-profile' do
control 'some-strict-control'
end
```
## Modifying Included Controls
Whether you are using `include_controls` or `require_controls`, the included
controls can be modified.
For example, let's say you want to include all the controls from `some-profile`
but the `telnet` control from the included profile only specifies that the
package `telnetd` is not installed and does not account for the fact that
CentOS's package is called `telnet-server`.
Do the following:
```ruby
# `some_profile` corresponds to `name:` in the `inspec.yml` `depends:` section
include_control 'some-profile' do
control 'telnet' do
telnet_server_packages = %w(telnetd telnet-server)
telnet_server_packages do |telnet_package|
package telnet_package do
it { should_not be_installed }
end
end
end
end
```
This will overwrite the tests in the `some-profile` control named `telnet` but
will not modify things such as `impact`, `title`, or `desc`.
## Example: Wrapping a CIS Profile
Chef Automate includes several built in Chef InSpec profiles for a variety of
platforms.
The example will:
- Include all controls from the `cis-centos7-level2` profile
- Modify the impact of the SSHD control to be informational
- Justification: You would like to have a banner but it needn't be a 'critical' failure
- Modify the HTTP server control to not execute/fail if a web server is running
- Justification: You want to run this profile, but don't want web servers to fail
First, add the following to your profile's `inspec.yml`:
```yaml
depends:
- name: 'cis-centos7-level2'
compliance: 'secteam/cis-centos7-level2'
```
Then add the following to one of your controls:
```ruby
include_controls 'cis-centos7-level2' do
control 'xccdf_org.cisecurity.benchmarks_rule_6.2.14_Set_SSH_Banner' do
impact 0.0
end
control 'xccdf_org.cisecurity.benchmarks_rule_3.11_Remove_HTTP_Server' do
# TODO: Remove me when/if InSpec add support for `not_if`
only_if('This server is a webserver') do
!service('httpd').running? || !service('apache2').running?
end
end
end
```
> NOTE: Message after the `only_if` will only show if the control is skipped