Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support other sources #50

Merged
merged 2 commits into from
May 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,32 @@ Please ensure that `chef-cookbooks` is the parent directory of `audit` cookbook.

Once the cookbook is available in Chef Server, you need to add the `audit::default` recipe to the run-list of each node. The profiles are selected via the `node['audit']['profiles']` attribute. For example, to run the `base/ssh` and `base/linux` profiles, you can define the attribute in a JSON-based role or environment file like this:

```json
"audit": {
"inspec_version": "0.22.0",
"profiles": {
"base/ssh": true,
"base/linux": true
}
```ruby
audit = {
"inspec_version" => "0.22.0",
"profiles" => {
# org / profile name
'base/linux' => true,
'brewinc/ssh-hardening' => {
# where inspec will fetch from
'source' => 'supermarket://hardening/ssh-hardening',
'key' => 'value',
},
# Windows path
'brewinc/win2012_audit' => {
# filesystem path
'source' => 'E:/profiles/win2012_audit',
},
'brewinc/tmp_compliance_profile' => {
# github
'source' => 'https://github.com/nathenharvey/tmp_compliance_profile',
},
# disable profile
'brewinc/tmp_compliance_profile-master' => {
'source' => '/tmp/tmp_compliance_profile-master',
'disabled' => true,
},
},
}
```

Expand Down Expand Up @@ -100,7 +119,7 @@ can be re-written in InSpec as follows:

```
# rename `control_group` to `control` and use a unique identifier
control "blog-1" do
control "blog-1" do
title 'Check SSH Port' # add the title from `control_group`
# rename the old `control` to `describe`
describe 'SSH' do
Expand All @@ -114,7 +133,7 @@ end
or even simplified to:

```
control "blog-1" do
control "blog-1" do
title 'SSH should be listening on port 22'
describe port(22) do
it { should be_listening }
Expand Down
10 changes: 6 additions & 4 deletions libraries/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ def with_http_rescue(&block)
begin
return yield
rescue Net::HTTPServerException => e
case e.message
case e.response.code
when /401/
Chef::Log.error "#{e} Possible time/date issue on the client."
Chef::Log.error "Possible time/date issue on the client."
when /403/
Chef::Log.error "#{e} Possible offline Compliance Server or chef_gate auth issue."
Chef::Log.error "Possible offline Compliance Server or chef_gate auth issue."
when /404/
Chef::Log.error "Object does not exist on remote server."
end
Chef::Log.error 'Profile NOT downloaded. Will use cached version if available.'
Chef::Log.error e.message
raise e if run_context.node.audit.raise_if_unreachable
end
end
Expand Down
29 changes: 20 additions & 9 deletions libraries/profile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,23 @@ class ComplianceProfile < Chef::Resource # rubocop:disable Metrics/ClassLength
end

require 'inspec'
# load the supermarket plugin
require 'bundles/inspec-supermarket/api'
require 'bundles/inspec-supermarket/target'
check_inspec
end

converge_by 'create cache directory' do
directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create)
end

converge_by 'fetch compliance profile' do
return if path # will be fetched from other source during execute phase

o, p = normalize_owner_profile
Chef::Log.info "Fetch compliance profile #{o}/#{p}"

path = tar_path
directory(::Pathname.new(path).dirname.to_s).run_action(:create)

if token # go direct
reqpath ="owners/#{o}/compliance/#{p}/tar"
Expand Down Expand Up @@ -92,19 +100,22 @@ class ComplianceProfile < Chef::Resource # rubocop:disable Metrics/ClassLength
check_inspec
end

converge_by 'create/verify cache directory' do
directory(::File.join(Chef::Config[:file_cache_path], 'compliance')).run_action(:create)
end

converge_by 'execute compliance profile' do
path = tar_path
path ||= tar_path
report_file = report_path

unless ::File.exist?(path)
Chef::Log.warn "No such file: #{path}"
supported_schemes = %w{http https supermarket compliance chefserver}
if !supported_schemes.include?(URI(path).scheme) && !::File.exist?(path)
Chef::Log.warn "No such path! Skipping: #{path}"
fail "Aborting since profile is not present here: #{path}" if run_context.node.audit.fail_if_not_present
return
end

report_file = report_path

o, p = normalize_owner_profile
Chef::Log.info "Execute compliance profile #{o}/#{p}"
Chef::Log.info "Executing: #{path}"

# TODO: flesh out inspec's report CLI interface,
# make this an execute[inspec check ...]
Expand Down Expand Up @@ -136,7 +147,7 @@ def check_inspec

def normalize_owner_profile
if profile.include?('/')
profile.split('/')
profile.split('/').last(2)
else
[owner || 'base', profile]
end
Expand Down
13 changes: 10 additions & 3 deletions recipes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,23 @@
server = node['audit']['server']

# iterate over all selected profiles
node['audit']['profiles'].each do |owner_profile, enabled|
next unless enabled
node['audit']['profiles'].each do |owner_profile, value|
case value
when Hash
next if value['disabled']
path = value['source']
else
next if value == false
end
fail "Invalid profile name '#{owner_profile}'. "\
"Must contain /, e.g. 'john/ssh'" if owner_profile !~ %r{\/}
o, p = owner_profile.split('/')
o, p = owner_profile.split('/').last(2)

compliance_profile p do
owner o
server server
token token
path path unless path.nil?
inspec_version node['audit']['inspec_version']
quiet node['audit']['quiet'] unless node['audit']['quiet'].nil?
action [:fetch, :execute]
Expand Down
53 changes: 53 additions & 0 deletions spec/unit/recipes/default_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,57 @@
expect { chef_run }.to raise_error("Invalid profile name 'myprofile'. Must contain /, e.g. 'john/ssh'")
end
end

context 'When specifying profiles with alternate sources' do
let(:chef_run) do
runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '6.5')
runner.node.set['audit']['profiles'] = {
'base/linux' => true,
'base/apache' => false,
'brewinc/ssh-hardening' => {
'source' => 'supermarket://hardening/ssh-hardening',
},
'brewinc/tmp_compliance_profile' => {
'source' => 'https://github.com/nathenharvey/tmp_compliance_profile',
},
'brewinc/tmp_compliance_profile-master' => {
'source' => '/tmp/tmp_compliance_profile-master',
},
'exampleorg/myprofile' => {
'disabled' => true,
},
}
runner.converge(described_recipe)
end
it 'executes base/linux in backward compatible mode' do
expect(chef_run).to execute_compliance_profile('linux').with(
path: nil,
)
end
it 'executes brewinc/ssh-hardening from supermarket' do
expect(chef_run).to execute_compliance_profile('ssh-hardening').with(
path: 'supermarket://hardening/ssh-hardening',
)
end
it 'executes brewinc/tmp_compliance_profile from github' do
expect(chef_run).to execute_compliance_profile('tmp_compliance_profile').with(
path: 'https://github.com/nathenharvey/tmp_compliance_profile',
)
end
it 'executes brewinc/tmp_compliance_profile-master from filesystem' do
expect(chef_run).to execute_compliance_profile('tmp_compliance_profile-master').with(
path: '/tmp/tmp_compliance_profile-master',
)
end
it 'does not execute disabled exampleorg/myprofile' do
expect(chef_run).to_not execute_compliance_profile('myprofile')
end
it 'executes execute_compliance_report[chef-server]' do
expect(chef_run).to execute_compliance_report('chef-server')
end

it 'converges successfully' do
expect { chef_run }.to_not raise_error
end
end
end