Skip to content

Commit

Permalink
Merge pull request #157 from chef-cookbooks/ap/chef-server-automate
Browse files Browse the repository at this point in the history
Add chef-server-visibility collector
  • Loading branch information
chris-rock authored Nov 16, 2016
2 parents ebbf5b7 + 5fe8336 commit f1b8692
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 15 deletions.
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Please ensure that `chef-cookbooks` is the parent directory of `audit` cookbook.

#### Reporting to Chef Compliance via Chef Server

If you want the audit cookbook to converge and retrieve compliance profiles through the Chef Server, set the `collector` and `profiles` attribute.
If you want the audit cookbook to converge and retrieve compliance profiles through the Chef Server, set the `collector` and `profiles` attributes.

This requires your Chef Server to be integrated with the Chef Compliance server using this [guide](https://docs.chef.io/integrate_compliance_chef_server.html).

Expand Down Expand Up @@ -153,9 +153,9 @@ node.default['audit']['profiles'].push("path": "#{PROFILES_PATH}/mylinux-failure
You can also configure in a policyfile like this:

```ruby
default['audit'] = {
'collector' => 'chef-server',
'profiles' => [
default["audit"] = {
"collector" => "chef-server",
"profiles" => [
{
"name": "linux",
"compliance": "base/linux"
Expand All @@ -168,6 +168,24 @@ default['audit'] = {
}
```

#### Reporting to Chef Visibility via Chef Server

If you want the audit cookbook to retrieve compliance profiles and report to Chef Automate(Visibility) through Chef Server, set the `collector` and `profiles` attributes. For example:


```ruby
"audit": {
"collector": "chef-server-visibility",
"insecure": false,
"profiles": [
{
"name": "windows",
"compliance": "base/windows"
}
]
}
```


#### Direct reporting to Chef Compliance

Expand Down Expand Up @@ -246,7 +264,7 @@ Simply include the `upload` recipe in the run_list, with attribute overrides for

```ruby
audit: {
server: 'https://compliance-server.test/api'
server: 'https://compliance-server.test/api',
collector: 'chef-compliance',
refresh_token: '21/XMEK3...',
profiles: [
Expand Down Expand Up @@ -302,8 +320,8 @@ This will allow the audit cookbook to fetch the profile from chef-compliance. F

```ruby
"audit": {
"fetcher": 'chef-server'
"collector": 'chef-visibility'
"fetcher": "chef-server",
"collector": "chef-visibility",
"profiles": [
{
"name": "ssh",
Expand Down
7 changes: 4 additions & 3 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
# root of location must host the *specs.4.8.gz source index
default['audit']['inspec_gem_source'] = nil

# collector possible values: chef-server, chef-compliance, chef-visibility, json-file
# collector possible values: chef-server, chef-compliance, chef-visibility, chef-server-visibility, json-file
# chef-visibility requires inspec version 0.27.1 or above
default['audit']['collector'] = 'chef-server'

# It will use an InSpec fetcher that fetches compliance profiles via Chef Server
# from Chef Compliance. Will be activated by default if the 'chef-server' collector
# from Chef Compliance or Chef Automate. Will be activated by default if the collectors
# 'chef-server' or 'chef-server-visibility' are used
# is used
# fetcher possible values: chef-server
default['audit']['fetcher'] = nil
Expand All @@ -46,7 +47,7 @@
default['audit']['insecure'] = nil

# Chef Compliance organization to post the report to. Defaults to Chef Server org if not defined
# needed for the 'chef-compliance' collector, optional for 'chef-server' collector
# needed for the 'chef-compliance' collector, optional for 'chef-server' and 'chef-server-visibility' collectors
default['audit']['owner'] = nil

# raise exception if Compliance API endpoint is unreachable
Expand Down
13 changes: 11 additions & 2 deletions files/default/handler/audit_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def report
load_needed_dependencies

# detect if we run in a chef client with chef server
load_chef_fetcher if reporters.include?('chef-server') || node['audit']['fetcher'] == 'chef-server'
load_chef_fetcher if reporters.include?('chef-server') || reporters.include?('chef-server-visibility') || node['audit']['fetcher'] == 'chef-server'

# iterate through reporters
reporters.each do |reporter|
Expand Down Expand Up @@ -74,7 +74,7 @@ def load_chef_fetcher

# sets format to json-min when chef-compliance, json when chef-visibility
def get_opts(reporter, quiet)
format = reporter == 'chef-visibility' ? 'json' : 'json-min'
format = ['chef-visibility', 'chef-server-visibility'].include?(reporter) ? 'json' : 'json-min'
output = quiet ? ::File::NULL : $stdout

Chef::Log.warn "Format is #{format}"
Expand Down Expand Up @@ -152,6 +152,15 @@ def send_report(reporter, server, user, profiles, report)
else
Chef::Log.warn "'server' and 'token' properties required by inspec report collector #{reporter}. Skipping..."
end
elsif reporter == 'chef-server-visibility'
chef_url = server || base_chef_server_url
chef_org = Chef::Config[:chef_server_url].split('/').last
if chef_url
url = construct_url(chef_url, File.join('organizations', chef_org, 'data-collector'))
Collector::ChefServerVisibility.new(entity_uuid, run_id, gather_nodeinfo, insecure, report).send_report(url)
else
Chef::Log.warn "unable to determine chef-server url required by inspec report collector '#{reporter}'. Skipping..."
end
elsif reporter == 'chef-server'
chef_url = server || base_chef_server_url
chef_org = Chef::Config[:chef_server_url].split('/').last
Expand Down
21 changes: 21 additions & 0 deletions libraries/collector_classes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,27 @@ def send_report
end
end

#
# Used to send inspec reports to Chef Visibility server via Chef Server
#
class ChefServerVisibility < ChefVisibility
def send_report(url)
content = @report
json_report = enriched_report(JSON.parse(content))

if @insecure
Chef::Config[:verify_api_cert] = false
Chef::Config[:ssl_verify_mode] = :verify_none
end

Chef::Log.info "Report to Visibility via Chef Server: #{url}"
rest = Chef::ServerAPI.new(url, Chef::Config)
with_http_rescue do
rest.post(url, JSON.parse(json_report))
end
end
end

#
# Used to write report to file on disk
#
Expand Down
2 changes: 1 addition & 1 deletion metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
license 'Apache 2.0'
description 'Allows for fetching and executing compliance profiles, and reporting its results'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '2.1.0'
version '2.2.0'

source_url 'https://github.com/chef-cookbooks/audit'
issues_url 'https://github.com/chef-cookbooks/audit/issues'
Expand Down
25 changes: 23 additions & 2 deletions spec/unit/report/audit_report_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# encoding: utf-8
#
# Cookbook Name:: compliance
# Cookbook Name:: audit
# Spec:: default
#
# Copyright 2016 Chef Software, Inc.
Expand All @@ -18,6 +18,7 @@
# limitations under the License.

require 'spec_helper'
require 'json'
require_relative '../../../files/default/handler/audit_report'
require_relative '../../data/mock.rb'

Expand Down Expand Up @@ -62,16 +63,28 @@
opts = @audit_report.get_opts(reporter, quiet)
expect(opts).to eq({'report' => true, 'format' => 'json-min', 'output' => '/dev/null', 'logger' => Chef::Log})
end
it 'given chef-server sets the format to json-min' do
reporter = 'chef-server'
quiet = true
opts = @audit_report.get_opts(reporter, quiet)
expect(opts).to eq({'report' => true, 'format' => 'json-min', 'output' => '/dev/null', 'logger' => Chef::Log})
end
it 'given chef-visibility sets the format to json' do
reporter = 'chef-visibility'
quiet = true
opts = @audit_report.get_opts(reporter, quiet)
expect(opts).to eq({'report' => true, 'format' => 'json', 'output' => '/dev/null', 'logger' => Chef::Log})
end
it 'given chef-server-visibility sets the format to json' do
reporter = 'chef-server-visibility'
quiet = true
opts = @audit_report.get_opts(reporter, quiet)
expect(opts).to eq({'report' => true, 'format' => 'json', 'output' => '/dev/null', 'logger' => Chef::Log})
end
end

describe 'call' do
it 'given a profile returns a report' do
it 'given a profile, returns a json report' do
require 'inspec'
opts = {'report' => true, 'format' => 'json', 'output' => '/dev/null'}
path = File.expand_path('../../../data/mock_profile.rb', __FILE__)
Expand All @@ -80,5 +93,13 @@
expected_report = /^.*version.*profiles.*controls.*statistics.*duration.*/
expect(report).to match(expected_report)
end
it 'given a profile, returns a json-min report' do
require 'inspec'
opts = {'report' => true, 'format' => 'json-min', 'output' => '/dev/null'}
path = File.expand_path('../../../data/mock_profile.rb', __FILE__)
profiles = [{'name': 'example', 'path': path }]
report = JSON.parse(@audit_report.call(opts, profiles))
expect(report['controls'].length).to eq(2)
end
end
end

0 comments on commit f1b8692

Please sign in to comment.