inspec-iggy 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,42 @@
|
|
1
|
+
# helpers for working with InSpec-AWS profiles
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module InspecPlugins::Iggy::Platforms
|
6
|
+
class AwsHelper
|
7
|
+
# find the additional parameters
|
8
|
+
AWS_RESOURCE_QUALIFIERS = {
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
# the iterators for the various resource types
|
12
|
+
AWS_RESOURCE_ITERATORS = {
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
AWS_REMOVED_PROPERTIES = {
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
# Terraform boilerplate controls/controls.rb content
|
19
|
+
def self.tf_controls
|
20
|
+
"\n\naws_vpc_id = attribute('aws_vpc_id', default: '', description: 'Optional AWS VPC identifier.')\n\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
# readme content
|
24
|
+
def self.readme
|
25
|
+
end
|
26
|
+
|
27
|
+
# inspec.yml boilerplate content from
|
28
|
+
# inspec/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml
|
29
|
+
def self.inspec_yml
|
30
|
+
yml = {}
|
31
|
+
yml['inspec_version'] = '~> 4'
|
32
|
+
yml['depends'] = [{
|
33
|
+
'name' => 'inspec-aws',
|
34
|
+
'url' => 'https://github.com/inspec/inspec-aws/archive/master.tar.gz'
|
35
|
+
}]
|
36
|
+
yml['supports'] = [{
|
37
|
+
'platform' => 'aws'
|
38
|
+
}]
|
39
|
+
yml
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# helpers for working with InSpec-Azure profiles
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module InspecPlugins::Iggy::Platforms
|
6
|
+
class AzureHelper
|
7
|
+
# find the additional parameters
|
8
|
+
AZURE_RESOURCE_QUALIFIERS = {
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
# the iterators for the various resource types
|
12
|
+
AZURE_RESOURCE_ITERATORS = {
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
AZURE_REMOVED_PROPERTIES = {
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
# readme content
|
19
|
+
def self.readme
|
20
|
+
"\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
# inspec.yml boilerplate content from
|
24
|
+
# inspec/lib/plugins/inspec-init/templates/profiles/azure/inspec.yml
|
25
|
+
def self.inspec_yml
|
26
|
+
yml = {}
|
27
|
+
yml['inspec_version'] = '>= 2.2.7'
|
28
|
+
yml['depends'] = [{
|
29
|
+
'name' => 'inspec-azure',
|
30
|
+
'url' => 'https://github.com/inspec/inspec-azure/archive/master.tar.gz'
|
31
|
+
}]
|
32
|
+
yml['supports'] = [{
|
33
|
+
'platform' => 'azure'
|
34
|
+
}]
|
35
|
+
yml
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# helpers for working with InSpec-GCP profiles
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module InspecPlugins::Iggy::Platforms
|
6
|
+
class GcpHelper
|
7
|
+
# find the additional parameters for the 'describe'
|
8
|
+
GCP_RESOURCE_QUALIFIERS = {
|
9
|
+
'google_bigquery_dataset' => [:project, :name],
|
10
|
+
'google_bigquery_table' => [:project, :dataset, :name],
|
11
|
+
'google_cloudfunctions_cloud_function' => [:project, :location, :name],
|
12
|
+
'google_compute_address' => [:project, :location, :name],
|
13
|
+
'google_compute_autoscaler' => [:project, :zone, :name],
|
14
|
+
'google_compute_backend_bucket' => [:project, :name],
|
15
|
+
'google_compute_backend_service' => [:project, :name],
|
16
|
+
'google_compute_disk' => [:project, :name, :zone],
|
17
|
+
'google_compute_firewall' => [:project, :name],
|
18
|
+
'google_compute_forwarding_rule' => [:project, :region, :name],
|
19
|
+
'google_compute_global_address' => [:project, :name],
|
20
|
+
'google_compute_global_forwarding_rule' => [:project, :name],
|
21
|
+
'google_compute_health_check' => [:project, :name],
|
22
|
+
'google_compute_http_health_check' => [:project, :name],
|
23
|
+
'google_compute_https_health_check' => [:project, :name],
|
24
|
+
'google_compute_image' => [:project, :name],
|
25
|
+
'google_compute_instance' => [:project, :zone, :name],
|
26
|
+
'google_compute_instance_group' => [:project, :zone, :name],
|
27
|
+
'google_compute_instance_group_manager' => [:project, :zone, :name],
|
28
|
+
'google_compute_instance_template' => [:project, :name],
|
29
|
+
'google_compute_network' => [:project, :name],
|
30
|
+
'google_compute_project_info' => [:project],
|
31
|
+
'google_compute_region' => [:project, :name],
|
32
|
+
'google_compute_region_backend_service' => [:project, :region, :name],
|
33
|
+
'google_compute_region_instance_group_manager' => [:project, :region, :name],
|
34
|
+
'google_compute_route' => [:project, :name],
|
35
|
+
'google_compute_router' => [:project, :region, :name],
|
36
|
+
'google_compute_snapshot' => [:project, :name],
|
37
|
+
'google_compute_ssl_certificate' => [:project, :name],
|
38
|
+
'google_compute_ssl_policy' => [:project, :name],
|
39
|
+
'google_compute_subnetwork' => [:project, :region, :name],
|
40
|
+
'google_compute_subnetwork_iam_policy' => [:project, :region, :name],
|
41
|
+
'google_compute_target_http_proxy' => [:project, :name],
|
42
|
+
'google_compute_target_https_proxy' => [:project, :name],
|
43
|
+
'google_compute_target_pool' => [:project, :region, :name],
|
44
|
+
'google_compute_target_tcp_proxy' => [:project, :name],
|
45
|
+
'google_compute_url_map' => [:project, :name],
|
46
|
+
'google_compute_vpn_tunnel' => [:project, :region, :name],
|
47
|
+
'google_compute_zone' => [:project, :zone],
|
48
|
+
'google_container_cluster' => [:project, :zone, :name],
|
49
|
+
'google_container_node_pool' => [:project, :zone, :cluster_name, :nodepool_name],
|
50
|
+
'google_container_regional_cluster' => [:project, :location, :name],
|
51
|
+
'google_container_regional_node_pool' => [:project, :location, :cluster, :name],
|
52
|
+
'google_dns_managed_zone' => [:project, :zone],
|
53
|
+
'google_dns_resource_record_set' => [:project, :name, :type, :managed_zone],
|
54
|
+
'google_kms_crypto_key' => [:project, :location, :key_ring_name, :name],
|
55
|
+
'google_kms_crypto_key_iam_binding' => [:crypto_key_url, :role],
|
56
|
+
'google_kms_key_ring' => [:project, :location, :name],
|
57
|
+
'google_kms_key_ring_iam_binding' => [:key_ring_url, :role],
|
58
|
+
'google_logging_project_exclusion' => [:project, :exclusion],
|
59
|
+
'google_logging_project_sink' => [:project, :sink],
|
60
|
+
'google_organization' => [:display_name],
|
61
|
+
'google_organization_policy' => [:name, :constraints],
|
62
|
+
'google_project' => [:project],
|
63
|
+
'google_project_alert_policy' => [:policy],
|
64
|
+
'google_project_alert_policy_condition' => [:name, :filter],
|
65
|
+
'google_project_iam_binding' => [:project, :role],
|
66
|
+
'google_project_iam_custom_role' => [:project, :name],
|
67
|
+
'google_project_logging_audit_config' => [:project],
|
68
|
+
'google_project_metric' => [:project, :metric],
|
69
|
+
'google_pubsub_subscription' => [:project, :name],
|
70
|
+
'google_pubsub_subscription_iam_policy' => [:project, :name],
|
71
|
+
'google_pubsub_topic' => [:project, :name],
|
72
|
+
'google_pubsub_topic_iam_policy' => [:project, :name],
|
73
|
+
'google_resourcemanager_organization_policy' => [:organization_name, :constraint],
|
74
|
+
'google_service_account' => [:name],
|
75
|
+
'google_service_account_key' => [:name],
|
76
|
+
'google_sourcerepo_repository' => [:project, :name],
|
77
|
+
'google_sql_database_instance' => [:project, :database],
|
78
|
+
'google_storage_bucket' => [:name],
|
79
|
+
'google_storage_bucket_acl' => [:bucket, :entity],
|
80
|
+
'google_storage_bucket_iam_binding' => [:bucket, :role],
|
81
|
+
'google_storage_bucket_object' => [:bucket, :object],
|
82
|
+
'google_storage_default_object_acl' => [:bucket, :entity],
|
83
|
+
'google_storage_object_acl' => [:bucket, :object, :entity],
|
84
|
+
'google_user' => [:user_key]
|
85
|
+
}.freeze
|
86
|
+
|
87
|
+
# the iterators for the various resource types
|
88
|
+
GCP_RESOURCE_ITERATORS = {
|
89
|
+
# 'google_compute_disk' => { 'iterator' => 'google_compute_disks', 'index' => 'names', 'qualifiers' => [:project, :zone] }, # false positives because instance attached disks aren't managed by Terraform
|
90
|
+
# 'google_compute_network' => { 'iterator' => 'google_compute_networks', 'index' => 'network_names', 'qualifiers' => [:project] },
|
91
|
+
# 'google_compute_region' => { 'iterator' => 'google_compute_regions', 'index' => 'region_names', 'qualifiers' => [:project] },
|
92
|
+
# 'google_compute_region_instance_group_manager' => { 'iterator' => 'google_compute_region_instance_group_managers', 'index' => 'instance_group_names', 'qualifiers' => [:project, :region] }, verify it has 2 filter criteria
|
93
|
+
# 'google_compute_route' => { 'iterator' => 'google_compute_routes', 'index' => 'names', 'qualifiers' => [:project] },
|
94
|
+
# 'google_compute_subnetwork' => { 'iterator' => 'google_compute_subnetworks', 'index' => 'subnetwork_names', 'qualifiers' => [:project, :region] },
|
95
|
+
# 'google_compute_zone' => { 'iterator' => 'google_compute_zones', 'index' => 'zone_names', 'qualifiers' => [:project] },
|
96
|
+
# 'google_kms_crypto_key_iam_binding' => { 'iterator' => 'google_kms_crypto_key_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:crypto_key_url] },
|
97
|
+
# 'google_kms_key_ring' => { 'iterator' => 'google_kms_key_rings', 'index' => 'key_ring_names', 'qualifiers' => [:project, :location] },
|
98
|
+
# 'google_kms_key_ring_iam_binding' => { 'iterator' => 'google_kms_key_ring_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:key_ring_url] },
|
99
|
+
# 'google_organization' => { 'iterator' => 'google_organizations', 'index' => 'names', 'qualifiers' => [] }, # organizations are not managed by Terraform
|
100
|
+
# 'google_project' => { 'iterator' => 'google_projects', 'index' => 'project_names', 'qualifiers' => [] }, # projects are not managed by Terraform
|
101
|
+
# 'google_project_iam_binding' => { 'iterator' => 'google_project_iam_bindings', 'index' => 'iam_binding_roles', 'qualifiers' => [:project] },
|
102
|
+
'google_bigquery_dataset' => { 'iterator' => 'google_bigquery_datasets', 'index' => 'names', 'qualifiers' => [:project] },
|
103
|
+
'google_bigquery_table' => { 'iterator' => 'google_bigquery_tables', 'index' => 'table_references', 'qualifiers' => [:project, :dataset] },
|
104
|
+
'google_cloudbuild_trigger' => { 'iterator' => 'google_cloudbuild_triggers', 'index' => 'names', 'qualifiers' => [:project] },
|
105
|
+
'google_cloudfunctions_cloud_function' => { 'iterator' => 'google_cloudfunctions_cloud_functions', 'index' => 'names', 'qualifiers' => [:project, :location] },
|
106
|
+
'google_compute_autoscaler' => { 'iterator' => 'google_compute_autoscalers', 'index' => 'names', 'qualifiers' => [:project, :zone] },
|
107
|
+
'google_compute_backend_bucket' => { 'iterator' => 'google_compute_backend_buckets', 'index' => 'names', 'qualifiers' => [:project] },
|
108
|
+
'google_compute_backend_service' => { 'iterator' => 'google_compute_backend_services', 'index' => 'names', 'qualifiers' => [:project] },
|
109
|
+
'google_compute_firewall' => { 'iterator' => 'google_compute_firewalls', 'index' => 'firewall_names', 'qualifiers' => [:project] },
|
110
|
+
'google_compute_forwarding_rule' => { 'iterator' => 'google_compute_forwarding_rules', 'index' => 'forwarding_rule_names', 'qualifiers' => [:project, :region] },
|
111
|
+
'google_compute_health_check' => { 'iterator' => 'google_compute_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
|
112
|
+
'google_compute_http_health_check' => { 'iterator' => 'google_compute_http_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
|
113
|
+
'google_compute_https_health_check' => { 'iterator' => 'google_compute_https_health_checks', 'index' => 'names', 'qualifiers' => [:project] },
|
114
|
+
'google_compute_instance' => { 'iterator' => 'google_compute_instances', 'index' => 'instance_names', 'qualifiers' => [:project, :zone] },
|
115
|
+
'google_compute_instance_group' => { 'iterator' => 'google_compute_instance_groups', 'index' => 'instance_group_names', 'qualifiers' => [:project, :zone] },
|
116
|
+
'google_compute_instance_group_manager' => { 'iterator' => 'google_compute_instance_group_managers', 'index' => 'base_instance_names', 'qualifiers' => [:project, :zone] },
|
117
|
+
'google_compute_instance_template' => { 'iterator' => 'google_compute_instance_templates', 'index' => 'names', 'qualifiers' => [:project] },
|
118
|
+
'google_compute_router' => { 'iterator' => 'google_compute_routers', 'index' => 'names', 'qualifiers' => [:project, :region] },
|
119
|
+
'google_compute_snapshot' => { 'iterator' => 'google_compute_snapshots', 'index' => 'names', 'qualifiers' => [:project] },
|
120
|
+
'google_compute_ssl_certificate' => { 'iterator' => 'google_compute_ssl_certificates', 'index' => 'names', 'qualifiers' => [:project] },
|
121
|
+
'google_compute_ssl_policy' => { 'iterator' => 'google_compute_ssl_policies', 'index' => 'names', 'qualifiers' => [:project] },
|
122
|
+
'google_compute_target_http_proxy' => { 'iterator' => 'google_compute_target_http_proxies', 'index' => 'names', 'qualifiers' => [:project] },
|
123
|
+
'google_compute_target_https_proxy' => { 'iterator' => 'google_compute_target_https_proxies', 'index' => 'names', 'qualifiers' => [:project] },
|
124
|
+
'google_compute_target_pool' => { 'iterator' => 'google_compute_target_pools', 'index' => 'names', 'qualifiers' => [:project, :region] },
|
125
|
+
'google_compute_target_tcp_proxy' => { 'iterator' => 'google_compute_target_tcp_proxies', 'index' => 'names', 'qualifiers' => [:project] },
|
126
|
+
'google_compute_url_map' => { 'iterator' => 'google_compute_url_maps', 'index' => 'names', 'qualifiers' => [:project] },
|
127
|
+
'google_compute_vpn_tunnel' => { 'iterator' => 'google_compute_vpn_tunnels', 'index' => 'vpn_tunnel_names', 'qualifiers' => [:project, :region] },
|
128
|
+
'google_container_cluster' => { 'iterator' => 'google_container_clusters', 'index' => 'cluster_names', 'qualifiers' => [:project, :zone] },
|
129
|
+
'google_container_node_pool' => { 'iterator' => 'google_container_node_pools', 'index' => 'node_pool_names', 'qualifiers' => [:project, :zone, :cluster_name] },
|
130
|
+
'google_container_regional_cluster' => { 'iterator' => 'google_container_regional_clusters', 'index' => 'names', 'qualifiers' => [:project, :location] },
|
131
|
+
'google_dns_managed_zone' => { 'iterator' => 'google_dns_managed_zones', 'index' => 'zone_names', 'qualifiers' => [:project] },
|
132
|
+
'google_dns_resource_record_set' => { 'iterator' => 'google_dns_resource_record_sets', 'index' => 'names', 'qualifiers' => [:project, :managed_zone] },
|
133
|
+
'google_kms_crypto_key' => { 'iterator' => 'google_kms_crypto_keys', 'index' => 'crypto_key_names', 'qualifiers' => [:project, :location, :key_ring_name] },
|
134
|
+
'google_logging_project_sink' => { 'iterator' => 'google_logging_project_sinks', 'index' => 'sink_names', 'qualifiers' => [:project] },
|
135
|
+
'google_project_alert_policy' => { 'iterator' => 'google_project_alert_policies', 'index' => 'policy_names', 'qualifiers' => [:project] },
|
136
|
+
'google_project_metric' => { 'iterator' => 'google_project_metrics', 'index' => 'metric_names', 'qualifiers' => [:project] },
|
137
|
+
'google_pubsub_subscription' => { 'iterator' => 'google_pubsub_subscriptions', 'index' => 'names', 'qualifiers' => [:project] },
|
138
|
+
}.freeze
|
139
|
+
|
140
|
+
GCP_REMOVED_PROPERTIES = {
|
141
|
+
'google_compute_http_health_check' => [:self_link, :id, :creation_timestamp], # id: terraform has name not id, self_link: undocumented but broken, creation_timestamp api incompatibility
|
142
|
+
'google_compute_instance' => [:label_fingerprint, :machine_type, :min_cpu_platform, :zone], # label_fingerprint, machine_type, zone api incompatibility | min_cpu_platform undefined
|
143
|
+
'google_compute_instance_group' => [:zone], # zone api incompatibility issue
|
144
|
+
'google_compute_forwarding_rule' => [:backend_service, :ip_version, :network, :region, :subnetwork], # :backend_service, :ip_version, :network, :region, :subnetwork api incompatibility
|
145
|
+
'google_compute_target_pool' => [:backup_pool, :failover_ratio, :id, :region, :self_link], # api incompatibility
|
146
|
+
|
147
|
+
}.freeze
|
148
|
+
|
149
|
+
# readme content
|
150
|
+
def self.readme
|
151
|
+
end
|
152
|
+
|
153
|
+
# inspec.yml boilerplate content from
|
154
|
+
# inspec/lib/plugins/inspec-init/templates/profiles/gcp/inspec.yml
|
155
|
+
def self.inspec_yml
|
156
|
+
yml = {}
|
157
|
+
yml['inspec_version'] = '>= 2.3.5'
|
158
|
+
yml['depends'] = [{
|
159
|
+
'name' => 'inspec-gcp',
|
160
|
+
'url' => 'https://github.com/inspec/inspec-gcp/archive/master.tar.gz'
|
161
|
+
}]
|
162
|
+
yml['supports'] = [{
|
163
|
+
'platform' => 'gcp'
|
164
|
+
}]
|
165
|
+
yml
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -1,46 +1,64 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
# renders the profile from the parsed files
|
2
3
|
|
3
4
|
require 'yaml'
|
4
5
|
|
6
|
+
require 'inspec-iggy/platforms/aws_helper'
|
7
|
+
require 'inspec-iggy/platforms/azure_helper'
|
8
|
+
require 'inspec-iggy/platforms/gcp_helper'
|
9
|
+
|
5
10
|
module InspecPlugins
|
6
11
|
module Iggy
|
7
12
|
class ProfileHelper
|
8
13
|
# match the output of 'inspec init profile'
|
9
|
-
|
14
|
+
# inspec/lib/plugins/inspec-init/lib/inspec-init/renderer.rb
|
15
|
+
def self.render_profile(cli, options, source_file, controls, platform = nil)
|
10
16
|
name = options[:name]
|
11
17
|
overwrite_mode = options[:overwrite]
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
|
19
|
+
# --------------------------- InSpec Code Generator ---------------------------
|
20
|
+
cli.headline('InSpec Iggy Code Generator')
|
21
|
+
|
22
|
+
full_destination_path = Pathname.new(Dir.pwd).join(name)
|
23
|
+
|
24
|
+
if File.exist?(full_destination_path) && !overwrite_mode
|
25
|
+
cli.plain_line "#{cli.emphasis(full_destination_path)} exists already, use --overwrite"
|
26
|
+
cli.exit(1)
|
18
27
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
28
|
+
|
29
|
+
# ensure that full_destination_path directory is available
|
30
|
+
FileUtils.mkdir_p(full_destination_path)
|
31
|
+
|
32
|
+
# Creating new profile at /Users/mattray/ws/inspec-iggy/FOO
|
33
|
+
cli.plain_line "Creating new profile at #{cli.emphasis(full_destination_path)}"
|
34
|
+
# * Creating file README.md
|
35
|
+
render_readme_md(cli, name, source_file, platform)
|
36
|
+
# * Creating directory controls
|
37
|
+
cli.list_item "Creating directory #{cli.emphasis('controls')}"
|
23
38
|
FileUtils.mkdir_p("#{name}/controls")
|
24
|
-
|
25
|
-
|
26
|
-
|
39
|
+
# * Creating file controls/generated.rb
|
40
|
+
render_controls_rb(cli, name, controls)
|
41
|
+
# * Creating file inspec.yml
|
42
|
+
render_inspec_yml(cli, name, source_file, options, platform)
|
43
|
+
cli.plain_line
|
27
44
|
end
|
28
45
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
|
33
|
-
f = File.new(render_file, 'w')
|
46
|
+
def self.render_readme_md(cli, name, source_file, platform)
|
47
|
+
cli.list_item "Creating file #{cli.emphasis('README.md')}"
|
48
|
+
f = File.new("#{name}/README.md", 'w')
|
34
49
|
f.puts("# #{name}")
|
35
50
|
f.puts
|
36
51
|
f.puts("This profile was generated by InSpec-Iggy v#{Iggy::VERSION} from the #{source_file} source file.")
|
52
|
+
|
53
|
+
f.puts(InspecPlugins::Iggy::Platforms::AwsHelper.readme) if platform.eql?('aws')
|
54
|
+
f.puts(InspecPlugins::Iggy::Platforms::AzureHelper.readme) if platform.eql?('azure')
|
55
|
+
f.puts(InspecPlugins::Iggy::Platforms::GcpHelper.readme) if platform.eql?('gcp')
|
56
|
+
|
37
57
|
f.close
|
38
58
|
end
|
39
59
|
|
40
|
-
|
41
|
-
|
42
|
-
render_file = "#{name}/inspec.yml"
|
43
|
-
cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
|
60
|
+
def self.render_inspec_yml(cli, name, source_file, options, platform)
|
61
|
+
cli.list_item "Creating file #{cli.emphasis('inspec.yml')}"
|
44
62
|
yml = {}
|
45
63
|
yml['name'] = name
|
46
64
|
yml['title'] = options[:title]
|
@@ -51,16 +69,19 @@ module InspecPlugins
|
|
51
69
|
yml['summary'] = options[:summary]
|
52
70
|
yml['version'] = options[:version]
|
53
71
|
yml['description'] = "Generated by InSpec-Iggy v#{Iggy::VERSION} from the #{source_file} source file."
|
54
|
-
|
72
|
+
|
73
|
+
yml.merge!(InspecPlugins::Iggy::Platforms::AwsHelper.inspec_yml) if platform.eql?('aws')
|
74
|
+
yml.merge!(InspecPlugins::Iggy::Platforms::AzureHelper.inspec_yml) if platform.eql?('azure')
|
75
|
+
yml.merge!(InspecPlugins::Iggy::Platforms::GcpHelper.inspec_yml) if platform.eql?('gcp')
|
76
|
+
|
77
|
+
f = File.new("#{name}/inspec.yml", 'w')
|
55
78
|
f.write(yml.to_yaml)
|
56
79
|
f.close
|
57
80
|
end
|
58
81
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
cli_ui.li "Create file #{cli_ui.mark_text(render_file)}"
|
63
|
-
f = File.new(render_file, 'w')
|
82
|
+
def self.render_controls_rb(cli, name, controls)
|
83
|
+
cli.list_item "Creating file #{cli.emphasis('controls/generated.rb')}"
|
84
|
+
f = File.new("#{name}/controls/generated.rb", 'w')
|
64
85
|
f.write(controls)
|
65
86
|
f.close
|
66
87
|
end
|
@@ -4,7 +4,8 @@ require 'inspec/plugin/v2'
|
|
4
4
|
|
5
5
|
require 'inspec-iggy/version'
|
6
6
|
require 'inspec-iggy/profile_helper'
|
7
|
-
require 'inspec-iggy/terraform/
|
7
|
+
require 'inspec-iggy/terraform/generate'
|
8
|
+
require 'inspec-iggy/terraform/negative'
|
8
9
|
|
9
10
|
module InspecPlugins::Iggy
|
10
11
|
module Terraform
|
@@ -20,71 +21,95 @@ module InspecPlugins::Iggy
|
|
20
21
|
say("Iggy v#{InspecPlugins::Iggy::VERSION}")
|
21
22
|
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
class_option :debug,
|
25
|
+
desc: 'Verbose debugging messages',
|
26
|
+
type: :boolean,
|
27
|
+
default: false
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
class_option :copyright,
|
30
|
+
desc: 'Name of the copyright holder',
|
31
|
+
default: 'The Authors'
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
class_option :email,
|
34
|
+
desc: 'Email address of the author',
|
35
|
+
default: 'you@example.com'
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
class_option :license,
|
38
|
+
desc: 'License for the profile',
|
39
|
+
default: 'Apache-2.0'
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
class_option :maintainer,
|
42
|
+
desc: 'Name of the copyright holder',
|
43
|
+
default: 'The Authors'
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
class_option :summary,
|
46
|
+
desc: 'One line summary for the profile',
|
47
|
+
default: 'An InSpec Compliance Profile'
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
class_option :title,
|
50
|
+
desc: 'Human-readable name for the profile',
|
51
|
+
default: 'InSpec Profile'
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
class_option :version,
|
54
|
+
desc: 'Specify the profile version',
|
55
|
+
default: '0.1.0'
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
class_option :overwrite,
|
58
|
+
desc: 'Overwrites existing profile directory',
|
59
|
+
type: :boolean,
|
60
|
+
default: false
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
62
|
+
class_option :name,
|
63
|
+
aliases: '-n',
|
64
|
+
required: true,
|
65
|
+
desc: 'Name of profile to be generated'
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
class_option :tfstate,
|
68
|
+
aliases: '-t',
|
69
|
+
desc: 'Specify path to the input terraform.tfstate',
|
70
|
+
default: 'terraform.tfstate'
|
71
|
+
|
72
|
+
class_option :platform,
|
73
|
+
desc: 'The InSpec platform providing the necessary resources (aws, azure, or gcp)'
|
74
|
+
|
75
|
+
class_option :resourcepath,
|
76
|
+
desc: 'Specify path to the InSpec Resource Pack providing the necessary resources'
|
70
77
|
|
71
78
|
desc 'generate [options]', 'Generate InSpec compliance controls from terraform.tfstate'
|
72
79
|
def generate
|
73
80
|
Inspec::Log.level = :debug if options[:debug]
|
74
|
-
|
75
|
-
|
76
|
-
|
81
|
+
platform = options[:platform]
|
82
|
+
resource_path = options[:resourcepath]
|
83
|
+
# require validation that if platform or resourcepath are passed, both are available
|
84
|
+
if platform or resource_path
|
85
|
+
unless platform and resource_path
|
86
|
+
error 'You must pass both --platform and --resourcepath if using either'
|
87
|
+
exit(1)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
generated_controls = InspecPlugins::Iggy::Terraform::Generate.parse_generate(options[:tfstate], resource_path, platform)
|
91
|
+
printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], generated_controls, platform)
|
92
|
+
InspecPlugins::Iggy::ProfileHelper.render_profile(ui, options, options[:tfstate], printable_controls, platform)
|
77
93
|
exit 0
|
78
94
|
end
|
79
95
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
96
|
+
desc 'negative [options]', 'Generate negative InSpec compliance controls from terraform.tfstate'
|
97
|
+
def negative
|
98
|
+
Inspec::Log.level = :debug if options[:debug]
|
99
|
+
platform = options[:platform]
|
100
|
+
resource_path = options[:resourcepath]
|
101
|
+
# require validation that if platform or resourcepath are passed, both are available
|
102
|
+
if platform or resource_path
|
103
|
+
unless platform and resource_path
|
104
|
+
error 'You must pass both --platform and --resourcepath if using either'
|
105
|
+
exit(1)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
negative_controls = InspecPlugins::Iggy::Terraform::Negative.parse_negative(options[:tfstate], resource_path, platform)
|
109
|
+
printable_controls = InspecPlugins::Iggy::InspecHelper.tf_controls(options[:title], negative_controls, platform)
|
110
|
+
InspecPlugins::Iggy::ProfileHelper.render_profile(ui, options, options[:tfstate], printable_controls, platform)
|
111
|
+
exit 0
|
112
|
+
end
|
88
113
|
end
|
89
114
|
end
|
90
115
|
end
|