Skip to main content

About the Compliance Phase

Chef Infra Client’s Compliance Phase lets you automatically execute compliance audits and view the results as part of any Chef Infra Client run. The Compliance Phase of the Chef Infra Client run replaces the legacy audit cookbook and works with your existing audit cookbook attributes, and you can also set it up for new cookbooks. This additional phase gives you the latest compliance capabilities without having to manage cookbook dependencies or juggle versions during Chef Infra Client updates.

Existing audit cookbook users can migrate to the new Compliance Phase by removing the audit cookbook from their run_list and setting the node['audit']['compliance_phase'] attribute to true.

The Compliance Phase replaces the audit cookbook by integrating Chef InSpec compliance checks into the Chef Infra Client run The Compliance Phase is designed to run on any node in your system that’s set up–or bootstrapped–for a chef-client run.

New in Chef Infra Client 17.8

Once turned on, the Compliance Phase always outputs its results in the CLI on manual runs. The output for automated runs is handled by reporters.

Upgrade to Compliance Phase from Audit Cookbook

The Compliance Phase requires Chef Infra Client 17 or higher.

If your system is configured to use the audit cookbook, make these changes to switch to the Compliance Phase:

  1. Set the node['audit']['compliance_phase'] attribute to true through a Policyfile or cookbook attributes file.

  2. Remove the audit cookbook from your run-list.

  3. On your next Chef Infra Client run, you should see the Compliance Phase results.

Set up the Compliance Phase in new Cookbooks

Turn on the Compliance Phase

Turn on the Compliance Phase by setting the node['audit']['compliance_phase'] attribute to true through cookbook attributes or Policyfiles. To turn on Compliance Phase using cookbook attributes add the following line to the attributes/default.rb file in your cookbook.

default['audit']['compliance_phase'] = true

Set Chef InSpec Profiles

Setting one or more Chef InSpec profiles turns on the Compliance Phase in a Chef Infra Client run. The presence of this configuration in your attributes file instructs Chef Infra Client to fetch and execute the specific Chef InSpec profiles and write the results to disk using the default cli and json-file reporters.

Retrieve Chef InSpec profiles from Chef Automate, Supermarket, a local file, GitHub, or over HTTP with the node['audit']['profiles'] attribute.

The following examples:

  • Retrieve profiles from Chef Automate, Supermarket, a local file, GitHub, or over HTTP.
  • Display the results on the command line using the default cli reporter.
  • Write the results to disk using the default json-file reporter to <chef_cache_path>/compliance_reports/compliance-<timestamp>.json.

# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile locations
default['audit']['profiles']['linux-baseline'] = {
  'compliance': 'user/linux-baseline',
  'version': '2.1.0'
}

Warning

Fetching profiles from Chef Automate requires setting data_collector.server_url and data_collector.token in your client.rb to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate data collector documentation.
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile locations
default['audit']['profiles']['ssh'] = {
  'supermarket': 'hardening/ssh-hardening'
}
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile locations
default['audit']['profiles']['4thcafe/win2012_audit'] = {
  'path': 'E:/profiles/win2012_audit'
}
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile locations
default['audit']['profiles']['ssl'] = {
  'git': 'https://github.com/dev-sec/ssl-benchmark.git'
}
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile locations
default['audit']['profiles']['ssh2'] = {
  'url': 'https://github.com/dev-sec/tests-ssh-hardening/archive/master.zip'
}

Fetch Profiles

Set the fetcher attribute with default['audit']['fetcher'] to retrieve Chef InSpec compliance profiles from either Chef Automate or Chef Infra Server in addition to the location defined by default ['audit']['profile']. Left unset, the Compliance Phase defaults to the fetchers included in Chef InSpec. Chef Infra and Chef InSpec fetchers are mutually exclusive so, you can only use one of these configurations.

The following examples:

  • Retrieve the ‘ssh’ profile from Chef Supermarket.
  • Fetch additional profiles from Chef Automate or Chef Infra Server.
  • Display the results on the command line using the default cli reporter.
  • Write the results to disk using the default json-file reporter to <chef_cache_path>/compliance_reports/compliance-<timestamp>.json.

# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile location
default['audit']['profiles']['ssh'] = {
'supermarket': 'hardening/ssh-hardening'
}
# Fetch additional profiles
default['audit']['fetcher'] = 'chef-automate'

Warning

Fetching profiles from Chef Automate requires setting data_collector.server_url and data_collector.token in your client.rb to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate data collector documentation.
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile location
default['audit']['profiles']['ssh'] = {
'supermarket': 'hardening/ssh-hardening'
}
# Fetch additional profiles
default['audit']['fetcher'] = 'chef-server'

