Skip to content

Commit

Permalink
stelligent#17 add rule directory for add external json rules
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Kascic committed Feb 7, 2017
1 parent 4ef7042 commit d95a9a4
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 19 deletions.
4 changes: 3 additions & 1 deletion bin/cfn_nag
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ opts = Trollop::options do
opt :input_json_path, 'CloudFormation template to nag on or directory of templates - all *.json and *.template recursively', type: :io, required: true
opt :output_format, 'Format of results: [txt, json]', type: :string, default: 'txt'
opt :debug, 'Enable debug output', type: :boolean, required: false, default: false
opt :rule_directory, 'Extra rule directories', type: :strings, require: false, default: [], multi: true
end

Trollop::die(:output_format,
'Must be txt or json') unless %w(txt json).include?(opts[:output_format])

CfnNag::configure_logging(opts)
exit CfnNag.new.audit(input_json_path: opts[:input_json_path],
output_format: opts[:output_format])
output_format: opts[:output_format],
rule_directories: opts[:rule_directory])
54 changes: 36 additions & 18 deletions lib/cfn_nag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ class CfnNag
def initialize
@warning_registry = []
@violation_registry = []
@custom_rule_registry = [
SecurityGroupMissingEgressRule,
UserMissingGroupRule,
UnencryptedS3PutObjectAllowedRule
]
end

def dump_rules
Expand Down Expand Up @@ -47,24 +52,29 @@ def dump_rules
end

def audit(input_json_path:,
rule_directories: [],
output_format:'txt')
validate_extra_rule_directories(rule_directories)

aggregate_results = audit_results input_json_path: input_json_path,
output_format: output_format
output_format: output_format,
rule_directories: rule_directories.flatten

aggregate_results.inject(0) { |total_failure_count, results| total_failure_count + results[:file_results][:failure_count] }
end

def audit_results(input_json_path:,
output_format:'txt')
output_format:'txt',
rule_directories: [])

templates = discover_templates(input_json_path)

aggregate_results = []
templates.each do |template|
aggregate_results << {
filename: template,
file_results: audit_file(input_json_path: template)
file_results: audit_file(input_json_path: template,
rule_directories: rule_directories)
}
end

Expand All @@ -85,7 +95,7 @@ def self.configure_logging(opts)
logger.add_appenders Logging.appenders.stdout
end

def audit_template(input_json:)
def audit_template(input_json:, rule_directories: [])
@stop_processing = false
@violations = []

Expand All @@ -96,7 +106,7 @@ def audit_template(input_json:)
@stop_processing = true
end

generic_json_rules input_json unless @stop_processing == true
generic_json_rules(input_json, rule_directories) unless @stop_processing == true

custom_rules input_json unless @stop_processing == true

Expand All @@ -108,12 +118,20 @@ def audit_template(input_json:)

private

def validate_extra_rule_directories(rule_directories)
rule_directories.flatten.each do |rule_directory|
fail "Not a real directory #{rule_directory}" unless File.directory? rule_directory
end
end


def render_results(aggregate_results:,output_format:)
results_renderer(output_format).new.render(aggregate_results)
end

def audit_file(input_json_path:)
audit_template(input_json: IO.read(input_json_path))
def audit_file(input_json_path:, rule_directories:)
audit_template(input_json: IO.read(input_json_path),
rule_directories: rule_directories)
end

def discover_templates(input_json_path)
Expand Down Expand Up @@ -162,15 +180,14 @@ def jruby_in_a_jar?
__dir__.start_with? '/uri:classloader'
end

def generic_json_rules(input_json)
def generic_json_rules(input_json, rule_directories)
unless command? 'jq'
fail 'jq executable must be available in PATH'
end

if jruby_in_a_jar?
rules = %w(basic_rules cfn_rules cidr_rules cloudfront_rules ebs_rules iam_policy_rules iam_user_rules lambda_rules loadbalancer_rules port_rules s3_bucket_rules sns_rules sqs_rules)
rules = rules.map { |rule| File.join(__dir__, 'json_rules', "#{rule}.rb")[1..-1] }
puts "Jruby it is: #{rules}"
else
rules = Dir[File.join(__dir__, 'json_rules', '*.rb')].sort
end
Expand All @@ -179,21 +196,22 @@ def generic_json_rules(input_json)
@input_json = input_json
eval IO.read(rule_file)
end

rule_directories.each do |rule_directory|
rules = Dir[File.join(rule_directory, '*.rb')].sort

rules.each do |rule_file|
@input_json = input_json
eval IO.read(rule_file)
end
end
end

def custom_rules(input_json)
cfn_model = CfnModel.new.parse(input_json)
custom_rule_registry.each do |rule_class|
@custom_rule_registry.each do |rule_class|
audit_result = rule_class.new.audit(cfn_model)
@violations << audit_result unless audit_result.nil?
end
end

def custom_rule_registry
[
SecurityGroupMissingEgressRule,
UserMissingGroupRule,
UnencryptedS3PutObjectAllowedRule
]
end
end
30 changes: 30 additions & 0 deletions spec/cfn_nag_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -343,4 +343,34 @@ def test_template(template_name)
expect(actual_aggregate_results).to eq expected_aggregate_results
end
end

context 'igw rule installed in gem', :rule_directory do

it 'flags a violation' do
expected_aggregate_results = [
{
filename: File.join(__dir__, 'test_templates/igw.json'),
file_results: {
failure_count: 1,
violations: [
Violation.new(type: Violation::FAILING_VIOLATION,
message: 'Internet Gateways are not allowed',
logical_resource_ids: %w(igw))
]
}
}
]

template_name = 'igw.json'

failure_count = @cfn_nag.audit(input_json_path: test_template(template_name),
rule_directories: %w(spec/other_json_rules))
expect(failure_count).to eq 1

actual_aggregate_results = @cfn_nag.audit_results(input_json_path: test_template(template_name),
rule_directories: %w(spec/other_json_rules))
expect(actual_aggregate_results).to eq expected_aggregate_results
end
end

end
9 changes: 9 additions & 0 deletions spec/test_templates/igw.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"AWSTemplateFormatVersion": "2010-09-09",

"Resources" : {
"igw": {
"Type": "AWS::EC2::InternetGateway"
}
}
}

0 comments on commit d95a9a4

Please sign in to comment.