Skip to main content

InSpec Profile Dependencies

A Chef InSpec profile can bring in the controls and custom resources from another Chef InSpec profile. Additionally, when inheriting the controls of another profile, a profile can skip or even modify those included controls.

For hands-on examples, check out Extending InSpec: InSpec Wrappers and Custom Resources on Learn Chef.

Define dependencies

Before a profile can use controls from another profile, the to-be-included profile needs to be specified in the including profile’s inspec.yml file in the depends section. For each profile to be included, a location for the profile from where to be fetched and a name for the profile should be included. For example:

depends:
- name: linux-baseline
  url: https://github.com/dev-sec/linux-baseline/archive/master.tar.gz
- name: ssh-baseline
  url: https://github.com/dev-sec/ssh-baseline/archive/master.tar.gz

Chef InSpec supports a number of dependency sources.

path

The path setting defines a profile that is located on disk. This setting is typically used during development of profiles and when debugging profiles.

depends:
- name: my-profile
  path: /absolute/path
- name: another
  path: ../relative/path

url

The url setting specifies a profile that is located at an HTTP- or HTTPS-based URL. The profile must be accessible via a HTTP GET operation and must be a valid profile archive (zip, tar, or tar.gz format).

depends:
- name: my-profile
  url: https://example.com/path/to/profile.tgz
- name: profile-via-git
  url: https://github.com/username/myprofile-repo/archive/master.tar.gz

url also supports basic authentication.

depends:
- name: my-profile
  url: https://example.com/path/to/profile.tgz
  username: user
  password: password

git

A git setting specifies a profile that is located in a Git repository, with optional settings for branch, tag, commit, version, and relative_path. The source location is translated into a URL upon resolution. This type of dependency supports version constraints via semantic versioning as Git tags.

depends:
- name: git-profile
  git: http://example.com/path/to/repo
  branch:  desired_branch
  tag:     desired_version
  commit:  pinned_commit
  version: semver_via_tags
  relative_path: relative/optional/path/to/profile

supermarket

A supermarket setting specifies a profile that is located in a cookbook hosted on Chef Supermarket. The source location is translated into a URL upon resolution.

For example:

depends:
- name: supermarket-profile
  supermarket: supermarket-username/supermarket-profile

Available Supermarket profiles can be listed with inspec supermarket profiles.

compliance

A compliance setting specifies a profile that is located on the Chef Automate or Chef Compliance server.

For example:

depends:
- name: linux
  compliance: base/linux

Gem dependencies

Any profile with Ruby gem dependencies that need to be installed can be specified using the gem_dependencies settings in the inspec.yml metadata file.

For example, if you required any Ruby library in a custom resource that needs a specific gem to be installed, then you can specify those gems in the metadata file. Chef InSpec will prompt to install the gems to ~/.inspec/gems when you run your profile the first time. To skip the prompt and automatically install, pass the --auto-install-gems option to inspec exec.

gem_dependencies:
  - name: "mongo"
    version: ">= 2.3.12"

Alternate resource names

By default, all custom resources from a listed dependency are available for use in a profile. If two of your dependencies provide a resource with the same name, you can use the require_resource InSpec DSL function to disambiguate the two:

require_resource(
  profile: '<DEPENDENCY_NAME>',
  resource: '<RESOURCE_NAME>',
  as: '<ALTERNATE_RESOURCE_NAME>'
)

where:

  • <DEPENDENCY_NAME> is the dependent profile
  • <RESOURCE_NAME> is the resource name in the dependent profile
  • <ALTERNATE_RESOURCE_NAME> is an alternate name for that resource

Use controls from a dependent profile

After you define a dependent profile in the inspec.yml file, you can use controls from those profiles.

See the inspec repository for an example profile that inherits controls from another profile.

The following examples show you how to include controls from a dependent profile.

Include all controls

With the include_controls command in a profile, all controls from the named profile will be executed every time the including profile is executed.

For example, if you have a profile called baseline-profile with the following controls:

  • baseline-1
  • baseline-2

And app-profile with the following controls:

  • app-1
  • app-2
  • app-3

Add baseline-profile as dependency of app-profile, then include the baseline-profile controls using include_controls in the control code of app-profile:

include_controls 'baseline-profile'

Every time you execute app-profile, InSpec also executes all the controls from baseline-profile:

  • app-1
  • app-2
  • app-3
  • baseline-1
  • baseline-2

