From 8966e93464d9d03bbb0eef063a337ca6d8d865ac Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 18 May 2017 20:58:05 +0200 Subject: [PATCH] add automate fetcher for chef solo Signed-off-by: Christoph Hartmann --- files/default/handler/audit_report.rb | 13 +++- files/default/vendor/chef-automate/fetcher.rb | 69 +++++++++++++++++++ libraries/compliance.rb | 2 +- 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 files/default/vendor/chef-automate/fetcher.rb diff --git a/files/default/handler/audit_report.rb b/files/default/handler/audit_report.rb index 809a0c49..6f5360b3 100644 --- a/files/default/handler/audit_report.rb +++ b/files/default/handler/audit_report.rb @@ -27,6 +27,7 @@ def report interval_time = node['audit']['interval']['time'] profiles = node['audit']['profiles'] quiet = node['audit']['quiet'] + fetcher = node['audit']['fetcher'] # load inspec, supermarket bundle and compliance bundle load_needed_dependencies @@ -36,7 +37,9 @@ def report reporters.include?('chef-server-compliance') || reporters.include?('chef-server-visibility') || reporters.include?('chef-server-automate') || - node['audit']['fetcher'] == 'chef-server' + %w{chef-server chef-server-compliance chef-server-visibility chef-server-automate}.include?(fetcher) + + load_automate_fetcher if fetcher == 'chef-automate' # ensure authentication for Chef Compliance is in place, see libraries/compliance.rb login_to_compliance(server, user, token, refresh_token) if reporters.include?('chef-compliance') @@ -95,11 +98,17 @@ def load_needed_dependencies # we expect inspec to be loaded before def load_chef_fetcher - Chef::Log.debug "Load vendored ruby files from: #{cookbook_vendor_path}" + Chef::Log.debug "Load Chef Server fetcher from: #{cookbook_vendor_path}" $LOAD_PATH.unshift(cookbook_vendor_path) require 'chef-server/fetcher' end + def load_automate_fetcher + Chef::Log.debug "Load Chef Automate fetcher from: #{cookbook_vendor_path}" + $LOAD_PATH.unshift(cookbook_vendor_path) + require 'chef-automate/fetcher' + end + # sets format to json-min when chef-compliance, json when chef-automate def get_opts(format, quiet) output = quiet ? ::File::NULL : $stdout diff --git a/files/default/vendor/chef-automate/fetcher.rb b/files/default/vendor/chef-automate/fetcher.rb new file mode 100644 index 00000000..fbffe2c2 --- /dev/null +++ b/files/default/vendor/chef-automate/fetcher.rb @@ -0,0 +1,69 @@ +module ChefAutomate + class Fetcher < Compliance::Fetcher + name 'chef-automate' + + # it positions itself before `compliance` fetcher + # only load it, if you want to use audit cookbook in Chef Solo with Chef Automate + priority 502 + + def self.resolve(target) + uri = if target.is_a?(String) && URI(target).scheme == 'compliance' + URI(target) + elsif target.respond_to?(:key?) && target.key?(:compliance) + URI("compliance://#{target[:compliance]}") + end + + return nil if uri.nil? + + # we have detailed information available in our lockfile, no need to ask the server + if target.respond_to?(:key?) && target.key?(:url) + profile_fetch_url = target[:url] + config = {} + else + # verifies that the target e.g base/ssh exists + profile = sanitize_profile_name(uri) + owner, id = profile.split('/') + profile_path = "/compliance/profiles/#{owner}/#{id}/tar" + dc = Chef::Config[:data_collector] + url = URI(dc[:server_url]) + url.path = profile_path + profile_fetch_url = url.to_s + config = { + 'token' => dc[:token], + } + end + + new(profile_fetch_url, config) + rescue URI::Error => _e + nil + end + + # returns a parsed url for `admin/profile` or `compliance://admin/profile` + # TODO: remove in future, copied from inspec to support older versions of inspec + def self.sanitize_profile_name(profile) + if URI(profile).scheme == 'compliance' + uri = URI(profile) + else + uri = URI("compliance://#{profile}") + end + uri.to_s.sub(%r{^compliance:\/\/}, '') + end + + def initialize(url, opts) + options = { + 'insecure' => true, + 'token' => opts['token'], + 'server_type' => 'automate', + 'automate' => { + 'ent' => '', + 'token_type' => 'dctoken', + }, + } + super(url, options) + end + + def to_s + 'Chef Automate for Chef Solo Fetcher' + end + end +end diff --git a/libraries/compliance.rb b/libraries/compliance.rb index b5208494..0b717d4b 100644 --- a/libraries/compliance.rb +++ b/libraries/compliance.rb @@ -39,7 +39,7 @@ def upload_profile(config, owner, profile_name, path) Compliance::API.upload(config, owner, profile_name, path) end -# TODO: temporary, we should not use this +# TODO: temporary, we should use a stateless approach # TODO: harmonize with CLI login_refreshtoken method def login_to_compliance(server, user, access_token, refresh_token) if !refresh_token.nil?