Reporters

Reporters control what’s done with the resulting report after the Chef InSpec run. Either a single value or a list of multiple values is supported. The default is the cli and json-file reporters.

Reporters can send Compliance Phase results to:

  • Chef Automate proxied by Chef Infra Server.
  • Directly to Chef Automate (requires additional authentication).
  • The terminal if Chef Infra Client is run interactively by a user.
  • A file on disk.

The following examples:

  • Retrieve the ‘ssh’ profile from Chef Supermarket
  • Fetch additional profiles from Chef Automate
  • Send the results to Chef Automate, Chef Automate proxied by Chef Infra Server, or to a file on disk.

# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile location
default['audit']['profiles']['ssh'] = {
'supermarket': 'hardening/ssh-hardening'
}
# Fetch additional profiles
default['audit']['fetcher'] = 'chef-automate'
# Set reporter
default['audit']['reporter'] = 'chef-automate'

Warning

Reporting Compliance Phase results directly to Chef Automate requires setting data_collector.server_url and data_collector.token in your client.rb to fetch profiles from Chef Automate. This configuration is described in more detail in the Chef Automate data collector documentation.
# Invoke the Compliance Phase
default['audit']['compliance_phase'] = true
# Set profile location
default['audit']['profiles']['ssh'] = {
'supermarket': 'hardening/ssh-hardening'
}
# Fetch additional profiles
default['audit']['fetcher'] = 'chef-server'
# Set reporter
default['audit']['reporter'] = 'chef-server-automate'
<div class="tabs-panel " id="local-reporter"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># Invoke the Compliance Phase</span>

default['audit']['compliance_phase'] = true # Set profile location default['audit']['profiles']['ssh'] = { 'supermarket': 'hardening/ssh-hardening' } # Fetch additional profiles default['audit']['fetcher'] = 'chef-automate' # Set two reporters default['audit']['reporter'] = 'json-file', 'cli' # Set the location of the json-file output # Note that the location attribute uses json_file default['audit']['json_file']['location'] = '/file/path/report.json'

The default json-file path is: <chef_cache_path>/compliance_reports/compliance-<timestamp>.json.

The path will also be output to the Chef Infra Client log:

['2017-08-29T00:22:10+00:00'] INFO: Reporting to json-file
['2017-08-29T00:22:10+00:00'] INFO: Writing report to /opt/kitchen/cache/compliance-reports/compliance-20170829002210.json
['2017-08-29T00:22:10+00:00'] INFO: Report handlers complete

Customize Profiles

You can upload profiles to Chef Automate using the Chef Automate API or the inspec compliance command.

Waivers

Use waivers to mark individual failing controls as administratively accepted, either on a temporary or permanent basis.

To use waivers:

  1. Prepare a YAML waiver file.
  2. Deliver the waiver file to the node in a cookbook_file or remote_file.
  3. Set the waiver_file attribute for the Compliance Phase to that location. For example:
default['audit']['waiver_file'] = "waivers.yaml"

External Data

Chef InSpec profiles should be self-contained and independent from external data. Sometimes, a profile’s test may exhibit different behavior depending on aspects of the node being tested and in these cases, you may want to use external data. Chef InSpec profiles accept inputs that let you customize the test.

Chef InSpec Input

You can pass Chef InSpec inputs to the Chef InSpec runner. Chef InSpec inputs were previously called attributes and you will set them in an ['audit']['attributes'] hash in your attributes file. Any data added to ['audit']['attributes'] as a hash is passed to Chef InSpec as individual attributes.

default['audit']['attributes'] = {
  first_input: 'some value',
  second_input: 'another value',
}

Chef Node Data

There are two primary ways to pass Chef Infra node data to Chef InSpec run during the Compliance Phase.

Any data added to the node['audit']['attributes'] hash will be passed as individual Chef InSpec attributes. This provides a clean interface between the Chef Infra client run and Chef InSpec profile, allowing for easy assignment of default values in the Chef InSpec profile. This method is especially recommended if the Chef InSpec profile is expected to be used outside of the context of Compliance Phase so it’s made explicit to profile consumers what attributes are necessary. Set the attributes in your cookbook attributes file and then use them in your Chef InSpec profile.

Set the attributes in a cookbook attributes file:

node['audit']['attributes']{
  'key1' = 'value1',
  'debug_enabled' = node['my_cookbook']['debug_enabled'],
  'environment' = node.chef_environment
}

Use the attributes in a Chef InSpec profile:

environment = attribute('environment', description: 'The Chef Infra environment for the node', default: 'dev')

