1
+ {
2
+ "AWSTemplateFormatVersion" : "2010-09-09",
3
+
4
+ "Description" : "CloudFormation Template to provision a target environment for the rails sample app",
5
+
6
+ "Parameters" : {
7
+
8
+ "KeyName" : {
9
+ "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
10
+ "Type" : "String",
11
+ "Default" : "ditc",
12
+ "MinLength": "1",
13
+ "MaxLength": "64",
14
+ "AllowedPattern" : "[-_ a-zA-Z0-9]*",
15
+ "ConstraintDescription" : "can contain only alphanumeric characters, spaces, dashes and underscores."
16
+ },
17
+
18
+ "InstanceType" : {
19
+ "Description" : "EC2 instance type",
20
+ "Type" : "String",
21
+ "Default" : "c1.medium",
22
+ "ConstraintDescription" : "must be a valid EC2 instance type."
23
+ },
24
+
25
+ "ApplicationName" : {
26
+ "Description" : "CNAME for the application",
27
+ "Type" : "String",
28
+ "Default" : "target"
29
+ },
30
+
31
+ "HostedZone" : {
32
+ "Description" : "Domain to use",
33
+ "Type" : "String",
34
+ "Default" : "devopscloud.com"
35
+ },
36
+
37
+ "EnvironmentType" : {
38
+ "Description" : "Mode for rails to run in",
39
+ "Type" : "String",
40
+ "Default" : "development"
41
+ },
42
+
43
+ "PrivateBucket" : {
44
+ "Description" : "S3 bucket for storing credentials",
45
+ "Type" : "String",
46
+ "Default" : "stelligentlabs-private",
47
+ "ConstraintDescription" : "Must be a valid S3 Bucket"
48
+ },
49
+
50
+ "PublicBucket" : {
51
+ "Description" : "S3 bucket for storing build artifacts",
52
+ "Type" : "String",
53
+ "Default" : "stelligentlabs",
54
+ "ConstraintDescription" : "Must be a valid S3 Bucket"
55
+ }
56
+ },
57
+
58
+ "Mappings" : {
59
+ "AWSInstanceType2Arch" : {
60
+ "t1.micro" : { "Arch" : "64" },
61
+ "m1.large" : { "Arch" : "64" },
62
+ "c1.medium" : { "Arch" : "64" }
63
+ },
64
+ "AWSRegionArch2AMI" : {
65
+ "us-east-1" : { "64" : "ami-7341831a" }
66
+ }
67
+ },
68
+
69
+ "Resources" : {
70
+
71
+ "CfnUser" : {
72
+ "Type" : "AWS::IAM::User",
73
+ "Properties" : {
74
+ "Path": "/",
75
+ "Policies": [{
76
+ "PolicyName": "root",
77
+ "PolicyDocument": { "Statement":[{
78
+ "Effect":"Allow",
79
+ "Action":"*",
80
+ "Resource":"*"
81
+ }
82
+ ]}
83
+ }]
84
+ }
85
+ },
86
+
87
+ "PrivateBucketPolicy" : {
88
+ "Type" : "AWS::S3::BucketPolicy",
89
+ "Properties" : {
90
+ "PolicyDocument": {
91
+ "Id":"PrivateBucketPolicy",
92
+ "Statement":[
93
+ {
94
+ "Sid":"ReadAccess",
95
+ "Action":["s3:GetObject"],
96
+ "Effect":"Allow",
97
+ "Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "PrivateBucket" } , "/*" ]]},
98
+ "Principal":{ "AWS": { "Fn::GetAtt" : [ "CfnUser", "Arn" ]} }
99
+ }
100
+ ]
101
+ },
102
+ "Bucket" : {"Ref" : "PrivateBucket"}
103
+ }
104
+ },
105
+
106
+ "HostKeys" : {
107
+ "Type" : "AWS::IAM::AccessKey",
108
+ "Properties" : {
109
+ "UserName" : { "Ref": "CfnUser" }
110
+ }
111
+ },
112
+
113
+ "Domain" : {
114
+ "Type" : "AWS::Route53::RecordSetGroup",
115
+ "Properties" : {
116
+ "HostedZoneName" : { "Fn::Join" : [ "", [ {"Ref" : "HostedZone"}, "." ]]},
117
+ "RecordSets" : [
118
+ {
119
+ "Name" : { "Fn::Join" : ["", [ { "Ref" : "ApplicationName" }, ".", { "Ref" : "HostedZone" }, "." ]]},
120
+ "Type" : "A",
121
+ "TTL" : "900",
122
+ "ResourceRecords" : [ { "Ref" : "IPAddress" } ]
123
+ }]
124
+ }
125
+ },
126
+
127
+ "WebServer": {
128
+ "Type": "AWS::EC2::Instance",
129
+ "DependsOn" : "PrivateBucketPolicy",
130
+ "Metadata" : {
131
+ "AWS::CloudFormation::Init" : {
132
+ "config" : {
133
+ "packages" : {
134
+ "yum" : {
135
+ "puppet" : []
136
+ }
137
+ },
138
+
139
+ "sources" : {
140
+ "/home/ec2-user/" : { "Fn::Join" : ["", ["https://s3.amazonaws.com/stelligentlabs/puppet.tar.gz"]]}
141
+ },
142
+
143
+ "files" : {
144
+ "/home/ec2-user/id_rsa.pub" : {
145
+ "source" : { "Fn::Join" : ["", ["https://s3.amazonaws.com/", { "Ref" : "PrivateBucket" }, "/id_rsa.pub"]]},
146
+ "mode" : "000500",
147
+ "owner" : "root",
148
+ "group" : "root",
149
+ "authentication" : "S3AccessCreds"
150
+ },
151
+ "/home/ec2-user/nodes.pp" : {
152
+ "content" : { "Fn::Join" : ["", [
153
+ "node default {\n",
154
+ "include system\n",
155
+ "include bundler\n",
156
+ "include passenger\n",
157
+ "include sqlite\n",
158
+ "include git\n",
159
+ "include httpd\n",
160
+ "}"
161
+ ]]},
162
+ "mode" : "000500",
163
+ "owner" : "root",
164
+ "group" : "root"
165
+ },
166
+
167
+
168
+ "/etc/httpd/conf/virtualhosts" : {
169
+ "content" : { "Fn::Join" : ["", [
170
+ "NameVirtualHost *:80\n",
171
+ "<VirtualHost *:80>\n",
172
+ "ServerName ", { "Fn::Join" : [ ".", [ { "Ref" : "ApplicationName" }, { "Ref" : "HostedZone" }]]}, "\n",
173
+ "ServerAlias ", { "Fn::Join" : [ ".", [ { "Ref" : "ApplicationName" }, { "Ref" : "HostedZone" }]]}, "\n",
174
+ "RailsEnv ", {"Ref" : "EnvironmentType"}, "\n",
175
+ "DocumentRoot /var/www/rails/public\n",
176
+ "<Directory /var/www/rails/public>\n",
177
+ "AllowOverride all\n",
178
+ "Options -MultiViews\n",
179
+ "</Directory>\n",
180
+ "</VirtualHost>\n"
181
+ ]]},
182
+ "mode" : "000500",
183
+ "owner" : "root",
184
+ "group" : "root"
185
+ },
186
+ "/etc/httpd/conf/passenger" : {
187
+ "content" : { "Fn::Join" : ["", [
188
+ "LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-3.0.13/ext/apache2/mod_passenger.so\n",
189
+ "PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-3.0.13\n",
190
+ "PassengerRuby /usr/bin/ruby\n"
191
+ ]]},
192
+ "mode" : "000500",
193
+ "owner" : "root",
194
+ "group" : "root"
195
+ }
196
+ }
197
+ }
198
+ },
199
+
200
+ "AWS::CloudFormation::Authentication" : {
201
+ "S3AccessCreds" : {
202
+ "type" : "S3",
203
+ "accessKeyId" : { "Ref" : "HostKeys" },
204
+ "secretKey" : {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]},
205
+ "buckets" : [ { "Ref" : "PrivateBucket" }, { "Ref" : "PublicBucket"} ]
206
+ }
207
+ }
208
+ },
209
+ "Properties": {
210
+ "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
211
+ { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
212
+ "InstanceType" : { "Ref" : "InstanceType" },
213
+ "SecurityGroups" : [ {"Ref" : "FrontendGroup"} ],
214
+ "KeyName" : { "Ref" : "KeyName" },
215
+ "Tags" : [{ "Key" : "Name", "Value" : "Target Environment" }],
216
+ "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
217
+ "#!/bin/bash -v\n",
218
+ "date > /home/ec2-user/starttime\n",
219
+ "yum update -y aws-cfn-bootstrap\n",
220
+
221
+ "# Install packages\n",
222
+ "/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackName" }, " -r WebServer ",
223
+ " --access-key ", { "Ref" : "HostKeys" },
224
+ " --secret-key ", {"Fn::GetAtt": ["HostKeys", "SecretAccessKey"]},
225
+ " --region ", { "Ref" : "AWS::Region" }, " || error_exit 'Failed to run cfn-init'\n",
226
+
227
+ "# Build environment using Puppet\n",
228
+ "puppet apply --modulepath=/home/ec2-user/modules /home/ec2-user/nodes.pp\n",
229
+
230
+ "# Add in virtual hosts config\n",
231
+ "cat /etc/httpd/conf/passenger >> /etc/httpd/conf/httpd.conf\n",
232
+ "cat /etc/httpd/conf/virtualhosts >> /etc/httpd/conf/httpd.conf\n",
233
+
234
+ "# Add Public key for passwordless authentication from Jenkins Instance\n",
235
+ "cat /home/ec2-user/id_rsa.pub >> /home/ec2-user/.ssh/authorized_keys\n",
236
+
237
+ "# Disable tty for ec2-user\n",
238
+ "echo \"Defaults:%ec2-user !requiretty\" >> /etc/sudoers\n",
239
+ "echo \"Defaults:ec2-user !requiretty\" >> /etc/sudoers\n",
240
+
241
+ "/opt/aws/bin/cfn-signal", " -e 0", " '", { "Ref" : "WaitHandle" }, "'","\n",
242
+
243
+ "date > /home/ec2-user/stoptime"
244
+ ]]}}
245
+ }
246
+ },
247
+
248
+ "IPAddress" : {
249
+ "Type" : "AWS::EC2::EIP"
250
+ },
251
+
252
+ "IPAssoc" : {
253
+ "Type" : "AWS::EC2::EIPAssociation",
254
+ "Properties" : {
255
+ "InstanceId" : { "Ref" : "WebServer" },
256
+ "EIP" : { "Ref" : "IPAddress" }
257
+ }
258
+ },
259
+
260
+ "FrontendGroup" : {
261
+ "Type" : "AWS::EC2::SecurityGroup",
262
+ "Properties" : {
263
+ "GroupDescription" : "Enable SSH and access to Apache",
264
+ "SecurityGroupIngress" : [
265
+ {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0" },
266
+ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" }
267
+ ]
268
+ }
269
+ },
270
+
271
+ "WaitHandle" : {
272
+ "Type" : "AWS::CloudFormation::WaitConditionHandle"
273
+ },
274
+
275
+ "WaitCondition" : {
276
+ "Type" : "AWS::CloudFormation::WaitCondition",
277
+ "DependsOn" : "WebServer",
278
+ "Properties" : {
279
+ "Handle" : { "Ref" : "WaitHandle" },
280
+ "Timeout" : "1200"
281
+ }
282
+ }
283
+ },
284
+
285
+ "Outputs" : {
286
+ "InstanceIPAddress" : {
287
+ "Value" : { "Ref" : "IPAddress" }
288
+ },
289
+ "StackName" : {
290
+ "Value" : { "Ref" : "AWS::StackName" }
291
+ },
292
+ "ArtifactBucket" : {
293
+ "Value" : { "Ref" : "PublicBucket" }
294
+ },
295
+ "Domain" : {
296
+ "Value" : { "Fn::Join" : ["", [{ "Ref" : "ApplicationName" }, ".", { "Ref" : "HostedZone" }]] },
297
+ "Description" : "Full domain"
298
+ },
299
+ "SampleApp" : {
300
+ "Value" : { "Fn::Join" : ["", ["http://", { "Ref" : "ApplicationName" }, ".", { "Ref" : "HostedZone" }, "/"]] },
301
+ "Description" : "URL for newly created Sample App"
302
+ }
303
+ }
304
+ }
0 commit comments