inspec-iggy 0.2.0 → 0.4.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.
@@ -4,8 +4,8 @@
4
4
  #
5
5
  # Copyright:: 2018, Chef Software, Inc <legal@chef.io>
6
6
  #
7
-
8
- # Iggy version
9
- module Iggy
10
- VERSION = "0.2.0".freeze
7
+ module InspecPlugins
8
+ module Iggy
9
+ VERSION = '0.4.0'.freeze
10
+ end
11
11
  end
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.2.0
4
+ version: 0.4.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: 2018-05-22 00:00:00.000000000 Z
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inspec
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '2.3'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 3.0.0
22
+ version: 4.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '2.0'
29
+ version: '2.3'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 3.0.0
32
+ version: 4.0.0
33
33
  description: Generate InSpec compliance profiles from Terraform by tagging instances
34
34
  and mapping Terraform to InSpec.
35
35
  email:
@@ -42,17 +42,14 @@ files:
42
42
  - README.md
43
43
  - inspec-iggy.gemspec
44
44
  - lib/inspec-iggy.rb
45
- - lib/inspec-iggy/cli.rb
46
- - lib/inspec-iggy/cloudformation.rb
45
+ - lib/inspec-iggy/cloudformation/cli_command.rb
46
+ - lib/inspec-iggy/cloudformation/parser.rb
47
47
  - lib/inspec-iggy/inspec_helper.rb
48
- - lib/inspec-iggy/terraform.rb
48
+ - lib/inspec-iggy/plugin.rb
49
+ - lib/inspec-iggy/profile.rb
50
+ - lib/inspec-iggy/terraform/cli_command.rb
51
+ - lib/inspec-iggy/terraform/parser.rb
49
52
  - lib/inspec-iggy/version.rb
50
- - test/bad.json
51
- - test/bjc-demo-aws-4.5.4.json
52
- - test/main.tf
53
- - test/outputs.tf
54
- - test/terraform.tfstate
55
- - test/variables.tf
56
53
  homepage: https://github.com/inspec/inspec-iggy
57
54
  licenses:
58
55
  - Apache-2.0
@@ -73,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
70
  version: '0'
74
71
  requirements: []
75
72
  rubyforge_project:
76
- rubygems_version: 2.6.14.1
73
+ rubygems_version: 2.6.13
77
74
  signing_key:
78
75
  specification_version: 4
79
76
  summary: InSpec plugin to generate InSpec compliance profiles from Terraform.