This is a great reminder that having a good naming convention for your controls is helpful to avoid confusion when including controls from other profiles!

Skip a control

What if one of the controls from the included profile does not apply to your environment? Luckily, it is not necessary to maintain a slightly-modified copy of the included profile just to delete a control. The skip_control command tells Chef InSpec to not run a particular control.

For example, if you have a profile called baseline-profile with the following controls:

  • baseline-1
  • baseline-2

And app-profile with the following controls:

  • app-1
  • app-2
  • app-3

Add baseline-profile as dependency of app-profile, then include the baseline-profile controls using include_controls and skip_control to exclude the profile you don’t want execute:

include_controls 'baseline-profile' do
  skip_control 'baseline-2'
end

Every time you execute app-profile, InSpec also executes all the controls from baseline-profile except baseline-2:

  • app-1
  • app-2
  • app-3
  • baseline-1

Modify a control

Let’s say a particular control from an included profile should still be run, but the impact isn’t appropriate? Perhaps the test should still run, but if it fails, it should be treated as low severity instead of high severity?

When a control is included, it can also be modified!

For example, if you have a profile called baseline-profile with the following controls:

  • baseline-1
  • baseline-2

And baseline-1 has an impact of 1.0 defined in baseline-profile:

control 'baseline-1' do
  impact 1.0
  ...
end

Add baseline-profile as dependency of app-profile, then include the baseline-profile controls to app-profile using include_controls and redefine the impact of baseline-1:

include_controls 'baseline-profile' do
  control 'baseline-1' do
    impact 0.5
  end
end

In the above example, all controls from baseline-profile are executed along with all the controls from the including profile, app-profile. However, should control baseline-1 fail, it will be raised with an impact of 0.5 instead of the originally intended impact of 1.0.

Selectively include controls

Use the require_controls command selectively include certain controls from an included profile. You don’t have to skip all the unneeded controls, or worse, copy/paste those controls bit-for-bit into your profile.

For example, if you have a profile called baseline-profile with the following controls:

  • baseline-1
  • baseline-2
  • baseline-3
  • baseline-4
  • baseline-5

And app-profile with the following controls:

  • app-1
  • app-2
  • app-3

Add baseline-profile as dependency of app-profile, then include specific baseline-profile controls using require_controls in the control code of app-profile:

require_controls 'baseline-profile' do
  control 'baseline-2'
  control 'baseline-4'
end

Every time you execute app-profile, InSpec executes the controls app-profile and the controls specified in the require_controls block:

  • app-1
  • app-2
  • app-3
  • baseline-2
  • baseline-4

Controls baseline-1, baseline-3, and baseline-5 are not run, just as if they were manually skipped. This method of including specific controls ensures only the controls specified are executed; if new controls are added to a later version of baseline-profile, they would not be run.

And, just the way its possible to modify controls when using include_controls, controls can be modified with require_controls as well.

require_controls 'baseline-profile' do
  control 'baseline-2' do
    impact 0.5
  end
  control 'baseline-4'
end

As with the prior example, only baseline-2 and baseline-4 are executed, but if baseline-2 fails, it will report with an impact of 0.5 instead of the originally-intended 1.0 impact.

Include controls from different profile versions

When a Chef InSpec profile has dependency on another profile to its specific version, then the controls can be included or selected by using the profile name and version separated by -.

Here, profile-a has following dependency:

name: profile-a
depends:
  - name: ssh
    git: https://github.com/dev-sec/ssh-baseline.git
    tag: 2.6.0

And profile-b has following dependency:

name: profile-b
depends:
  - name: ssh
    git: https://github.com/dev-sec/ssh-baseline.git
    tag: 2.7.0

You can include or require controls of these profiles in a following manner:

include_controls "ssh-2.6.0"
include_controls "ssh-2.7.0"

OR

require_controls "ssh-2.6.0"
require_controls "ssh-2.7.0"

Vendor dependencies

When you execute a local profile, Inspec reads the inspec.yml file in order to source any profile dependencies. It then caches the dependencies locally and generates an inspec.lock file.

If you add or update dependencies in inspec.yml, dependencies may be re-vendored and the lockfile updated with inspec vendor --overwrite

Edit this page on GitHub

Thank you for your feedback!

×