introduce secrets backend

This commit is contained in:
Christoph Hartmann 2016-05-07 20:17:09 +02:00
parent c7a49056c4
commit f1faf47112
12 changed files with 99 additions and 41 deletions

View file

@ -1,3 +1,14 @@
# Example InSpec Profile with Attributes
This profile uses InSpec attributes to parameterize a profile.
## Usage
```
$ inspec exec examples/profile-attribute --attrs examples/profile-attribute.yml
....
Finished in 0.00178 seconds (files took 0.48529 seconds to load)
4 examples, 0 failures
```

View file

@ -1,20 +1,11 @@
# encoding: utf-8
val_user = attribute('user', default: 'alice', required: true)
val_password = attribute('password', required: true)
val_user = attribute('user', default: 'alice', description: 'An identification for the user')
val_password = attribute('password', description: 'A value for the password')
# that works
describe 'bob' do
it { should eq val_user.value }
end
describe 'secret' do
it { should eq val_password.value }
end
describe val_user.value do
describe val_user do
it { should eq 'bob' }
end
describe val_password.value do
describe val_password do
it { should eq 'secret' }
end

View file

@ -1,10 +0,0 @@
name: inheritance
title: InSpec example inheritance
maintainer: Chef Software, Inc.
copyright: Chef Software, Inc.
copyright_email: support@chef.io
license: Apache 2 license
summary: Demonstrates the use of InSpec profile inheritance
version: 1.0.0
supports:
- os-family: unix

View file

@ -9,7 +9,6 @@ require 'json'
require 'pp'
require 'utils/base_cli'
require 'utils/json_log'
require 'yaml'
class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
class_option :diagnose, type: :boolean,
@ -107,17 +106,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI # rubocop:disable Metrics/ClassLength
desc 'exec PATHS', 'run all test files at the specified PATH.'
exec_options
option :attr_file, type: :array
def exec(*targets)
diagnose
o = opts.dup
# parse attribute file
unless o['attr_file'].nil?
o['attrs'] = {}
o['attr_file'].each do |file|
o['attrs'] = o['attrs'].merge(YAML.load_file(file))
end
end
# run tests
run_tests(targets, o)
end

View file

@ -11,6 +11,7 @@ module Inspec
autoload :CLI, 'inspec/plugins/cli'
autoload :Fetcher, 'inspec/plugins/fetcher'
autoload :SourceReader, 'inspec/plugins/source_reader'
autoload :Secret, 'inspec/plugins/secret'
end
# PLEASE NOTE: The Plugin system is an internal mechanism for connecting

View file

@ -0,0 +1,15 @@
# encoding: utf-8
# author: Dominik Richter
# author: Christoph Hartmann
require 'utils/plugin_registry'
module Inspec
module Plugins
class Secret < PluginRegistry::Plugin
def self.plugin_registry
Inspec::SecretsBackend
end
end
end
end

View file

@ -86,17 +86,13 @@ module Inspec
end
end
def register_value(&block)
@values.push(block)
end
def register_attribute(name, options = {})
# we need to return an attribute object, in order to allow lazy access
# we need to return an attribute object, to allow dermination of default values
attr = Attribute.new(name, options)
# set value
attr.value(@conf['attrs'][attr.name]) unless @conf['attrs'].nil?
# read value from given gived values
attr.value(@conf['attributes'][attr.name]) unless @conf['attributes'].nil?
@attributes.push(attr)
attr
attr.value
end
def set_header(field, val)

View file

@ -10,6 +10,7 @@ require 'inspec/backend'
require 'inspec/profile_context'
require 'inspec/profile'
require 'inspec/metadata'
require 'inspec/secrets'
# spec requirements
module Inspec
@ -28,6 +29,7 @@ module Inspec
# list of profile attributes
@attributes = []
load_attributes(@conf)
configure_transport
end
@ -48,6 +50,21 @@ module Inspec
@backend = Inspec::Backend.create(@conf)
end
# determine all attributes before the execution, fetch data from secrets backend
def load_attributes(options)
attributes = {}
# read endpoints for secrets eg. yml file
secrets_targets = options['attrs']
unless secrets_targets.nil?
secrets_targets.each do |target|
secrets = Inspec::SecretsBackend.resolve(target)
# merge hash values
attributes = attributes.merge(secrets.attributes) unless secrets.nil? || secrets.attributes.nil?
end
end
options['attributes'] = attributes
end
def add_target(target, options = {})
profile = Inspec::Profile.for_target(target, options)
fail "Could not resolve #{target} to valid input." if profile.nil?

19
lib/inspec/secrets.rb Normal file
View file

@ -0,0 +1,19 @@
# encoding: utf-8
# author: Christoph Hartmann
# author: Dominik Richter
require 'inspec/plugins'
require 'utils/plugin_registry'
module Inspec
SecretsBackend = PluginRegistry.new
def self.secrets(version)
if version != 1
fail 'Only secrets version 1 is supported!'
end
Inspec::Plugins::Secret
end
end
require 'inspec/secrets/yaml'

View file

@ -0,0 +1,23 @@
# encoding: utf-8
require 'yaml'
module Secrets
class YAML < Inspec.secrets(1)
name 'yaml'
attr_reader :attributes
def self.resolve(target)
unless target.is_a?(String) && File.file?(target) && target.end_with?('.yml')
return nil
end
new(target)
end
# array of yaml file paths
def initialize(target)
@attributes = ::YAML.load_file(target)
end
end
end

View file

@ -55,6 +55,8 @@ module Inspec
desc: 'Which formatter to use: progress, documentation, json'
option :color, type: :boolean, default: true,
desc: 'Use colors in output.'
option :attrs, type: :array,
desc: 'Load attributes file (experimental)'
end
private

View file

@ -39,7 +39,6 @@ describe 'inspec exec with json formatter' do
actual = profile.dup
key = actual.delete('controls').keys
.find { |x| x =~ /generated from example.rb/ }
actual.must_equal({
"name" => "profile",
"title" => "InSpec Example Profile",
@ -55,6 +54,7 @@ describe 'inspec exec with json formatter' do
"controls/example.rb" => {"title"=>"/tmp profile", "controls"=>["tmp-1.0", key]},
"controls/gordon.rb" => {"title"=>"Gordon Config Checks", "controls"=>["gordon-1.0"]},
},
"attributes" => []
})
end