control 'debug-disabled-in-production' do
  title 'Debug logs disabled in production'
  desc 'Debug logs contain potentially sensitive information and shouldn't be on in production.'
  impact 1.0

  describe file('/path/to/my/app/config') do
    its('content') { should_not include "debug=true" }
  end

  only_if { environment == 'production' }
end

Use the Chef Infra Node Object

Compliance Phase can be configured to pass the Chef Infra node object as a Chef InSpec attribute named chef_node.

While using the chef_node object provides the ability to write more flexible profiles, it’s difficult to reuse these profiles outside of the Compliance Phase. To reuse these profiles, you will need to understand how to pass in a single attribute containing Chef Infra-like data. Pass external data explicitly whenever possible.

To use this option, first set it in a wrapper cookbook:

node.override['audit']['chef_node_attribute_enabled'] = true

And then use it in your profile:

chef_node = attribute('chef_node', description: 'Chef Node')

control 'no-password-auth-in-prod' do
  title 'No Password Authentication in Production'
  desc 'Password authentication is allowed in all environments except production'
  impact 1.0

  describe sshd_config do
    its('PasswordAuthentication') { should cmp 'No' }
  end

  only_if { chef_node['chef_environment'] == 'production' }
end

Useful Compliance Phase Attributes

audit-enforcer

A special reporter that causes the compliance run to raise an error and immediately terminates the Chef Infra Client run if any control of any Chef InSpec profile fails. If you specify multiple reporters, place the audit-enforcer at the end of the list, allowing the other reporters to generate their output before run termination. Example:

# fail on error
default['audit']['reporter'] = 'audit-enforcer'.

chef_node_attribute_enabled

If set, a hash representation of the Chef Infra node object will be sent to an input named chef_node. Default: false

# send a hash representation of the Chef Infra node object
default['audit']['chef_node_attribute_enabled'] = true

compliance_phase

Turn on the built-in Compliance Phase run. Possible values: true, false, nil