@@ -1,53 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # Author:: Matt Ray (<matt@chef.io>)
4
- #
5
- # Copyright:: 2018, Chef Software, Inc <legal@chef.io>
6
- #
7
-
8
- require "inspec/plugins"
9
- require "thor"
10
-
11
- require "inspec-iggy/terraform"
12
-
13
- module Iggy
14
- class CLI < Thor
15
- namespace "terraform"
16
-
17
- map %w{-v --version} => "version"
18
-
19
- desc "version", "Display version information", hide: true
20
- def version
21
- say("Iggy v#{Iggy::VERSION}")
22
- end
23
-
24
- class_option :tfstate,
25
- :aliases => "-t",
26
- :desc => "Specify path to the input terraform.tfstate",
27
- :default => "terraform.tfstate"
28
-
29
- class_option :debug,
30
- :desc => "Verbose debugging messages",
31
- :type => :boolean,
32
- :default => false
33
-
34
- desc "generate [options]", "Generate InSpec compliance controls from terraform.tfstate"
35
- def generate
36
- Inspec::Log.level = :debug if options[:debug]
37
- generated_controls = Iggy::Terraform.parse_generate(options[:tfstate])
38
- # let's just generate a control file with a set of controls for now
39
- Iggy::InspecHelper.print_controls(options[:tfstate], generated_controls)
40
- exit 0
41
- end
42
-
43
- desc "extract [options]", "Extract tagged InSpec profiles from terraform.tfstate"
44
- def extract
45
- Inspec::Log.level = :debug if options[:debug]
46
- extracted_profiles = Iggy::Terraform.parse_extract(options[:tfstate])
47
- Iggy::InspecHelper.print_commands(extracted_profiles)
48
- exit 0
49
- end
50
- end
51
-
52
- Inspec::Plugins::CLI.add_subcommand(CLI, "terraform", "terraform SUBCOMMAND ...", "Extract or generate InSpec from Terraform", {})
53
- end
@@ -1,104 +0,0 @@
1
- #
2
- # Author:: Matt Ray (<matt@chef.io>)
3
- #
4
- # Copyright:: 2018, Chef Software, Inc <legal@chef.io>
5
- #
6
-
7
- require "iggy"
8
-
9
- require "json"
10
- require "thor"
11
-
12
- module Iggy
13
- class CloudFormation < Thor
14
- option :template,
15
- :aliases => "-t",
16
- :desc => "Specify path to the input CloudFormation template"
17
-
18
- option :debug,
19
- :desc => "Verbose debugging messages",
20
- :type => :boolean,
21
- :default => false
22
-
23
- desc "generate [options]", "Generate InSpec compliance controls from CloudFormation template"
24
- long_desc <<-LONGDESC
25
- Reads in a CloudFormation JSON file and generates matching InSpec compliance controls.
26
- LONGDESC
27
- def generate
28
- Iggy::Log.level = :debug if options[:debug]
29
- Iggy::Log.debug "CloudFormation.generate file = #{options[:template]}"
30
- # hash of generated controls
31
- generated_controls = parse_generate(options[:template])
32
- Iggy::Log.debug "CloudFormation.generate generated_controls = #{generated_controls}"
33
- # let's just generate a control file with a set of controls for now
34
- Iggy::Inspec.print_controls(options[:template], generated_controls)
35
- exit 0
36
- end
37
-
38
- private
39
-
40
- def parse_generate(file)
41
- Iggy::Log.debug "CloudFormation.parse_generate file = #{file}"
42
- begin
43
- unless File.file?(file)
44
- STDERR.puts "ERROR: #{file} is an invalid file, please check your path."
45
- exit(-1)
46
- end
47
- template = JSON.parse(File.read(file))
48
- rescue JSON::ParserError => e
49
- STDERR.puts e.message
50
- STDERR.puts "ERROR: Parsing error in #{file}."
51
- exit(-1)
52
- end
53
- basename = File.basename(file)
54
- absolutename = File.absolute_path(file)
55
-
56
- # InSpec controls generated
57
- generated_controls = {}
58
-
59
- # iterate over the resources
60
- cfn_resources = template["Resources"]
61
- # iterate over the Resources, use these as IDs?
62
- cfn_resources.keys.each do |cfn_res|
63
- # split out the last ::, these are all AWS
64
- cfn_res_type = "aws_" + cfn_resources[cfn_res]["Type"].split("::").last.downcase
65
-
66
- # does this match an InSpec resource?
67
- if Inspec::RESOURCES.include?(cfn_res_type)
68
- Iggy::Log.debug "CloudFormation.parse_generate cfn_res_type = #{cfn_res_type} MATCH"
69
- # insert new control based off the resource's ID
70
- generated_controls[cfn_res] = {}
71
- generated_controls[cfn_res]["name"] = "#{cfn_res_type}::#{cfn_res}"
72
- generated_controls[cfn_res]["title"] = "Iggy #{basename} #{cfn_res_type}::#{cfn_res}"
73
- generated_controls[cfn_res]["desc"] = "#{cfn_res_type}::#{cfn_res} from the source file #{absolutename}\nGenerated by Iggy v#{Iggy::VERSION}"
74
- generated_controls[cfn_res]["impact"] = "1.0"
75
- generated_controls[cfn_res]["resource"] = cfn_res_type
76
- generated_controls[cfn_res]["parameter"] = cfn_res
77
- generated_controls[cfn_res]["tests"] = []
78
- generated_controls[cfn_res]["tests"][0] = "it { should exist }"
79
-
80
- # if there's a match, see if there are matching InSpec properties
81
- inspec_properties = Iggy::Inspec.resource_properties(cfn_res_type)
82
-
83
- cfn_resources[cfn_res]["Properties"].keys.each do |attr|
84
- # insert '_' on the CamelCase to get camel_case
85
- attr_split = attr.split /(?=[A-Z])/
86
- property = attr_split.join("_").downcase
87
- if inspec_properties.member?(property)
88
- Iggy::Log.debug "CloudFormation.parse_generate #{cfn_res_type} inspec_property = #{property} MATCH"
89
- value = cfn_resources[cfn_res]["Properties"][attr]
90
- # skip the {"Ref"=>"VPC"} for now
91
- generated_controls[cfn_res]["tests"].push("its('#{property}') { should cmp '#{value}' }") unless value.is_a? Hash
92
- else
93
- Iggy::Log.debug "CloudFormation.parse_generate #{cfn_res_type} inspec_property = #{property} SKIP"
94
- end
95
- end
96
- else
97
- Iggy::Log.debug "CloudFormation.parse_generate cfn_res_type = #{cfn_res_type} SKIP"
98
- end
99
- end
100
- generated_controls
101
- end
102
-
103
- end
104
- end
@@ -1,146 +0,0 @@
1
- #
2
- # Author:: Matt Ray (<matt@chef.io>)
3
- #
4
- # Copyright:: 2018, Chef Software, Inc <legal@chef.io>
5
- #
6
-
7
- require "inspec/objects/control"
8
- require "inspec/objects/ruby_helper"
9
- require "inspec/objects/describe"
10
-
11
- require "inspec-iggy/inspec_helper"
12
-
13
- module Iggy
14
- class Terraform
15
-
16
- # makes it easier to change out later
17
- TAG_NAME = "iggy_name_"
18
- TAG_URL = "iggy_url_"
19
-
20
- # boilerplate tfstate parsing
21
- def self.parse_tfstate(file)
22
- Inspec::Log.debug "Iggy::Terraform.parse_tfstate file = #{file}"
23
- begin
24
- unless File.file?(file)
25
- STDERR.puts "ERROR: #{file} is an invalid file, please check your path."
26
- exit(-1)
27
- end
28
- tfstate = JSON.parse(File.read(file))
29
- rescue JSON::ParserError => e
30
- STDERR.puts e.message
31
- STDERR.puts "ERROR: Parsing error in #{file}."
32
- exit(-1)
33
- end
34
- end
35
-
36
- # parse through the JSON for the tagged Resources
37
- def self.parse_extract(file)
38
- tfstate = parse_tfstate(file)
39
- # InSpec profiles extracted
40
- extracted_profiles = {}
41
-
42
- # iterate over the resources
43
- tf_resources = tfstate["modules"][0]["resources"]
44
- tf_resources.keys.each do |tf_res|
45
- tf_res_id = tf_resources[tf_res]["primary"]["id"]
46
-
47
- # get the attributes, see if any of them have a tagged profile attached
48
- tf_resources[tf_res]["primary"]["attributes"].keys.each do |attr|
49
- next unless attr.start_with?("tags." + TAG_NAME)
50
- Inspec::Log.debug "Iggy::Terraform.parse_extract tf_res = #{tf_res} attr = #{attr} MATCHED TAG"
51
- # get the URL and the name of the profiles
52
- name = attr.split(TAG_NAME)[1]
53
- url = tf_resources[tf_res]["primary"]["attributes"]["tags.#{TAG_URL}#{name}"]
54
- if tf_res.start_with?("aws_vpc") # should this be VPC or subnet?
55
- # if it's a VPC, store it as the VPC id + name
56
- key = tf_res_id + ":" + name
57
- Inspec::Log.debug "Iggy::Terraform.parse_extract aws_vpc tagged with InSpec #{key}"
58
- extracted_profiles[key] = {
59
- "type" => "aws_vpc",
60
- "az" => "us-west-2",
61
- "url" => url,
62
- }
63
- elsif tf_res.start_with?("aws_instance")
64
- # if it's a node, get information about the IP and SSH/WinRM
65
- key = tf_res_id + ":" + name
66
- Inspec::Log.debug "Iggy::Terraform.parse_extract aws_instance tagged with InSpec #{key}"
67
- extracted_profiles[key] = {
68
- "type" => "aws_instance",
69
- "public_ip" => tf_resources[tf_res]["primary"]["attributes"]["public_ip"],
70
- "key_name" => tf_resources[tf_res]["primary"]["attributes"]["key_name"],
71
- "url" => url,
72
- }
73
- else
74
- # should generic AWS just be the default except for instances?
75
- STDERR.puts "ERROR: #{file} #{tf_res_id} has an InSpec-tagged resource but #{tf_res} is currently unsupported."
76
- exit(-1)
77
- end
78
- end
79
- end
80
- Inspec::Log.debug "Iggy::Terraform.parse_extract extracted_profiles = #{extracted_profiles}"
81
- extracted_profiles
82
- end
83
-
84
- # parse through the JSON and generate InSpec controls
85
- def self.parse_generate(file)
86
- tfstate = parse_tfstate(file)
87
- basename = File.basename(file)
88
- absolutename = File.absolute_path(file)
89
-
90
- # InSpec controls generated
91
- generated_controls = []
92
-
93
- # iterate over the resources
94
- tf_resources = tfstate["modules"][0]["resources"]
95
- tf_resources.keys.each do |tf_res|
96
- tf_res_type = tf_resources[tf_res]["type"]
97
-
98
- # add translation layer
99
- if InspecHelper::TERRAFORM_RESOURCES.keys.include?(tf_res_type)
100
- Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} #{InspecHelper::TERRAFORM_RESOURCES[tf_res_type]} TRANSLATED"
101
- tf_res_type = InspecHelper::TERRAFORM_RESOURCES[tf_res_type]
102
- end
103
-
104
- # does this match an InSpec resource?
105
- if InspecHelper::RESOURCES.include?(tf_res_type)
106
- Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} MATCH"
107
- tf_res_id = tf_resources[tf_res]["primary"]["id"]
108
-
109
- # insert new control based off the resource's ID
110
- ctrl = Inspec::Control.new
111
- ctrl.id = "#{tf_res_type}::#{tf_res_id}"
112
- ctrl.title = "Iggy #{basename} #{tf_res_type}::#{tf_res_id}"
113
- ctrl.desc = "#{tf_res_type}::#{tf_res_id} from the source file #{absolutename}\nGenerated by Iggy v#{Iggy::VERSION}"
114
- ctrl.impact = "1.0"
115
-
116
- describe = Inspec::Describe.new
117
- # describes the resourde with the id as argument
118
- describe.qualifier.push([tf_res_type, tf_res_id])
119
-
120
- # ensure the resource exists
121
- describe.add_test(nil, "exist", nil)
122
-
123
- # if there's a match, see if there are matching InSpec properties
124
- inspec_properties = Iggy::InspecHelper.resource_properties(tf_res_type)
125
- tf_resources[tf_res]["primary"]["attributes"].keys.each do |attr|
126
- if inspec_properties.member?(attr)
127
- Inspec::Log.debug "Iggy::Terraform.parse_generate #{tf_res_type} inspec_property = #{attr} MATCH"
128
- value = tf_resources[tf_res]["primary"]["attributes"][attr]
129
- describe.add_test(attr, "cmp", value)
130
- else
131
- Inspec::Log.debug "Iggy::Terraform.parse_generate #{tf_res_type} inspec_property = #{attr} SKIP"
132
- end
133
- end
134
-
135
- ctrl.add_test(describe)
136
- generated_controls.push(ctrl)
137
- else
138
- Inspec::Log.debug "Iggy::Terraform.parse_generate tf_res_type = #{tf_res_type} SKIP"
139
- end
140
- end
141
- Inspec::Log.debug "Iggy::Terraform.parse_generate generated_controls = #{generated_controls}"
142
- generated_controls
143
- end
144
-
145
- end
146
- end
@@ -1,6 +0,0 @@
1
- {
2
- this
3
- file
4
- is
5
- junk
6
- }
@@ -1,851 +0,0 @@
1
-
2
- {
3
- "AWSTemplateFormatVersion": "2010-09-09",
4
- "Description": "BJC Chef Demo (4.5.4)",
5
- "Parameters": {
6
- "AvailabilityZone": {
7
- "Description": "Availability Zone",
8
- "Type": "String",
9
- "Default": "us-west-2c"
10
- },
11
- "DemoName": {
12
- "Description": "Name of the customer or organization",
13
- "Type": "String",
14
- "Default": "bjc-demo"
15
- },
16
- "Version": {
17
- "Description": "Version",
18
- "Type": "String",
19
- "Default": "4.5.4"
20
- },
21
- "KeyName": {
22
- "Description": "Name of an existing ec2 KeyPair to enable SSH access",
23
- "Type": "AWS::EC2::KeyPair::KeyName",
24
- "ConstraintDescription": "must be the name of an existing EC2 KeyPair."
25
- },
26
- "SSHLocation": {
27
- "Description": "The IP address range that can be used to SSH to the EC2 instances",
28
- "Type": "String",
29
- "MinLength": "9",
30
- "MaxLength": "18",
31
- "Default": "0.0.0.0/0",
32
- "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
33
- "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x."
34
- },
35
- "TTL": {
36
- "Description": "Time in hours for the demo to stay active. Default is 4, maximum is 720 hours (30 days).",
37
- "Type": "Number",
38
- "Default": 8,
39
- "MinValue": 0,
40
- "MaxValue": 720
41
- },
42
- "ChefServerAMI": {
43
- "Type": "String",
44
- "Default": "ami-3e6f1a46",
45
- "Description": "AMI ID for the Chef Server"
46
- },
47
- "BuildNode1AMI": {
48
- "Type": "String",
49
- "Default": "ami-cb6f1ab3",
50
- "Description": "AMI ID for Build Node 1"
51
- },
52
- "BuildNode2AMI": {
53
- "Type": "String",
54
- "Default": "ami-3c6d1844",
55
- "Description": "AMI ID for Build Node 2"
56
- },
57
- "BuildNode3AMI": {
58
- "Type": "String",
59
- "Default": "ami-4b6f1a33",
60
- "Description": "AMI ID for Build Node 3"
61
- },
62
- "deliveredAMI": {
63
- "Type": "String",
64
- "Default": "ami-676f1a1f",
65
- "Description": "AMI ID for delivered"
66
- },
67
- "ecomacceptanceAMI": {
68
- "Type": "String",
69
- "Default": "ami-de6c19a6",
70
- "Description": "AMI ID for ecomacceptance"
71
- },
72
- "rehearsalAMI": {
73
- "Type": "String",
74
- "Default": "ami-846c19fc",
75
- "Description": "AMI ID for rehearsal"
76
- },
77
- "unionAMI": {
78
- "Type": "String",
79
- "Default": "ami-1f621767",
80
- "Description": "AMI ID for union"
81
- },
82
- "WindowsWorkstation1AMI": {
83
- "Type": "String",
84
- "Default": "ami-ba6e1bc2",
85
- "Description": "AMI ID for the Windows Workstation"
86
- },
87
- "AutomateAMI": {
88
- "Type": "String",
89
- "Default": "ami-7d6c1905",
90
- "Description": "AMI ID for the Automate Server"
91
- }
92
- },
93
- "Resources": {
94
- "InstanceProfile" : {
95
- "Type" : "AWS::IAM::InstanceProfile",
96
- "Properties" : {
97
- "Path" : "/",
98
- "Roles" : ["chefDemo"]
99
- }
100
- },
101
- "VPC": {
102
- "Type": "AWS::EC2::VPC",
103
- "Properties": {
104
- "CidrBlock": "172.31.0.0/16",
105
- "EnableDnsSupport": "true",
106
- "EnableDnsHostnames": "true",
107
- "Tags": [
108
- {
109
- "Key": "Application",
110
- "Value": {
111
- "Ref": "AWS::StackId"
112
- },
113
- "Key": "Name",
114
- "Value": {
115
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "VPC" ] ]
116
- }
117
- }
118
- ]
119
- }
120
- },
121
- "SubnetAutomate": {
122
- "Type": "AWS::EC2::Subnet",
123
- "Properties": {
124
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
125
- "VpcId": {
126
- "Ref": "VPC"
127
- },
128
- "CidrBlock": "172.31.54.0/24",
129
- "Tags": [
130
- {
131
- "Key": "Application",
132
- "Value": {
133
- "Ref": "AWS::StackId"
134
- },
135
- "Key": "Name",
136
- "Value": {
137
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Automate Subnet" ] ]
138
- }
139
- }
140
- ]
141
- }
142
- },
143
- "SubnetProd": {
144
- "Type": "AWS::EC2::Subnet",
145
- "Properties": {
146
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
147
- "VpcId": {
148
- "Ref": "VPC"
149
- },
150
- "CidrBlock": "172.31.62.0/24",
151
- "Tags": [
152
- {
153
- "Key": "Application",
154
- "Value": {
155
- "Ref": "AWS::StackId"
156
- },
157
- "Key": "Name",
158
- "Value": {
159
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Prod Subnet" ] ]
160
- }
161
- }
162
- ]
163
- }
164
- },
165
- "SubnetWorkstations": {
166
- "Type": "AWS::EC2::Subnet",
167
- "Properties": {
168
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
169
- "VpcId": {
170
- "Ref": "VPC"
171
- },
172
- "CidrBlock": "172.31.10.0/24",
173
- "Tags": [
174
- {
175
- "Key": "Application",
176
- "Value": {
177
- "Ref": "AWS::StackId"
178
- },
179
- "Key": "Name",
180
- "Value": {
181
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Workstations Subnet" ] ]
182
- }
183
- }
184
- ]
185
- }
186
- },
187
- "InternetGateway": {
188
- "Type": "AWS::EC2::InternetGateway",
189
- "Properties": {
190
- "Tags": [
191
- {
192
- "Key": "Application",
193
- "Value": {
194
- "Ref": "AWS::StackId"
195
- },
196
- "Key": "Name",
197
- "Value": {
198
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, " IG" ] ]
199
- }
200
- }
201
- ]
202
- }
203
- },
204
- "AttachGateway": {
205
- "Type": "AWS::EC2::VPCGatewayAttachment",
206
- "Properties": {
207
- "VpcId": {
208
- "Ref": "VPC"
209
- },
210
- "InternetGatewayId": {
211
- "Ref": "InternetGateway"
212
- }
213
- }
214
- },
215
- "RouteTable": {
216
- "Type": "AWS::EC2::RouteTable",
217
- "Properties": {
218
- "VpcId": {
219
- "Ref": "VPC"
220
- },
221
- "Tags": [
222
- {
223
- "Key": "Application",
224
- "Value": {
225
- "Ref": "AWS::StackId"
226
- },
227
- "Key": "Name",
228
- "Value": {
229
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Demo RouteTable" ] ]
230
- }
231
- }
232
- ]
233
- }
234
- },
235
- "Route": {
236
- "Type": "AWS::EC2::Route",
237
- "DependsOn": "AttachGateway",
238
- "Properties": {
239
- "RouteTableId": {
240
- "Ref": "RouteTable"
241
- },
242
- "DestinationCidrBlock": "0.0.0.0/0",
243
- "GatewayId": {
244
- "Ref": "InternetGateway"
245
- }
246
- }
247
- },
248
- "SubnetRouteTableAssociationAutomate": {
249
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
250
- "Properties": {
251
- "SubnetId": {
252
- "Ref": "SubnetAutomate"
253
- },
254
- "RouteTableId": {
255
- "Ref": "RouteTable"
256
- }
257
- }
258
- },
259
- "SubnetRouteTableAssociationProd": {
260
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
261
- "Properties": {
262
- "SubnetId": {
263
- "Ref": "SubnetProd"
264
- },
265
- "RouteTableId": {
266
- "Ref": "RouteTable"
267
- }
268
- }
269
- },
270
- "SubnetRouteTableAssociationWorkstations": {
271
- "Type": "AWS::EC2::SubnetRouteTableAssociation",
272
- "Properties": {
273
- "SubnetId": {
274
- "Ref": "SubnetWorkstations"
275
- },
276
- "RouteTableId": {
277
- "Ref": "RouteTable"
278
- }
279
- }
280
- },
281
- "NetworkAcl": {
282
- "Type": "AWS::EC2::NetworkAcl",
283
- "Properties": {
284
- "VpcId": {
285
- "Ref": "VPC"
286
- },
287
- "Tags": [
288
- {
289
- "Key": "Application",
290
- "Value": {
291
- "Ref": "AWS::StackId"
292
- },
293
- "Key": "Name",
294
- "Value": {
295
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "NetworkAcl" ] ]
296
- }
297
- }
298
- ]
299
- }
300
- },
301
- "InboundNetworkAclEntry": {
302
- "Type": "AWS::EC2::NetworkAclEntry",
303
- "Properties": {
304
- "NetworkAclId": {
305
- "Ref": "NetworkAcl"
306
- },
307
- "RuleNumber": "100",
308
- "Protocol": "-1",
309
- "RuleAction": "allow",
310
- "Egress": "false",
311
- "CidrBlock": "0.0.0.0/0"
312
- }
313
- },
314
- "OutBoundNetworkAclEntry": {
315
- "Type": "AWS::EC2::NetworkAclEntry",
316
- "Properties": {
317
- "NetworkAclId": {
318
- "Ref": "NetworkAcl"
319
- },
320
- "RuleNumber": "100",
321
- "Protocol": "-1",
322
- "RuleAction": "allow",
323
- "Egress": "true",
324
- "CidrBlock": "0.0.0.0/0"
325
- }
326
- },
327
- "SubnetNetworkAclAssociationAutomate": {
328
- "Type": "AWS::EC2::SubnetNetworkAclAssociation",
329
- "Properties": {
330
- "SubnetId": {
331
- "Ref": "SubnetAutomate"
332
- },
333
- "NetworkAclId": {
334
- "Ref": "NetworkAcl"
335
- }
336
- }
337
- },
338
- "SubnetNetworkAclAssociationProd": {
339
- "Type": "AWS::EC2::SubnetNetworkAclAssociation",
340
- "Properties": {
341
- "SubnetId": {
342
- "Ref": "SubnetProd"
343
- },
344
- "NetworkAclId": {
345
- "Ref": "NetworkAcl"
346
- }
347
- }
348
- },
349
- "SubnetNetworkAclAssociationPOCWorkstations": {
350
- "Type": "AWS::EC2::SubnetNetworkAclAssociation",
351
- "Properties": {
352
- "SubnetId": {
353
- "Ref": "SubnetWorkstations"
354
- },
355
- "NetworkAclId": {
356
- "Ref": "NetworkAcl"
357
- }
358
- }
359
- },
360
- "WindowsWorkstation1": {
361
- "Type": "AWS::EC2::Instance",
362
- "Properties": {
363
- "InstanceType": "c4.large",
364
- "EbsOptimized" : "true",
365
- "IamInstanceProfile" : {"Ref" : "InstanceProfile"},
366
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
367
- "NetworkInterfaces": [
368
- {
369
- "GroupSet": [
370
- {
371
- "Ref": "DemoSecurityGroup"
372
- }
373
- ],
374
- "AssociatePublicIpAddress": "true",
375
- "PrivateIpAddress": "172.31.54.201",
376
- "DeviceIndex": "0",
377
- "DeleteOnTermination": "true",
378
- "SubnetId": {
379
- "Ref": "SubnetAutomate"
380
- }
381
- }
382
- ],
383
- "KeyName": {
384
- "Ref": "KeyName"
385
- },
386
- "UserData" : {
387
- "Fn::Base64" : {
388
- "Fn::Join" : [
389
- "",
390
- ["<powershell>\n",
391
- "set-executionpolicy -executionpolicy unrestricted -force -scope LocalMachine",
392
- "</powershell>"
393
- ]
394
- ]
395
- }
396
- },
397
- "ImageId": {
398
- "Ref": "WindowsWorkstation1AMI"
399
- },
400
- "Tags": [
401
- {
402
- "Key": "Name",
403
- "Value": {
404
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Workstation" ] ]
405
- }
406
- }
407
- ]
408
- }
409
- },
410
- "BuildNode1": {
411
- "Type": "AWS::EC2::Instance",
412
- "Properties": {
413
- "InstanceType": "m4.large",
414
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
415
- "NetworkInterfaces": [
416
- {
417
- "GroupSet": [
418
- {
419
- "Ref": "DemoSecurityGroup"
420
- }
421
- ],
422
- "AssociatePublicIpAddress": "true",
423
- "PrivateIpAddress": "172.31.54.51",
424
- "DeviceIndex": "0",
425
- "DeleteOnTermination": "true",
426
- "SubnetId": {
427
- "Ref": "SubnetAutomate"
428
- }
429
- }
430
- ],
431
- "KeyName": { "Ref": "KeyName" },
432
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
433
- "#!/bin/bash -xe\n",
434
- "hostnamectl set-hostname build-node-1\n",
435
- "sleep 90\n",
436
- "sudo chef-client\n"]]}
437
- },
438
- "ImageId": {
439
- "Ref": "BuildNode1AMI"
440
- },
441
- "Tags": [
442
- {
443
- "Key": "Name",
444
- "Value": {
445
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Build Node 1" ] ]
446
- }
447
- }
448
- ]
449
- }
450
- },
451
- "BuildNode2": {
452
- "Type": "AWS::EC2::Instance",
453
- "Properties": {
454
- "InstanceType": "m4.large",
455
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
456
- "NetworkInterfaces": [
457
- {
458
- "GroupSet": [
459
- {
460
- "Ref": "DemoSecurityGroup"
461
- }
462
- ],
463
- "AssociatePublicIpAddress": "true",
464
- "PrivateIpAddress": "172.31.54.52",
465
- "DeviceIndex": "0",
466
- "DeleteOnTermination": "true",
467
- "SubnetId": {
468
- "Ref": "SubnetAutomate"
469
- }
470
- }
471
- ],
472
- "KeyName": { "Ref": "KeyName" },
473
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
474
- "#!/bin/bash -xe\n",
475
- "hostnamectl set-hostname build-node-2\n",
476
- "sleep 90\n",
477
- "sudo chef-client\n"]]}
478
- },
479
- "ImageId": {
480
- "Ref": "BuildNode2AMI"
481
- },
482
- "Tags": [
483
- {
484
- "Key": "Name",
485
- "Value": {
486
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Build Node 2" ] ]
487
- }
488
- }
489
- ]
490
- }
491
- },
492
- "BuildNode3": {
493
- "Type": "AWS::EC2::Instance",
494
- "Properties": {
495
- "InstanceType": "m4.large",
496
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
497
- "NetworkInterfaces": [
498
- {
499
- "GroupSet": [
500
- {
501
- "Ref": "DemoSecurityGroup"
502
- }
503
- ],
504
- "AssociatePublicIpAddress": "true",
505
- "PrivateIpAddress": "172.31.54.53",
506
- "DeviceIndex": "0",
507
- "DeleteOnTermination": "true",
508
- "SubnetId": {
509
- "Ref": "SubnetAutomate"
510
- }
511
- }
512
- ],
513
- "KeyName": { "Ref": "KeyName" },
514
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
515
- "#!/bin/bash -xe\n",
516
- "hostnamectl set-hostname build-node-3\n",
517
- "sleep 90\n",
518
- "sudo chef-client\n"]]}
519
- },
520
- "ImageId": {
521
- "Ref": "BuildNode3AMI"
522
- },
523
- "Tags": [
524
- {
525
- "Key": "Name",
526
- "Value": {
527
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Build Node 3" ] ]
528
- }
529
- }
530
- ]
531
- }
532
- },
533
- "delivered": {
534
- "Type": "AWS::EC2::Instance",
535
- "Properties": {
536
- "InstanceType": "m4.large",
537
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
538
- "NetworkInterfaces": [
539
- {
540
- "GroupSet": [
541
- {
542
- "Ref": "DemoSecurityGroup"
543
- }
544
- ],
545
- "AssociatePublicIpAddress": "true",
546
- "PrivateIpAddress": "172.31.54.101",
547
- "DeviceIndex": "0",
548
- "DeleteOnTermination": "true",
549
- "SubnetId": {
550
- "Ref": "SubnetAutomate"
551
- }
552
- }
553
- ],
554
- "KeyName": { "Ref": "KeyName" },
555
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
556
- "#!/bin/bash -xe\n",
557
- "hostnamectl set-hostname delivered\n",
558
- "sleep 90\n",
559
- "sudo chef-client\n"
560
- ]]}
561
- },
562
- "ImageId": {
563
- "Ref": "deliveredAMI"
564
- },
565
- "Tags": [
566
- {
567
- "Key": "Name",
568
- "Value": {
569
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "delivered" ] ]
570
- }
571
- }
572
- ]
573
- }
574
- },
575
- "ecomacceptance": {
576
- "Type": "AWS::EC2::Instance",
577
- "Properties": {
578
- "InstanceType": "m4.large",
579
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
580
- "NetworkInterfaces": [
581
- {
582
- "GroupSet": [
583
- {
584
- "Ref": "DemoSecurityGroup"
585
- }
586
- ],
587
- "AssociatePublicIpAddress": "true",
588
- "PrivateIpAddress": "172.31.54.102",
589
- "DeviceIndex": "0",
590
- "DeleteOnTermination": "true",
591
- "SubnetId": {
592
- "Ref": "SubnetAutomate"
593
- }
594
- }
595
- ],
596
- "KeyName": { "Ref": "KeyName" },
597
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
598
- "#!/bin/bash -xe\n",
599
- "hostnamectl set-hostname ecomacceptance\n",
600
- "sleep 90\n",
601
- "sudo chef-client\n"
602
- ]]}
603
- },
604
- "ImageId": {
605
- "Ref": "ecomacceptanceAMI"
606
- },
607
- "Tags": [
608
- {
609
- "Key": "Name",
610
- "Value": {
611
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "ecomacceptance" ] ]
612
- }
613
- }
614
- ]
615
- }
616
- },
617
- "rehearsal": {
618
- "Type": "AWS::EC2::Instance",
619
- "Properties": {
620
- "InstanceType": "m4.large",
621
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
622
- "NetworkInterfaces": [
623
- {
624
- "GroupSet": [
625
- {
626
- "Ref": "DemoSecurityGroup"
627
- }
628
- ],
629
- "AssociatePublicIpAddress": "true",
630
- "PrivateIpAddress": "172.31.54.103",
631
- "DeviceIndex": "0",
632
- "DeleteOnTermination": "true",
633
- "SubnetId": {
634
- "Ref": "SubnetAutomate"
635
- }
636
- }
637
- ],
638
- "KeyName": { "Ref": "KeyName" },
639
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
640
- "#!/bin/bash -xe\n",
641
- "hostnamectl set-hostname rehearsal\n",
642
- "sleep 90\n",
643
- "sudo chef-client\n"
644
- ]]}
645
- },
646
- "ImageId": {
647
- "Ref": "rehearsalAMI"
648
- },
649
- "Tags": [
650
- {
651
- "Key": "Name",
652
- "Value": {
653
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "rehearsal" ] ]
654
- }
655
- }
656
- ]
657
- }
658
- },
659
- "union": {
660
- "Type": "AWS::EC2::Instance",
661
- "Properties": {
662
- "InstanceType": "m4.large",
663
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
664
- "NetworkInterfaces": [
665
- {
666
- "GroupSet": [
667
- {
668
- "Ref": "DemoSecurityGroup"
669
- }
670
- ],
671
- "AssociatePublicIpAddress": "true",
672
- "PrivateIpAddress": "172.31.54.104",
673
- "DeviceIndex": "0",
674
- "DeleteOnTermination": "true",
675
- "SubnetId": {
676
- "Ref": "SubnetAutomate"
677
- }
678
- }
679
- ],
680
- "KeyName": { "Ref": "KeyName" },
681
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
682
- "#!/bin/bash -xe\n",
683
- "hostnamectl set-hostname union\n",
684
- "sleep 90\n",
685
- "sudo chef-client\n"
686
- ]]}
687
- },
688
- "ImageId": {
689
- "Ref": "unionAMI"
690
- },
691
- "Tags": [
692
- {
693
- "Key": "Name",
694
- "Value": {
695
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "union" ] ]
696
- }
697
- }
698
- ]
699
- }
700
- },
701
- "Chef": {
702
- "Type": "AWS::EC2::Instance",
703
- "Properties": {
704
- "InstanceType": "c4.xlarge",
705
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
706
- "BlockDeviceMappings" : [
707
- {
708
- "DeviceName" : "/dev/sda1",
709
- "Ebs" : { "VolumeSize" : "50" }
710
- }
711
- ],
712
- "NetworkInterfaces": [
713
- {
714
- "GroupSet": [
715
- {
716
- "Ref": "DemoSecurityGroup"
717
- }
718
- ],
719
- "AssociatePublicIpAddress": "true",
720
- "PrivateIpAddress": "172.31.54.10",
721
- "DeviceIndex": "0",
722
- "DeleteOnTermination": "true",
723
- "SubnetId": {
724
- "Ref": "SubnetAutomate"
725
- }
726
- }
727
- ],
728
- "KeyName": { "Ref": "KeyName" },
729
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
730
- "#!/bin/bash -xe\n",
731
- "hostnamectl set-hostname chef\n",
732
- "chef-server-ctl reconfigure\n"]]}
733
- },
734
- "ImageId": {
735
- "Ref": "ChefServerAMI"
736
- },
737
- "Tags": [
738
- {
739
- "Key": "Name",
740
- "Value": {
741
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Chef Server" ] ]
742
- }
743
- }
744
- ]
745
- }
746
- },
747
- "Automate": {
748
- "Type": "AWS::EC2::Instance",
749
- "Properties": {
750
- "InstanceType": "c4.xlarge",
751
- "AvailabilityZone": { "Ref": "AvailabilityZone" },
752
- "BlockDeviceMappings" : [
753
- {
754
- "DeviceName" : "/dev/sda1",
755
- "Ebs" : { "VolumeSize" : "50" }
756
- }
757
- ] ,
758
- "NetworkInterfaces": [
759
- {
760
- "GroupSet": [
761
- {
762
- "Ref": "DemoSecurityGroup"
763
- }
764
- ],
765
- "AssociatePublicIpAddress": "true",
766
- "PrivateIpAddress": "172.31.54.11",
767
- "DeviceIndex": "0",
768
- "DeleteOnTermination": "true",
769
- "SubnetId": {
770
- "Ref": "SubnetAutomate"
771
- }
772
- }
773
- ],
774
- "KeyName": { "Ref": "KeyName" },
775
- "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
776
- "#!/bin/bash -xe\n",
777
- "hostnamectl set-hostname automate\n",
778
- "delivery-ctl reconfigure\n"]]}
779
- },
780
- "ImageId": {
781
- "Ref": "AutomateAMI"
782
- },
783
- "Tags": [
784
- {
785
- "Key": "Name",
786
- "Value": {
787
- "Fn::Join" : [ " ", [ { "Ref": "DemoName" }, "Automate Server" ] ]
788
- }
789
- }
790
- ]
791
- }
792
- },
793
- "DemoSecurityGroup": {
794
- "Type": "AWS::EC2::SecurityGroup",
795
- "Properties": {
796
- "VpcId": {
797
- "Ref": "VPC"
798
- },
799
- "GroupDescription": "Enable required ports for Chef Server",
800
- "SecurityGroupIngress": [
801
- {
802
- "IpProtocol": "tcp",
803
- "FromPort": "22",
804
- "ToPort": "22",
805
- "CidrIp": {
806
- "Ref": "SSHLocation"
807
- }
808
- },
809
- {
810
- "IpProtocol": "tcp",
811
- "FromPort": "0",
812
- "ToPort": "65535",
813
- "CidrIp": "172.31.0.0/16"
814
- },
815
- {
816
- "IpProtocol": "tcp",
817
- "FromPort": "3389",
818
- "ToPort": "3389",
819
- "CidrIp": "0.0.0.0/0"
820
- },
821
- {
822
- "IpProtocol": "tcp",
823
- "FromPort": "443",
824
- "ToPort": "443",
825
- "CidrIp": "0.0.0.0/0"
826
- },
827
- {
828
- "IpProtocol": "icmp",
829
- "FromPort": "8",
830
- "ToPort": "-1",
831
- "CidrIp": "0.0.0.0/0"
832
- },
833
- {
834
- "IpProtocol": "udp",
835
- "FromPort": "3389",
836
- "ToPort": "3389",
837
- "CidrIp": "0.0.0.0/0"
838
- },
839
- {
840
- "IpProtocol": "tcp",
841
- "FromPort": "5985",
842
- "ToPort": "5985",
843
- "CidrIp": "0.0.0.0/0"
844
- }
845
- ]
846
- }
847
- }
848
- },
849
- "Outputs":
850
- {"WindowsWorkstation1PubDNS":{"Description":"Public IP address of the Windows Workstation","Value":{"Fn::GetAtt":["WindowsWorkstation1","PublicIp"]}}}
851
- }