The audit cookbook is a tool used to run InSpec tests and send the results to chef-compliance (either directly or via chef-server) or to chef-visibility in an automated way.
We recently took on an overhaul of the audit cookbook to rewrite the content using chef handlers.
What changed
- The audit cookbook is now using a chef handler, so you should no longer see that any resources were updated at the end of the run. Idempotency for the win!
- Much of the extra profile aggregation logic has been removed; we are now doing a straight call to the inspec runner, similar to what is done in kitchen-inspec
- The way profiles are specified in the audit attributes has been changed, in an effort to harmonize profile locations across our tools
- There is now an attribute for
fetcher
. This enables the audit cookbook to fetch a profile from chef-compliance via chef-server, while reporting to whatever reporter you’d like (i.e. chef-visibility) - You can now choose to send the json report to a file on disk
- You can now specify multiple reporters
Chef Handler
While the change to using a chef handler doesn’t have any impact on how you set up the audit cookbook, it’s worth mentioning that you should now see the output at the end of the audit cookbook run look something like the following after you have run it once:
InSpec Runner
This is another one that doesn’t have any impact on how you set up to use the audit cookbook, but it’s good information to know. The InSpec runner is the thing that grabs the profile locations and begins the process of executing them. In the audit cookbook, that call is here. Why is that something to know? Because, if you’re trying to use the audit cookbook to run some profiles and something is going wildly wrong, you can easily test if your profile location is incorrect by attempting to run it with inspec exec PROFILE
. This is also the same way kitchen-inspec works.
How to Define Profile Locations
This is a bigger change. In an attempt to harmonize profile locations, we have switched to passing an array of hashes. We support path
, url
, git
, compliance
, and supermarket
. name
can be used in conjunction with any of these. a reference to name
on its own defaults to supermarket. So in your .kitchen.yml
, you will now define your profiles like this:
suites: attributes: audit: profiles: - path: test/recipes/master # local path - name: hardening/ssh-hardening # defaults to supermarket - name: os-hardening # name and url url: https://github.com/dev-sec/tests-os-hardening/archive/master.zip - git: https://github.com/dev-sec/tests-ssh-hardening.git # git location - name: ssh # profile on supermarket, a little more explicitly defined supermarket: hardening/ssh-hardening - name: ssh-hardening # the 'name' part is optional. it can be included in any of these definitions git: https://github.com/dev-sec/tests-ssh-hardening.git - name: linux # profile from chef-compliance compliance: base/linux - name: master-local # local path to profile with a name defined path: test/recipes/master
Why this whole ‘name’ thing, you ask? Good question! The name is what we use to fill in the profile information. If you’re familiar with the InSpec command line, you would recognize it as:
These ‘names’ are also used when using InSpec’s include_controls functionality, as can be seen here.
Defined in your cookbook, Chef runtime attributes for profile locations look like this:
"audit": { "profiles": [ { "path": "test/recipes/master" }, { "name": "hardening/ssh-hardening" }, { "name": "os-hardening", "url": "https://github.com/dev-sec/tests-os-hardening/archive/master.zip" }, { "git": "https://github.com/dev-sec/tests-ssh-hardening.git" }, { "name": "linux", "compliance": "base/linux" } ]
The Fetcher Attribute
A fetcher attribute, but why? Well, sometimes you want to report the results of a profile from chef-compliance in chef-visibility. But, there’s a problem…we don’t have access to those chef-compliance profiles. So how do you do that? You use the fetcher attribute! Setting the fetcher attribute to chef-server allows the audit cookbook to fetch the desired profile so this can happen! Here’s an example for ya:
attributes: audit: fetcher: 'chef-server' collector: 'chef-visibility' inspec_version: 1.2.1 profiles: - name: ssh compliance: base/ssh
The json File Reporter
Ever want to have a record of those profile results on disk? Well now you can! Just set the collector attribute to ‘json-file’, and a file named ‘inspec-{timestamp}.json’ will be placed on the filesystem.
Multiple Reporters
You can now set the audit cookbook up to send results to multiple reporters. Need to have your data report to chef-compliance and chef-visibility? Want to also have those results saved to a json file? We got ya covered!
collector: - 'chef-visibility' - 'json-file' - 'chef-compliance'
Everything Else
default['audit']['interval']['enabled']
attribute to true
, and set your preferred timing using the default['audit']['interval']['time']
attribute. When the interval enabled attribute is true, we create a simple file named report_timing.json and read the create time of that file to calculate whether or not the profile is overdue to run.Upload functionality is still there too. So, if you want to upload a profile to chef-compliance, you can do that. There a great example cookbook here.
Real-Life Examples
chef-visibility
--- driver: name: vagrant provisioner: name: chef_zero platforms: - name: ubuntu-14.04 - name: centos-7.2 suites: - name: default run_list: - recipe[test-profiles::default] attributes: audit: collector: 'chef-visibility' inspec_version: 1.2.1 profiles: - git: https://github.com/dev-sec/tests-ssh-hardening.git - name: ssh supermarket: hardening/ssh-hardening
with your data_collector.server_url
and data_collector.token
defined in your client.rb like this:
data_collector.server_url ENV['DATA_COLLECTOR_ENDPOINT'] data_collector.token "93a49a4f2482c64126f7b6015e6b0f30284287ee4054ff8807fb63d9cbd1c506"
chef-compliance
--- driver: name: vagrant provisioner: name: chef_zero platforms: - name: ubuntu-14.04 - name: centos-7.2 suites: - name: default run_list: - recipe[test-profiles::default] attributes: audit: collector: 'chef-compliance' server: "https://192.168.33.201/api" inspec_version: 1.2.1 insecure: true refresh_token: '2/mEiUPY9xalpq_laGdVKylDy6jxV_yxG8mQJBCITrOuZOrL5DGKKDhRm-PDfk0IMR2p9sKOR2uWEFbPdoq-Bxdg==' owner: admin profiles: - name: ssh compliance: base/ssh
chef-server
--- driver: name: vagrant provisioner: name: chef_zero platforms: - name: ubuntu-14.04 - name: centos-7.2 suites: - name: default run_list: - recipe[test-profiles::default] attributes: audit: collector: 'chef-server' inspec_version: 1.2.1 profiles: - name: ssh compliance: base/ssh
reporting to chef-visibility and saving reports to disk using chef-compliance, external (url), and local profiles
--- driver: name: vagrant provisioner: name: chef_zero platforms: - name: ubuntu-14.04 - name: centos-7.2 suites: - name: default run_list: - recipe[test-profiles::default] attributes: audit: fetcher: 'chef-server' collector: - 'chef-visibility' - 'json-file' inspec_version: 1.2.1 profiles: - name: ssh compliance: base/ssh - name: ssh-hardening git: https://github.com/dev-sec/tests-ssh-hardening.git - name: local-master path: test/master