inspec-iggy 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +19 -0
- data/README.md +34 -3
- data/inspec-iggy.gemspec +2 -2
- data/lib/inspec-iggy/cloudformation/cli_command.rb +3 -3
- data/lib/inspec-iggy/cloudformation/{parser.rb → generate.rb} +9 -9
- data/lib/inspec-iggy/inspec_helper.rb +443 -27
- data/lib/inspec-iggy/platforms/aws_helper.rb +42 -0
- data/lib/inspec-iggy/platforms/azure_helper.rb +38 -0
- data/lib/inspec-iggy/platforms/gcp_helper.rb +168 -0
- data/lib/inspec-iggy/profile_helper.rb +50 -29
- data/lib/inspec-iggy/terraform/cli_command.rb +74 -49
- data/lib/inspec-iggy/terraform/generate.rb +130 -0
- data/lib/inspec-iggy/terraform/negative.rb +112 -0
- data/lib/inspec-iggy/version.rb +1 -1
- metadata +12 -8
- data/lib/inspec-iggy/terraform/parser.rb +0 -148
@@ -0,0 +1,130 @@
|
|
1
|
+
# parses Terraform d.tfstate files
|
2
|
+
|
3
|
+
require 'inspec/objects/control'
|
4
|
+
require 'inspec/objects/ruby_helper'
|
5
|
+
require 'inspec/objects/describe'
|
6
|
+
|
7
|
+
require 'inspec-iggy/file_helper'
|
8
|
+
require 'inspec-iggy/inspec_helper'
|
9
|
+
|
10
|
+
module InspecPlugins::Iggy::Terraform
|
11
|
+
class Generate
|
12
|
+
# parse through the JSON and generate InSpec controls
|
13
|
+
def self.parse_generate(tf_file, resource_path, platform)
|
14
|
+
# parse the tfstate file to get the Terraform resources
|
15
|
+
tfstate = InspecPlugins::Iggy::FileHelper.parse_json(tf_file)
|
16
|
+
absolutename = File.absolute_path(tf_file)
|
17
|
+
|
18
|
+
# take those Terraform resources and map to InSpec resources by name and keep all attributes
|
19
|
+
# resources -> [{name1 -> {unfiltered_attributes}, name2 -> {unfiltered_attributes}]
|
20
|
+
parsed_resources = parse_resources(tfstate, resource_path, platform)
|
21
|
+
|
22
|
+
# InSpec controls generated from matched_resources and attributes
|
23
|
+
generated_controls = parse_controls(parsed_resources, absolutename, platform)
|
24
|
+
|
25
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_generate generated_controls = #{generated_controls}"
|
26
|
+
generated_controls
|
27
|
+
end
|
28
|
+
|
29
|
+
# returns the list of all InSpec resources found in the tfstate file
|
30
|
+
def self.parse_resources(tfstate, resource_path, _platform)
|
31
|
+
# iterate over the resources
|
32
|
+
resources = {}
|
33
|
+
tfstate['modules'].each do |m|
|
34
|
+
tf_resources = m['resources']
|
35
|
+
tf_resources.keys.each do |tf_res|
|
36
|
+
resource_type = tf_resources[tf_res]['type']
|
37
|
+
|
38
|
+
next if resource_type.eql?('random_id') # this is a Terraform resource, not a provider resource
|
39
|
+
|
40
|
+
# load resource pack resources
|
41
|
+
InspecPlugins::Iggy::InspecHelper.load_resource_pack(resource_path) if resource_path
|
42
|
+
|
43
|
+
# add translation layer
|
44
|
+
if InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES.key?(resource_type)
|
45
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_resources resource_type = #{resource_type} #{InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES[resource_type]} TRANSLATED"
|
46
|
+
resource_type = InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES[resource_type]
|
47
|
+
end
|
48
|
+
resources[resource_type] = {} if resources[resource_type].nil?
|
49
|
+
# does this match an InSpec resource?
|
50
|
+
if InspecPlugins::Iggy::InspecHelper.available_resources.include?(resource_type)
|
51
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_resources resource_type = #{resource_type} MATCHED"
|
52
|
+
resource_id = tf_resources[tf_res]['primary']['id']
|
53
|
+
resource_attributes = tf_resources[tf_res]['primary']['attributes']
|
54
|
+
resources[resource_type][resource_id] = resource_attributes
|
55
|
+
else
|
56
|
+
Inspec::Log.debug "Iggy::Terraform.Generate.parse_generate resource_type = #{resource_type} SKIPPED"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
resources
|
61
|
+
end
|
62
|
+
|
63
|
+
# take the resources and map to describes
|
64
|
+
def self.parse_controls(resources, absolutename, platform) # rubocop:disable Metrics/AbcSize
|
65
|
+
controls = []
|
66
|
+
# iterate over the resources types and their ids
|
67
|
+
resources.keys.each do |resource_type|
|
68
|
+
resources[resource_type].keys.each do |resource_id|
|
69
|
+
# insert new control based off the resource's ID
|
70
|
+
ctrl = Inspec::Control.new
|
71
|
+
ctrl.id = "#{resource_type}::#{resource_id}"
|
72
|
+
ctrl.title = "InSpec-Iggy #{resource_type}::#{resource_id}"
|
73
|
+
ctrl.descriptions[:default] = "#{resource_type}::#{resource_id} from the source file #{absolutename}\nGenerated by InSpec-Iggy v#{InspecPlugins::Iggy::VERSION}"
|
74
|
+
ctrl.impact = '1.0'
|
75
|
+
|
76
|
+
describe = Inspec::Describe.new
|
77
|
+
case platform
|
78
|
+
when 'aws' # rubocop:disable Lint/EmptyWhen
|
79
|
+
when 'azure' # rubocop:disable Lint/EmptyWhen
|
80
|
+
# this is a hack for azure, we need a better longterm solution
|
81
|
+
# if resource.start_with?('azure_')
|
82
|
+
# name = resource_id.split('/').last
|
83
|
+
# else
|
84
|
+
# name = resource_id
|
85
|
+
# end
|
86
|
+
|
87
|
+
# if resource_type.start_with?('azure_')
|
88
|
+
# if resource_type.eql?('azure_resource_group')
|
89
|
+
# describe.qualifier.push([resource_type, name: name])
|
90
|
+
# else
|
91
|
+
# resource_group = resource_id.split('resourceGroups/').last.split('/').first
|
92
|
+
# describe.qualifier.push([resource_type, name: name, group_name: resource_group])
|
93
|
+
# end
|
94
|
+
when 'gcp'
|
95
|
+
qualifier = [resource_type, {}]
|
96
|
+
if InspecPlugins::Iggy::InspecHelper.available_resource_qualifiers(platform).key?(resource_type)
|
97
|
+
InspecPlugins::Iggy::InspecHelper.available_resource_qualifiers(platform)[resource_type].each do |parameter|
|
98
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_controls #{resource_type} qualifier found = #{parameter} MATCHED"
|
99
|
+
value = resources[resource_type][resource_id][parameter.to_s] # pull value out of the tf attributes
|
100
|
+
qualifier[1][parameter] = value
|
101
|
+
end
|
102
|
+
end
|
103
|
+
describe.qualifier.push(qualifier)
|
104
|
+
end
|
105
|
+
|
106
|
+
# ensure the resource exists unless Azure, which currently doesn't support it as of InSpec 2.2
|
107
|
+
describe.add_test(nil, 'exist', nil) unless resource_type.start_with?('azure_')
|
108
|
+
|
109
|
+
# if there's a match, see if there are matching InSpec properties
|
110
|
+
inspec_properties = InspecPlugins::Iggy::InspecHelper.resource_properties(resource_type, platform)
|
111
|
+
# push stuff back into inspec_properties?
|
112
|
+
resources[resource_type][resource_id].keys.each do |attr|
|
113
|
+
if inspec_properties.member?(attr)
|
114
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_controls #{resource_type} inspec_property = #{attr} MATCHED"
|
115
|
+
value = resources[resource_type][resource_id][attr]
|
116
|
+
describe.add_test(attr, 'cmp', value)
|
117
|
+
else
|
118
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_controls #{resource_type} inspec_property = #{attr} SKIPPED"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
ctrl.add_test(describe)
|
123
|
+
controls.push(ctrl)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
Inspec::Log.debug "Iggy::Terraform::Generate.parse_generate controls = #{controls}"
|
127
|
+
controls
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# returns negative of Terraform tfstate file coverage
|
2
|
+
|
3
|
+
require 'inspec/objects/control'
|
4
|
+
require 'inspec/objects/ruby_helper'
|
5
|
+
require 'inspec/objects/describe'
|
6
|
+
|
7
|
+
require 'inspec-iggy/file_helper'
|
8
|
+
require 'inspec-iggy/inspec_helper'
|
9
|
+
require 'inspec-iggy/terraform/generate'
|
10
|
+
|
11
|
+
module InspecPlugins::Iggy::Terraform
|
12
|
+
class Negative
|
13
|
+
# parse through the JSON and generate InSpec controls
|
14
|
+
def self.parse_negative(tf_file, resource_path, platform)
|
15
|
+
tfstate = InspecPlugins::Iggy::FileHelper.parse_json(tf_file)
|
16
|
+
sourcefile = File.absolute_path(tf_file)
|
17
|
+
|
18
|
+
# take those Terraform resources and map to InSpec resources by name and keep all attributes
|
19
|
+
parsed_resources = InspecPlugins::Iggy::Terraform::Generate.parse_resources(tfstate, resource_path, platform)
|
20
|
+
|
21
|
+
# subtract matched resources from all available resources
|
22
|
+
negative_controls = parse_unmatched_resources(parsed_resources, sourcefile, platform)
|
23
|
+
negative_controls += parse_matched_resources(parsed_resources, sourcefile, platform)
|
24
|
+
|
25
|
+
negative_controls
|
26
|
+
end
|
27
|
+
|
28
|
+
# return controls for the iterators of things unmatched in the terraform.tfstate
|
29
|
+
def self.parse_unmatched_resources(resources, sourcefile, platform)
|
30
|
+
resources.extend Hashie::Extensions::DeepFind # use to find iterators' values from other attributes
|
31
|
+
unmatched_resources = InspecPlugins::Iggy::InspecHelper.available_resource_iterators(platform).keys - resources.keys
|
32
|
+
Inspec::Log.debug "Terraform::Negative.parse_unmatched_resources unmatched_resources #{unmatched_resources}"
|
33
|
+
unmatched_controls = []
|
34
|
+
unmatched_resources.each do |unmatched|
|
35
|
+
unresources = InspecPlugins::Iggy::InspecHelper.available_resource_iterators(platform)[unmatched]
|
36
|
+
iterator = unresources['iterator']
|
37
|
+
ctrl = Inspec::Control.new
|
38
|
+
ctrl.id = "NEGATIVE-COVERAGE:#{iterator}"
|
39
|
+
ctrl.title = "InSpec-Iggy NEGATIVE-COVERAGE:#{iterator}"
|
40
|
+
ctrl.descriptions[:default] = "NEGATIVE-COVERAGE:#{iterator} from the source file #{sourcefile}\nGenerated by InSpec-Iggy v#{InspecPlugins::Iggy::VERSION}"
|
41
|
+
ctrl.impact = '1.0'
|
42
|
+
describe = Inspec::Describe.new
|
43
|
+
qualifier = [iterator, {}]
|
44
|
+
unresources['qualifiers'].each do |parameter|
|
45
|
+
Inspec::Log.debug "Terraform::Negative.parse_unmatched_resources #{iterator} qualifier found = #{parameter} MATCHED"
|
46
|
+
value = resources.deep_find(parameter.to_s) # value comes from another likely source. Assumption is values are consistent for this type of field
|
47
|
+
qualifier[1][parameter] = value
|
48
|
+
end
|
49
|
+
describe.qualifier.push(qualifier)
|
50
|
+
describe.add_test(nil, 'exist', nil, { negated: true }) # last field is negated
|
51
|
+
ctrl.add_test(describe)
|
52
|
+
unmatched_controls.push(ctrl)
|
53
|
+
end
|
54
|
+
Inspec::Log.debug "Terraform::Negative.parse_unmatched_resources negative_controls = #{unmatched_controls}"
|
55
|
+
unmatched_controls
|
56
|
+
end
|
57
|
+
|
58
|
+
# controls for iterators minus the matched resources
|
59
|
+
def self.parse_matched_resources(resources, sourcefile, platform) # rubocop:disable Metrics/AbcSize
|
60
|
+
Inspec::Log.debug "Terraform::Negative.parse_matched_resources matched_resources #{resources.keys}"
|
61
|
+
matched_controls = []
|
62
|
+
resources.keys.each do |resource|
|
63
|
+
resources[resource].extend Hashie::Extensions::DeepFind # use to find iterators' values from other attributes
|
64
|
+
resource_iterators = InspecPlugins::Iggy::InspecHelper.available_resource_iterators(platform)[resource]
|
65
|
+
if resource_iterators.nil?
|
66
|
+
Inspec::Log.warn "No iterator matching #{resource} for #{platform} found!"
|
67
|
+
next
|
68
|
+
else
|
69
|
+
iterator = resource_iterators['iterator']
|
70
|
+
index = resource_iterators['index']
|
71
|
+
Inspec::Log.debug "Terraform::Negative.parse_matched_resources iterator:#{iterator} index:#{index}"
|
72
|
+
end
|
73
|
+
# Nothing but the finest bespoke hand-built InSpec
|
74
|
+
ctrl = "control 'NEGATIVE-COVERAGE:#{iterator}' do\n"
|
75
|
+
ctrl += " title 'InSpec-Iggy NEGATIVE-COVERAGE:#{iterator}'\n"
|
76
|
+
ctrl += " desc \"\n"
|
77
|
+
ctrl += " NEGATIVE-COVERAGE:#{iterator} from the source file #{sourcefile}\n\n"
|
78
|
+
ctrl += " Generated by InSpec-Iggy v#{InspecPlugins::Iggy::VERSION}\"\n\n"
|
79
|
+
ctrl += " impact 1.0\n"
|
80
|
+
# get the qualifiers for the resource iterator
|
81
|
+
ctrl += " (#{iterator}({ "
|
82
|
+
resource_iterators['qualifiers'].each do |parameter|
|
83
|
+
Inspec::Log.debug "Terraform::Negative.parse_matched_resources #{iterator} qualifier found = #{parameter} MATCHED"
|
84
|
+
value = resources[resource].deep_find(parameter.to_s) # value comes from resources being evaluated. Assumption is values are consistent for this type of field
|
85
|
+
ctrl += "#{parameter}: '#{value}', "
|
86
|
+
end
|
87
|
+
ctrl += "}).#{index} - [\n"
|
88
|
+
# iterate over the resources
|
89
|
+
resources[resource].keys.each do |resource_name|
|
90
|
+
ctrl += " '#{resource_name}',\n"
|
91
|
+
end
|
92
|
+
ctrl += " ]).each do |name|\n"
|
93
|
+
ctrl += " describe #{resource}({ name: name, "
|
94
|
+
# iterate over resource qualifiers
|
95
|
+
InspecPlugins::Iggy::InspecHelper.available_resource_qualifiers(platform)[resource].each do |parameter|
|
96
|
+
next if parameter.eql?(:name)
|
97
|
+
Inspec::Log.debug "Iggy::Terraform::Negative.parse_matched_resources #{resource} qualifier found = #{parameter} MATCHED"
|
98
|
+
value = resources[resource].deep_find(parameter.to_s) # value comes from resources being evaluated. Assumption is values are consistent for this type of field
|
99
|
+
ctrl += "#{parameter}: '#{value}', "
|
100
|
+
end
|
101
|
+
ctrl += "}) do\n"
|
102
|
+
ctrl += " it { should_not exist }\n"
|
103
|
+
ctrl += " end\n"
|
104
|
+
ctrl += " end\n"
|
105
|
+
ctrl += "end\n\n"
|
106
|
+
matched_controls.push(ctrl)
|
107
|
+
end
|
108
|
+
Inspec::Log.debug "Terraform::Negative.parse_matched_resources negative_controls = #{matched_controls}"
|
109
|
+
matched_controls
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/inspec-iggy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inspec-iggy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Ray
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inspec
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '2.3'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: '5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,9 +29,9 @@ dependencies:
|
|
29
29
|
version: '2.3'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
33
|
-
description: InSpec plugin to generate InSpec
|
34
|
-
|
32
|
+
version: '5'
|
33
|
+
description: InSpec plugin to generate InSpec profiles from Terraform and CloudFormation
|
34
|
+
to ensure automatic compliance coverage.
|
35
35
|
email:
|
36
36
|
- matt@chef.io
|
37
37
|
executables: []
|
@@ -43,13 +43,17 @@ files:
|
|
43
43
|
- inspec-iggy.gemspec
|
44
44
|
- lib/inspec-iggy.rb
|
45
45
|
- lib/inspec-iggy/cloudformation/cli_command.rb
|
46
|
-
- lib/inspec-iggy/cloudformation/
|
46
|
+
- lib/inspec-iggy/cloudformation/generate.rb
|
47
47
|
- lib/inspec-iggy/file_helper.rb
|
48
48
|
- lib/inspec-iggy/inspec_helper.rb
|
49
|
+
- lib/inspec-iggy/platforms/aws_helper.rb
|
50
|
+
- lib/inspec-iggy/platforms/azure_helper.rb
|
51
|
+
- lib/inspec-iggy/platforms/gcp_helper.rb
|
49
52
|
- lib/inspec-iggy/plugin.rb
|
50
53
|
- lib/inspec-iggy/profile_helper.rb
|
51
54
|
- lib/inspec-iggy/terraform/cli_command.rb
|
52
|
-
- lib/inspec-iggy/terraform/
|
55
|
+
- lib/inspec-iggy/terraform/generate.rb
|
56
|
+
- lib/inspec-iggy/terraform/negative.rb
|
53
57
|
- lib/inspec-iggy/version.rb
|
54
58
|
homepage: https://github.com/mattray/inspec-iggy
|
55
59
|
licenses:
|
@@ -1,148 +0,0 @@
|
|
1
|
-
# parses Terraform d.tfstate files
|
2
|
-
|
3
|
-
require 'inspec/objects/control'
|
4
|
-
require 'inspec/objects/ruby_helper'
|
5
|
-
require 'inspec/objects/describe'
|
6
|
-
|
7
|
-
require 'inspec-iggy/file_helper'
|
8
|
-
require 'inspec-iggy/inspec_helper'
|
9
|
-
|
10
|
-
module InspecPlugins::Iggy::Terraform
|
11
|
-
class Parser
|
12
|
-
# disabled extract functionality
|
13
|
-
# makes it easier to change out later
|
14
|
-
# TAG_NAME = 'iggy_name_'.freeze
|
15
|
-
# TAG_URL = 'iggy_url_'.freeze
|
16
|
-
|
17
|
-
# parse through the JSON and generate InSpec controls
|
18
|
-
def self.parse_generate(tf_file) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
19
|
-
tfstate = InspecPlugins::Iggy::FileHelper.parse_json(tf_file)
|
20
|
-
absolutename = File.absolute_path(tf_file)
|
21
|
-
|
22
|
-
# InSpec controls generated
|
23
|
-
generated_controls = []
|
24
|
-
|
25
|
-
# iterate over the resources
|
26
|
-
tfstate['modules'].each do |m|
|
27
|
-
tf_resources = m['resources']
|
28
|
-
tf_resources.keys.each do |tf_res|
|
29
|
-
tf_res_type = tf_resources[tf_res]['type']
|
30
|
-
|
31
|
-
# add translation layer
|
32
|
-
if InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES.key?(tf_res_type)
|
33
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} #{InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES[tf_res_type]} TRANSLATED"
|
34
|
-
tf_res_type = InspecPlugins::Iggy::InspecHelper::TRANSLATED_RESOURCES[tf_res_type]
|
35
|
-
end
|
36
|
-
|
37
|
-
# does this match an InSpec resource?
|
38
|
-
if InspecPlugins::Iggy::InspecHelper::RESOURCES.include?(tf_res_type)
|
39
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} MATCHED"
|
40
|
-
tf_res_id = tf_resources[tf_res]['primary']['id']
|
41
|
-
|
42
|
-
# insert new control based off the resource's ID
|
43
|
-
ctrl = Inspec::Control.new
|
44
|
-
ctrl.id = "#{tf_res_type}::#{tf_res_id}"
|
45
|
-
ctrl.title = "InSpec-Iggy #{tf_res_type}::#{tf_res_id}"
|
46
|
-
ctrl.descriptions[:default] = "#{tf_res_type}::#{tf_res_id} from the source file #{absolutename}\nGenerated by InSpec-Iggy v#{InspecPlugins::Iggy::VERSION}"
|
47
|
-
ctrl.impact = '1.0'
|
48
|
-
|
49
|
-
describe = Inspec::Describe.new
|
50
|
-
# describes the resource with the name as argument
|
51
|
-
# this is a hack for azure, we need a better longterm solution
|
52
|
-
if tf_res_type.start_with?('azure_')
|
53
|
-
name = tf_res_id.split('/').last
|
54
|
-
else
|
55
|
-
name = tf_res_id
|
56
|
-
end
|
57
|
-
|
58
|
-
# describes the resource with the id as argument
|
59
|
-
# going to need to move the special Azure code out, and add helpers for each provider
|
60
|
-
if tf_res_type.start_with?('azure_')
|
61
|
-
if tf_res_type.eql?('azure_resource_group')
|
62
|
-
describe.qualifier.push([tf_res_type, name: name])
|
63
|
-
else
|
64
|
-
resource_group = tf_res_id.split('resourceGroups/').last.split('/').first
|
65
|
-
describe.qualifier.push([tf_res_type, name: name, group_name: resource_group])
|
66
|
-
end
|
67
|
-
else
|
68
|
-
describe.qualifier.push([tf_res_type, tf_res_id])
|
69
|
-
end
|
70
|
-
|
71
|
-
# ensure the resource exists unless Azure, which currently doesn't support it as of InSpec 2.2
|
72
|
-
describe.add_test(nil, 'exist', nil) unless tf_res_type.start_with?('azure_')
|
73
|
-
|
74
|
-
# if there's a match, see if there are matching InSpec properties
|
75
|
-
inspec_properties = InspecPlugins::Iggy::InspecHelper.resource_properties(tf_res_type)
|
76
|
-
# push stuff back into inspec_properties?
|
77
|
-
inspec_properties.push('name') if tf_res_type.start_with?('azure_')
|
78
|
-
tf_resources[tf_res]['primary']['attributes'].keys.each do |attr|
|
79
|
-
if inspec_properties.member?(attr)
|
80
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate #{tf_res_type} inspec_property = #{attr} MATCHED"
|
81
|
-
value = tf_resources[tf_res]['primary']['attributes'][attr]
|
82
|
-
describe.add_test(attr, 'cmp', value)
|
83
|
-
else
|
84
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate #{tf_res_type} inspec_property = #{attr} SKIPPED"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
ctrl.add_test(describe)
|
89
|
-
generated_controls.push(ctrl)
|
90
|
-
else
|
91
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} SKIPPED"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
Inspec::Log.debug "Iggy::Terraform.parse_generate generated_controls = #{generated_controls}"
|
96
|
-
generated_controls
|
97
|
-
end
|
98
|
-
|
99
|
-
# disabled extract functionality
|
100
|
-
# # parse through the JSON for the tagged Resources
|
101
|
-
# def self.parse_extract(file)
|
102
|
-
# tfstate = parse_tfstate(file)
|
103
|
-
# # InSpec profiles extracted
|
104
|
-
# extracted_profiles = {}
|
105
|
-
|
106
|
-
# # iterate over the resources
|
107
|
-
# tf_resources = tfstate['modules'][0]['resources']
|
108
|
-
# tf_resources.keys.each do |tf_res|
|
109
|
-
# tf_res_id = tf_resources[tf_res]['primary']['id']
|
110
|
-
|
111
|
-
# # get the attributes, see if any of them have a tagged profile attached
|
112
|
-
# tf_resources[tf_res]['primary']['attributes'].keys.each do |attr|
|
113
|
-
# next unless attr.start_with?('tags.' + TAG_NAME)
|
114
|
-
# Inspec::Log.debug "Iggy::Terraform.parse_extract tf_res = #{tf_res} attr = #{attr} MATCHED TAG"
|
115
|
-
# # get the URL and the name of the profiles
|
116
|
-
# name = attr.split(TAG_NAME)[1]
|
117
|
-
# url = tf_resources[tf_res]['primary']['attributes']["tags.#{TAG_URL}#{name}"]
|
118
|
-
# if tf_res.start_with?('aws_vpc') # should this be VPC or subnet?
|
119
|
-
# # if it's a VPC, store it as the VPC id + name
|
120
|
-
# key = tf_res_id + ':' + name
|
121
|
-
# Inspec::Log.debug "Iggy::Terraform.parse_extract aws_vpc tagged with InSpec #{key}"
|
122
|
-
# extracted_profiles[key] = {
|
123
|
-
# 'type' => 'aws_vpc',
|
124
|
-
# 'az' => 'us-west-2',
|
125
|
-
# 'url' => url,
|
126
|
-
# }
|
127
|
-
# elsif tf_res.start_with?('aws_instance')
|
128
|
-
# # if it's a node, get information about the IP and SSH/WinRM
|
129
|
-
# key = tf_res_id + ':' + name
|
130
|
-
# Inspec::Log.debug "Iggy::Terraform.parse_extract aws_instance tagged with InSpec #{key}"
|
131
|
-
# extracted_profiles[key] = {
|
132
|
-
# 'type' => 'aws_instance',
|
133
|
-
# 'public_ip' => tf_resources[tf_res]['primary']['attributes']['public_ip'],
|
134
|
-
# 'key_name' => tf_resources[tf_res]['primary']['attributes']['key_name'],
|
135
|
-
# 'url' => url,
|
136
|
-
# }
|
137
|
-
# else
|
138
|
-
# # should generic AWS just be the default except for instances?
|
139
|
-
# STDERR.puts "ERROR: #{file} #{tf_res_id} has an InSpec-tagged resource but #{tf_res} is currently unsupported."
|
140
|
-
# exit(-1)
|
141
|
-
# end
|
142
|
-
# end
|
143
|
-
# end
|
144
|
-
# Inspec::Log.debug "Iggy::Terraform.parse_extract extracted_profiles = #{extracted_profiles}"
|
145
|
-
# extracted_profiles
|
146
|
-
# end
|
147
|
-
end
|
148
|
-
end
|