# Turn on Compliance Phase
default['audit']['compliance_phase] = true

control_results_limit

The list of results for each control will be truncated to this amount to reduce the size of reports. A summary of removed results will be sent with each impacted control. Defaults to 50.

# allow 100 results
 default['audit']['control_results_limit'] = 100

fetcher

Controls the location for additional profile locations for Chef InSpec profiles default fetch locations provided through the [audit][profiles] attribute. Accepted values: nil, ‘chef-server’, ‘chef-automate’.

# fetch additional profiles from Chef Server
default[audit][fetcher] = 'chef-server'

insecure

Setting the attribute default['audit']['insecure'] to true will skip SSL certificate verification for the chef-automate and chef-server-automate reporters. This allows connections to HTTPS endpoints with self-signed ssl certificates. Default is false

# allow self-signed certificates
default['audit']['insecure'] = true

interval

New in Chef Infra Client 17.8

You can control the frequency of Compliance Phase scans with the default['audit']['interval'], which means that control the frequency that the Compliance Phase runs with a Chef Infra Client run. This helps you control the impact of compliance scans on system performance in business environments that require compliance scans less frequently than Chef Infra Client Runs.

default['audit']['interval']['enabled']
Set to true to turn on interval runs.
# Set independent Compliance Phase scans
default['audit']['interval']['enabled'] = true
default['audit']['interval']['time']
The time in minutes between Compliance Phase execution. Default: 1440 (once a day).
# Define the timing of independent Compliance Phase scans
# Sets scan to twice daily
default['audit']['interval']['time'] = 1220

json_file

The location on disk that Chef InSpec’s json reports are saved to when using the ‘json-file’ reporter. Defaults to: <chef_cache_path>/compliance_reports/compliance-<timestamp>.json

default['audit']['reporter'] = 'json-file'
default['audit']['json_file']['location'] = '/path/to/file.json'

inspec_backend_cache

Chef InSpec caches the results of commands executed on the node during the Compliance Phase. Caching improves the Compliance Phase performance when slower-running commands are executed multiple times during a Chef Infra Client run. Disable this feature if your Chef InSpec profile runs a command multiple times expecting different output during the run. Default: true. Example:

# Disable caching of commands
default['audit']['inspec_backend_cache'] = false

profiles

Chef InSpec Compliance profiles to be used for scanning nodes.

# use the ssh-hardening profile from Supermarket
default['audit']['profiles']['ssh'] = {
  'supermarket': 'hardening/ssh-hardening'
  }

quiet

Controls verbosity of the Chef InSpec runner. Defaults to true. To turn this off, set the attribute default['audit']['quiet'] to false.

# verbose
default['audit']['quiet'] = false

reporter

Controls what’s done with the resulting report after the Chef InSpec run. Accepts a single string value or an array of multiple values. The ‘cli’ reporter mimics the Chef InSpec command line output in your terminal, which lets you see your system’s compliance status at the end of the Compliance Phase. Accepted values: ‘chef-server-automate’, ‘chef-automate’, ‘json-file’, ‘audit-enforcer’, ‘cli’

# set the reporter to Chef Automate
default['audit']['reporter'] = 'chef-automate', 'cli'

run_time_limit

Control results that have a run_time below this limit will be stripped of the start_time and run_time fields to reduce the size of reports. Defaults to 1.0. Set this attribute with default['audit']['run_time_limit'].

# allow 5 minutes run time
default['audit']['run_time_limit'] = 5.0

result_include_backtrace

When a Chef InSpec resource throws an exception, results contain a short error message and a detailed ruby stacktrace of the error. Default: false (doesn’t send backtrace). Example:

# include backtrace
default['audit']['result_include_backtrace'] = true

result_message_limit

Truncates any control result messages exceeding this character limit. Chef Automate has a 4 MB report size limit and can’t ingest reports exceeding this limitation. Chef InSpec will append this text at the end of any truncated messages: [Truncated to 10000 characters] Default: 10000.

default['audit']['result_message_limit] = 10000

server

When reporting to a Chef Automate instance proxied over Chef Infra Server, the Compliance Phase can be configured to use a different URL than the chef_server_url configured in client.rb. Turn on with the attribute default['audit']['server'].

default['audit']['server'] = 'https://server.4thcafe.com'.

waiver_file

A string path or an array of paths to Chef InSpec waiver files.

default['audit']['waiver_file'] = 'path/to/waiver.yml'.

Errors and Troubleshooting

Cache Results

Chef InSpec caches the results of commands executed on the node during the Compliance Phase. Caching improves the Compliance Phase performance when slower-running commands are executed multiple times during a Chef Infra Client run. Disable this feature if your Chef InSpec profile runs a command multiple times expecting different output during the run. Default: true. Example:

# Disable caching of commands
default['audit']['inspec_backend_cache'] = false

Chef InSpec Report Size Limits

The size of the report being generated from running the Compliance Phase is influenced by a few factors like:

  • number of controls and tests in a profile
  • number of profile failures for the node
  • controls metadata (title, description, tags, etc)
  • number of resources (users, processes, etc) that are being tested

Depending on your setup, there are some limits you need to be aware of. A common one is Chef Infra Server default (1MB) request size. Exceeding this limit will reject the report with ERROR: 413 "Request Entity Too Large". For more details about these limits, please refer to the documentation on troubleshooting 413 errors.

HTTP Errors

401, 403 Unauthorized - bad clock

Occasionally, the system date/time will drift between client and server. If this drift is greater than a couple of minutes, the Chef Infra Server will throw a 401 unauthorized and the request won’t be forwarded to the Chef Automate server.

On the Chef Infra Server you can see this in the following logs:

# chef-server-ctl tail

==> /var/log/opscode/nginx/access.log <==
192.168.200.102 - - ['28/Aug/2016:14:57:36 +0000']  "GET /organizations/4thcafe/nodes/vagrant-c0971990 HTTP/1.1" 401 "0.004" 93 "-" "Chef Infra Client/12.14.38 (ruby-2.3.1-p112; ohai-8.19.2; x86_64-linux; +https://chef.io)" "127.0.0.1:8000" "401" "0.003" "12.14.38" "algorithm=sha1;version=1.1;" "vagrant-c0971990" "2013-09-25T15:00:14Z" "2jmj7l5rSw0yVb/vlWAYkK/YBwk=" 1060

==> /var/log/opscode/opscode-erchef/crash.log <==
2016-08-28 14:57:36 =ERROR REPORT====
{<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}

==> /var/log/opscode/opscode-erchef/erchef.log <==
2016-08-28 14:57:36.521 ['error'] {<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}

==> /var/log/opscode/opscode-erchef/current <==
2016-08-28_14:57:36.52659 ['error'] {<<"method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; ">>,"Unauthorized"}

==> /var/log/opscode/opscode-erchef/requests.log.1 <==
2016-08-28T14:57:36Z erchef@127.0.0.1 method=GET; path=/organizations/4thcafe/nodes/vagrant-c0971990; status=401; req_id=g3IAA2QAEGVyY2hlZkAxMjcuMC4wLjEBAAOFrgAAAAAAAAAA; org_name=4thcafe; msg=bad_clock; couchdb_groups=false; couchdb_organizations=false; couchdb_containers=false; couchdb_acls=false; 503_mode=false; couchdb_associations=false; couchdb_association_requests=false; req_time=1; user=vagrant-c0971990; req_api_version=1;

Additionally, the chef_gate log will contain a similar message:

# /var/log/opscode/chef_gate/current
2016-08-28_15:01:34.88702 ['GIN'] 2016/08/28 - 15:01:34 | 401 |   13.650403ms | 192.168.200.102 |   POST    /compliance/organizations/4thcafe/inspec
2016-08-28_15:01:34.88704 Error #01: Authentication failed. Please check your system's clock.

401 Token and Refresh Token Authentication

In the event of a malformed or unset token, the Chef Automate server will log the token error:

==> /var/log/chef-compliance/core/current <==
2016-08-28_20:41:46.17496 20:41:46.174 ERR => Token authentication: %!(EXTRA *errors.errorString=malformed JWS, only 1 segments)
2016-08-28_20:41:46.17498 ['GIN'] 2016/08/28 - 20:41:46 | 401 |      53.824us | 192.168.200.102 |   GET     /owners/base/compliance/linux/tar

==> /var/log/chef-compliance/nginx/compliance.access.log <==
192.168.200.102 - - ['28/Aug/2016:21:23:46 +0000'] "GET /api/owners/base/compliance/linux/tar HTTP/1.1" 401 0 "-" "Ruby"

413 Request Entity Too Large

This error indicates that you have exceeded limit the erchef request size in Chef Infra Server. The default for versions before 13.0 was 1MB. Starting with version 13.0 the default is 2MB.

To resolve this error, set the opscode_erchef['max_request_size'] in Chef Infra Server’s /etc/opscode/chef-server.rb to a larger amount. This example sets the limit to 3MB:

opscode_erchef['max_request_size'] = 3000000

Then run chef-server-ctl reconfigure to apply this change.

413 Error Logs

The 413 “Request Entity Too Large” error appears in both the stacktrace and the Chef Infra Server Nginx logs.

The stacktrace shows the 413 error:

Running handlers:
['2017-12-21T16:21:15+00:00'] WARN: Compliance report size is 1.71 MB.
['2017-12-21T16:21:15+00:00'] ERROR: 413 "Request Entity Too Large" (Net::HTTPServerException)
/opt/chef/embedded/lib/ruby/2.4.0/net/http/response.rb:122:in `error!'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.6.4/lib/chef/http.rb:152:in `request'
/opt/chef/embedded/lib/ruby/gems/2.4.0/gems/chef-13.6.4/lib/chef/http.rb:131:in `post'
/var/chef/cache/cookbooks/audit/libraries/reporters/cs_automate.rb:37:in `block in send_report'
...

The Chef Infra Server Nginx log confirms the 413 error:

==> /var/log/opscode/nginx/access.log <==
192.168.56.40 - - ['21/Dec/2017:11:35:30 +0000']  "POST /organizations/eu_org/data-collector HTTP/1.1" 413 "0.803" 64 "-" "Chef Infra Client/13.6.4 (ruby-2.4.2-p198; ohai-13.6.0; x86_64-linux; +https://chef.io)" "-" "-" "-" "13.6.4" "algorithm=sha1;version=1.1;" "bootstrapped-node" "2017-12-21T11:35:31Z" "GR6RyPvKkZDaGyQDYCPfoQGS8G4=" 1793064

Troubleshooting

Chef Automate sets the logstash limit to 10% of the system memory automatically as part of the automate-ctl reconfigure command execution. You have reached the java heap size(-Xmx) limit of logstash if a Chef InSpec report doesn’t become available in Chef Automate and this error is in the logstash logs:

/var/log/delivery/logstash/current
2017-12-21_13:59:54.69949 DEBUG: Ruby filter is processing an 'inspec_profile' event
2017-12-21_14:00:16.51553 java.lang.OutOfMemoryError: Java heap space
2017-12-21_14:00:16.51556 Dumping heap to /opt/delivery/embedded/logstash/heapdump.hprof ...
2017-12-21_14:00:16.51556 Unable to create /opt/delivery/embedded/logstash/heapdump.hprof: File exists
2017-12-21_14:00:18.50676 Error: Your application used more memory than the safety cap of 383M.
2017-12-21_14:00:18.50694 Specify -J-Xmx####m to increase it (#### = cap size in MB).
2017-12-21_14:00:18.50703 Specify -w for full OutOfMemoryError stack trace
Edit this page on GitHub

Thank you for your feedback!

×