stacco 0.1.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.
@@ -0,0 +1,17 @@
1
+ # hit aws bootstrapping webhook
2
+ unique_id=$(uuidgen -t)
3
+
4
+ aws_wait_handle_response_file="/tmp/cf-wait-handle-response.json"
5
+
6
+ cat >"${aws_wait_handle_response_file}" <<EOF
7
+ {"Status": "SUCCESS",
8
+ "Reason": "Configuration Complete",
9
+ "UniqueId": "${unique_id}",
10
+ "Data": "Application has completed configuration."
11
+ }
12
+ EOF
13
+
14
+ curl -s -T "${aws_wait_handle_response_file}" "${AWS_WAIT_HANDLE}"
15
+ rm "${aws_wait_handle_response_file}"
16
+
17
+ echo "done bootstrapping!"
@@ -0,0 +1,37 @@
1
+ # configure hostname from metadata service
2
+ public_hostname_response_code=404
3
+ while [ "${public_hostname_response_code}" != "200" ]; do
4
+ public_hostname_response_code=$(curl -sL -w "%{http_code}" "http://169.254.169.254/latest/meta-data/public-hostname" -o /dev/null)
5
+ sleep 3
6
+ done
7
+
8
+ public_hostname=$(curl http://169.254.169.254/latest/meta-data/public-hostname)
9
+ private_hostname=$(curl http://169.254.169.254/latest/meta-data/hostname)
10
+
11
+ echo "${public_hostname}" > /etc/hostname
12
+ hostname -b -F /etc/hostname
13
+
14
+ short_hostname=$(hostname -s)
15
+
16
+ sed -i '/127\.0\.0\.1/d' /etc/hosts
17
+ cat >>/etc/hosts <<EOF
18
+ 127.0.0.1 localhost ${short_hostname} ${public_hostname} ${private_hostname}
19
+ EOF
20
+
21
+
22
+ # disable long update-initramfs calls (we're ephemeral!)
23
+ sed -i 's/=yes/=no/g' /etc/initramfs-tools/update-initramfs.conf
24
+
25
+ echo 'deb http://get.docker.io/ubuntu docker main' > /etc/apt/sources.list.d/docker.list
26
+ curl -sL "https://get.docker.io/gpg" | apt-key add -
27
+ apt-get update
28
+ apt-get upgrade -qy
29
+ apt-get -qy install htop tree btrfs-tools xz-utils cloud-utils
30
+
31
+
32
+ if [ -b "/dev/xvdd" ]; then
33
+ mkfs.btrfs -L datavols /dev/xvdd
34
+ mkdir -p /volumes
35
+ mount /dev/xvdd /volumes
36
+ fi
37
+
@@ -0,0 +1,36 @@
1
+ mkdir -p /etc/bexng
2
+ echo "${DOMAIN}" > /etc/bexng/name
3
+
4
+ cat >"/etc/bexng/secrets.exs" <<EOF
5
+ [
6
+ authy: "${AUTHY_KEY}",
7
+ mandrill: "${MANDRILL_KEY}",
8
+ admin_password: "${ADMIN_PASSWORD}"
9
+ ]
10
+ EOF
11
+
12
+ base64 -d >"/etc/bexng/armory_testnet_watch_only.wallet" <<EOF
13
+ ${WALLET_DATA}
14
+ EOF
15
+
16
+ start_container "postgresql" \
17
+ --volume="/volumes/postgresql:/var/lib/postgresql"
18
+
19
+ start_container "bitcoind" \
20
+ --volume="/volumes/bitcoind:/var/lib/bitcoin"
21
+
22
+ start_container "bexng" \
23
+ -e "BEXNG_TARGET_SYSTEM=${DOMAIN}" \
24
+ --link="${containers[bitcoind]}:bitcoind" \
25
+ --link="${containers[postgresql]}:postgresql" \
26
+ --publish="4369:4369" \
27
+ --publish="9999:9999" \
28
+ --publish="20000:20000" \
29
+ --publish="20001:20001" \
30
+ --publish="51607:51607" \
31
+ --publish="51608:51608" \
32
+ --volume="/etc/bexng:/target"
33
+
34
+ start_container "bexng_frontend" \
35
+ -e "BEXNG_BACKEND=127.0.0.1:51608" \
36
+ --publish="80:8080"
@@ -0,0 +1,24 @@
1
+ docker_volume="/dev/xvdc"
2
+
3
+ # install docker
4
+ mkdir -p /var/lib/docker
5
+ mount -t btrfs -o "rw,noatime,space_cache" "${docker_volume}" /var/lib/docker
6
+
7
+ apt-get install -qy lxc-docker
8
+ gpasswd -a ubuntu docker
9
+ docker login -e="${DOCKER_REGISTRY_EMAIL}" -p="${DOCKER_REGISTRY_PASSWORD}" -u="${DOCKER_REGISTRY_USER}" "${DOCKER_REGISTRY}"
10
+
11
+ # start containers
12
+ declare -A containers
13
+
14
+ start_container() {
15
+ image_name=$1
16
+ shift
17
+
18
+ echo "starting container: ${image_name}..." >&2
19
+ container_id=$(docker run -d $@ quay.io/bexio/${image_name}:latest)
20
+ container_name=$(docker inspect "${container_id}" | grep Name | tr '"/' ' ' | awk '{print $3;}')
21
+ echo "started."
22
+
23
+ containers[${image_name}]=${container_name}
24
+ }
@@ -0,0 +1,3 @@
1
+ start_container "bexng_frontend" \
2
+ -e "BEXNG_BACKEND=${BACKEND_ENDPOINT}:51607" \
3
+ --publish="80:8080"
@@ -0,0 +1,88 @@
1
+ openvpn_pkg_path="/tmp/openvpn-as.deb"
2
+ curl -sL "http://swupdate.openvpn.org/as/openvpn-as-2.0.7-Debian7.amd64.deb" > "${openvpn_pkg_path}"
3
+ sudo dpkg -i "${openvpn_pkg_path}"
4
+ rm "${openvpn_pkg_path}"
5
+
6
+ mkdir -p /usr/local/openvpn_as/etc/licenses
7
+ echo "openvpn:openvpn" | sudo chpasswd
8
+
9
+ cat >"/usr/local/openvpn_as/etc/licenses/IOVS-WMFK-YDTO-MKPY.lic" <<EOF
10
+ CPU_MODEL_NAME=Intel(R) Xeon(R) CPU E5-2650 0 @ 2.00GHz
11
+ HOSTNAME=OVPNAS20
12
+ INODE_HASH=304d68e87dfb6280e1f2fbf1e52d84286420f638273e281ec9bef7df3603d821
13
+ LICENSE_KEY=IOVS-WMFK-YDTO-MKPY
14
+ MAC_ADDR=06:53:b9:ea:dd:c0
15
+ MAC_ADDR_0=06:53:b9:ea:dd:c0
16
+ PROP_FUZZY=MAC_ADDR
17
+ PROP_STRICT=CPU_MODEL_NAME
18
+ VPROP_N_REQUIRED=2
19
+ VPROP_VERSION=2
20
+ concurrent_connections=0
21
+ concurrent_connections_aggregated=10
22
+ expiry_date=20150210
23
+ expiry_date_updates=
24
+ openvpn_core_max_version=1.0
25
+ quota_properties=concurrent_connections
26
+ -----BEGIN RSA SIGNATURE-----
27
+ vpin6QaiijAJYaDj1D1zTxY3muCNDdCXJsM/yIVtsif6smBsdK
28
+ I8+OfdzXzKROo1fit7zlaXfEfufar1vwA1ofciORF6T/ky+AG/
29
+ GiAAn057TBOGCCfxy1aUHkRslGKmJPnWUsl7qGQYlGG/JfYBzS
30
+ ZRP/jckzWEc65IigRynPA=
31
+ -----END RSA SIGNATURE-----
32
+ EOF
33
+
34
+ cat >"/usr/local/openvpn_as/etc/config.json" <<EOF
35
+ {
36
+ "Default": {
37
+ "admin_ui.https.ip_address": "eth0",
38
+ "admin_ui.https.port": "943",
39
+ "aui.eula_version": "2",
40
+ "auth.ldap.0.name": "My LDAP servers",
41
+ "auth.ldap.0.ssl_verify": "never",
42
+ "auth.ldap.0.timeout": "4",
43
+ "auth.ldap.0.use_ssl": "never",
44
+ "auth.module.type": "pam",
45
+ "auth.pam.0.service": "openvpnas",
46
+ "auth.radius.0.acct_enable": "false",
47
+ "auth.radius.0.name": "My Radius servers",
48
+ "cs.cws_proto_v2": "true",
49
+ "cs.https.ip_address": "eth0",
50
+ "cs.https.port": "943",
51
+ "cs.prof_sign_web": "true",
52
+ "host.name": "vpn.${DOMAIN}",
53
+ "sa.initial_run_groups.0": "web_group",
54
+ "sa.initial_run_groups.1": "openvpn_group",
55
+ "vpn.client.routing.inter_client": "false",
56
+ "vpn.client.routing.reroute_dns": "true",
57
+ "vpn.client.routing.reroute_gw": "false",
58
+ "vpn.daemon.0.client.netmask_bits": "20",
59
+ "vpn.daemon.0.client.network": "172.27.224.0",
60
+ "vpn.daemon.0.listen.ip_address": "eth0",
61
+ "vpn.daemon.0.listen.port": "443",
62
+ "vpn.daemon.0.listen.protocol": "tcp",
63
+ "vpn.daemon.0.server.ip_address": "eth0",
64
+ "vpn.server.daemon.enable": "true",
65
+ "vpn.server.daemon.tcp.n_daemons": 1,
66
+ "vpn.server.daemon.tcp.port": "443",
67
+ "vpn.server.daemon.udp.n_daemons": 1,
68
+ "vpn.server.daemon.udp.port": "1194",
69
+ "vpn.server.group_pool.0": "172.27.240.0/20",
70
+ "vpn.server.port_share.enable": "true",
71
+ "vpn.server.port_share.ip_address": "1.2.3.4",
72
+ "vpn.server.port_share.port": "1234",
73
+ "vpn.server.port_share.service": "admin+client",
74
+ "vpn.server.routing.gateway_access": "true",
75
+ "vpn.server.routing.private_access": "nat",
76
+ "vpn.server.routing.private_network.0": "10.100.0.0/24",
77
+ "vpn.server.routing.private_network.1": "10.100.1.0/24",
78
+ "vpn.tls_refresh.do_reauth": "true",
79
+ "vpn.tls_refresh.interval": "360"
80
+ },
81
+ "_INTERNAL": {
82
+ "run_api.active_profile": "Default",
83
+ "webui.edit_profile": "Default"
84
+ }
85
+ }
86
+ EOF
87
+
88
+ /usr/local/openvpn_as/scripts/confdba -l -f /usr/local/openvpn_as/etc/config.json
@@ -0,0 +1,534 @@
1
+ <%
2
+ ubuntu_daily_ami = "ami-6ac2a85a"
3
+ docker_library_snapshot = "snap-ee9ca31c"
4
+ %>
5
+
6
+ {
7
+ "AWSTemplateFormatVersion": "2010-09-09",
8
+ "Description": <%= j @stack.description %>,
9
+
10
+ "Resources": {
11
+
12
+ "VPC": {"Type": "AWS::EC2::VPC", "Properties": {
13
+ "CidrBlock": "10.100.0.0/16",
14
+ "InstanceTenancy": "default",
15
+ "EnableDnsSupport": true,
16
+ "EnableDnsHostnames": true
17
+ }},
18
+
19
+ "InternetGateway": {"Type": "AWS::EC2::InternetGateway", "Properties": {
20
+ }},
21
+
22
+ "InternetGatewayAttachment": {"Type": "AWS::EC2::VPCGatewayAttachment", "Properties": {
23
+ "VpcId": {"Ref": "VPC"},
24
+ "InternetGatewayId": {"Ref": "InternetGateway"}
25
+ }},
26
+
27
+ "NetworkAcl": {"Type": "AWS::EC2::NetworkAcl", "Properties": {
28
+ "VpcId": {"Ref": "VPC"}
29
+ }},
30
+
31
+ "PublicSubnet": {"Type": "AWS::EC2::Subnet", "Properties": {
32
+ "VpcId": {"Ref": "VPC"},
33
+ "CidrBlock": "10.100.0.0/24"
34
+ }},
35
+ "PublicSubnetAcl": {"Type": "AWS::EC2::SubnetNetworkAclAssociation", "Properties": {
36
+ "NetworkAclId": {"Ref": "NetworkAcl"},
37
+ "SubnetId": {"Ref": "PublicSubnet"}
38
+ }},
39
+ "PublicRouteTable": {"Type": "AWS::EC2::RouteTable", "Properties": {
40
+ "VpcId": {"Ref": "VPC"}
41
+ }},
42
+ "PublicSubnetRoute": {"Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": {
43
+ "SubnetId": {"Ref": "PublicSubnet"},
44
+ "RouteTableId": {"Ref": "PublicRouteTable"}
45
+ }},
46
+ "PublicSubnetGatewayRoute": {"Type": "AWS::EC2::Route", "DependsOn": "InternetGatewayAttachment", "Properties": {
47
+ "DestinationCidrBlock": "0.0.0.0/0",
48
+ "RouteTableId": {"Ref": "PublicRouteTable"},
49
+ "GatewayId": {"Ref": "InternetGateway"}
50
+ }},
51
+ "PublicIngressAcl": {"Type": "AWS::EC2::NetworkAclEntry", "Properties": {
52
+ "NetworkAclId": {"Ref": "NetworkAcl"},
53
+ "RuleNumber": "100",
54
+
55
+ "CidrBlock": "0.0.0.0/0",
56
+ "Protocol": "-1",
57
+ "RuleAction": "allow"
58
+ }},
59
+ "PublicEgressAcl": {"Type": "AWS::EC2::NetworkAclEntry", "Properties": {
60
+ "NetworkAclId": {"Ref": "NetworkAcl"},
61
+ "RuleNumber": "100",
62
+
63
+ "Egress": true,
64
+ "CidrBlock": "0.0.0.0/0",
65
+ "Protocol": "-1",
66
+ "RuleAction": "allow"
67
+ }},
68
+
69
+ "PrivateSubnet": {"Type": "AWS::EC2::Subnet", "Properties": {
70
+ "VpcId": {"Ref": "VPC"},
71
+ "AvailabilityZone": {"Fn::GetAtt": ["PublicSubnet", "AvailabilityZone"]},
72
+ "CidrBlock": "10.100.1.0/24"
73
+ }},
74
+ "PrivateSubnetAcl": {"Type": "AWS::EC2::SubnetNetworkAclAssociation", "Properties": {
75
+ "NetworkAclId": {"Ref": "NetworkAcl"},
76
+ "SubnetId": {"Ref": "PrivateSubnet"}
77
+ }},
78
+ "PrivateRouteTable": {"Type": "AWS::EC2::RouteTable", "Properties": {
79
+ "VpcId": {"Ref": "VPC"}
80
+ }},
81
+ "PrivateSubnetRoute": {"Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": {
82
+ "SubnetId": {"Ref": "PrivateSubnet"},
83
+ "RouteTableId": {"Ref": "PrivateRouteTable"}
84
+ }},
85
+ "PrivateSubnetGatewayRoute": {"Type": "AWS::EC2::Route", "DependsOn": "InternetGatewayAttachment", "Properties": {
86
+ "DestinationCidrBlock": "0.0.0.0/0",
87
+ "RouteTableId": {"Ref": "PrivateRouteTable"},
88
+ "GatewayId": {"Ref": "InternetGateway"}
89
+ }},
90
+
91
+ "DHCPOptions": {"Type": "AWS::EC2::DHCPOptions", "Properties": {
92
+ "DomainName": <%= j domain %>,
93
+ "DomainNameServers": ["AmazonProvidedDNS"]
94
+ }},
95
+ "VPCDHCPOptionsAssociation": {"Type": "AWS::EC2::VPCDHCPOptionsAssociation", "Properties": {
96
+ "VpcId": {"Ref": "VPC"},
97
+ "DhcpOptionsId": {"Ref": "DHCPOptions"}
98
+ }},
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+ "AppS3Bucket": {"Type": "AWS::S3::Bucket", "Properties": {
107
+ "BucketName": <%= j domain %>,
108
+ "AccessControl": "PublicRead",
109
+ "WebsiteConfiguration": {
110
+ "IndexDocument": "index.html",
111
+ "ErrorDocument": "404.html"
112
+ }
113
+ }},
114
+
115
+ "AppS3BucketDistribution": {"Type": "AWS::CloudFront::Distribution", "Properties": {
116
+ "DistributionConfig": {
117
+ "Aliases": [<%= j domain %>],
118
+ "Enabled": "true",
119
+
120
+ "Origins": [{
121
+ "Id": "AppS3BucketOrigin",
122
+ "DomainName": {"Fn::Join": ["", [<%= j domain %>, ".s3-website-", {"Ref": "AWS::Region"}, ".amazonaws.com"]]},
123
+
124
+ "CustomOriginConfig": {
125
+ "HTTPPort": "80",
126
+ "HTTPSPort": "443",
127
+ "OriginProtocolPolicy": "http-only"
128
+ }
129
+ }],
130
+
131
+ "DefaultCacheBehavior": {
132
+ "TargetOriginId": "AppS3BucketOrigin",
133
+ "ForwardedValues": {"QueryString": "false"},
134
+ "ViewerProtocolPolicy": "redirect-to-https"
135
+ }
136
+ }
137
+ }},
138
+
139
+ "AppS3BucketDNSRecord": {"Type": "AWS::Route53::RecordSet", "Properties": {
140
+ "HostedZoneId": <%= j hosted_zone %>,
141
+ "Type": "A",
142
+ "Name": <%= j "#{domain}." %>,
143
+ "AliasTarget": {
144
+ "HostedZoneId": <%= j @config['cloudfront']['hosted_zone'] %>,
145
+ "DNSName": {"Fn::GetAtt": ["AppS3BucketDistribution", "DomainName"]}
146
+ }
147
+ }},
148
+
149
+ "WwwS3Bucket": {"Type": "AWS::S3::Bucket", "Properties": {
150
+ "BucketName": <%= j "www.#{domain}" %>,
151
+ "AccessControl": "PublicRead",
152
+ "WebsiteConfiguration": {
153
+ "RedirectAllRequestsTo": {
154
+ "HostName": <%= j domain %>,
155
+ "Protocol": "https"
156
+ }
157
+ }
158
+ }},
159
+
160
+ "WwwS3BucketDistribution": {"Type": "AWS::CloudFront::Distribution", "Properties": {
161
+ "DistributionConfig": {
162
+ "Aliases": [<%= j "www.#{domain}" %>],
163
+ "Enabled": "true",
164
+
165
+ "Origins": [{
166
+ "Id": "WwwS3BucketOrigin",
167
+ "DomainName": {"Fn::Join": ["", [<%= j "www.#{domain}" %>, ".s3-website-", {"Ref": "AWS::Region"}, ".amazonaws.com"]]},
168
+
169
+ "CustomOriginConfig": {
170
+ "HTTPPort": "80",
171
+ "HTTPSPort": "443",
172
+ "OriginProtocolPolicy": "http-only"
173
+ }
174
+ }],
175
+
176
+ "DefaultCacheBehavior": {
177
+ "TargetOriginId": "WwwS3BucketOrigin",
178
+ "ForwardedValues": {"QueryString": "false"},
179
+ "ViewerProtocolPolicy": "redirect-to-https"
180
+ }
181
+ }
182
+ }},
183
+
184
+ "WwwS3BucketDNSRecord": {"Type": "AWS::Route53::RecordSet", "Properties": {
185
+ "HostedZoneId": <%= j hosted_zone %>,
186
+ "Type": "CNAME", "TTL": "300",
187
+ "Name": <%= j "www.#{domain}." %>,
188
+ "ResourceRecords": [{"Fn::GetAtt": ["WwwS3BucketDistribution", "DomainName"]}]
189
+ }},
190
+
191
+
192
+ "AdminS3Bucket": {"Type": "AWS::S3::Bucket", "Properties": {
193
+ "BucketName": <%= j "admin.#{domain}" %>,
194
+ "AccessControl": "PublicRead",
195
+ "WebsiteConfiguration": {
196
+ "IndexDocument": "index.html",
197
+ "ErrorDocument": "404.html"
198
+ }
199
+ }},
200
+
201
+ "AdminS3BucketDistribution": {"Type": "AWS::CloudFront::Distribution", "Properties": {
202
+ "DistributionConfig": {
203
+ "Aliases": [<%= j "admin.#{domain}" %>],
204
+ "Enabled": "true",
205
+
206
+ "Origins": [{
207
+ "Id": "AdminS3BucketOrigin",
208
+ "DomainName": {"Fn::Join": ["", [<%= j "admin.#{domain}" %>, ".s3-website-", {"Ref": "AWS::Region"}, ".amazonaws.com"]]},
209
+
210
+ "CustomOriginConfig": {
211
+ "HTTPPort": "80",
212
+ "HTTPSPort": "443",
213
+ "OriginProtocolPolicy": "http-only"
214
+ }
215
+ }],
216
+
217
+ "DefaultCacheBehavior": {
218
+ "TargetOriginId": "AdminS3BucketOrigin",
219
+ "ForwardedValues": {"QueryString": "false"},
220
+ "ViewerProtocolPolicy": "redirect-to-https"
221
+ }
222
+ }
223
+ }},
224
+
225
+ "AdminS3BucketDNSRecord": {"Type": "AWS::Route53::RecordSet", "Properties": {
226
+ "HostedZoneId": <%= j hosted_zone %>,
227
+ "Type": "CNAME", "TTL": "300",
228
+ "Name": <%= j "admin.#{domain}." %>,
229
+ "ResourceRecords": [{"Fn::GetAtt": ["AdminS3BucketDistribution", "DomainName"]}]
230
+ }},
231
+
232
+
233
+
234
+
235
+ "InstanceBootstrapWaitHandle": {"Type": "AWS::CloudFormation::WaitConditionHandle", "Properties": {}},
236
+ "InstanceBootstrap": {"Type": "AWS::CloudFormation::WaitCondition", "DependsOn": ["Frontend", "Backend", "OpenVPN"], "Properties": {
237
+ "Handle": {"Ref": "InstanceBootstrapWaitHandle"},
238
+ "Count": "3",
239
+ "Timeout": "6000"
240
+ }},
241
+
242
+
243
+
244
+ "Frontend": {"Type": "AWS::EC2::Instance", "Properties": {
245
+ "InstanceType": "m1.small",
246
+ "ImageId": <%= j ubuntu_daily_ami %>,
247
+
248
+ "Tags": [
249
+ { "Key": "Name", "Value": "web01" },
250
+ { "Key": "Environment", "Value": <%= j environment %> }
251
+ ],
252
+
253
+ "KeyName": <%= j @stack.iam_keypair_name %>,
254
+
255
+ "BlockDeviceMappings": [
256
+ {"DeviceName": "/dev/xvdc", "Ebs": {
257
+ "SnapshotId": <%= j docker_library_snapshot %>,
258
+ "VolumeSize": "50"
259
+ }}
260
+ ],
261
+
262
+ "NetworkInterfaces": [{
263
+ "Description": "Primary network interface",
264
+ "DeviceIndex": 0,
265
+ "DeleteOnTermination": true,
266
+
267
+ "SubnetId": {"Ref": "PublicSubnet"},
268
+ "GroupSet": [{"Ref": "FrontendSecurityGroup"}]
269
+ }],
270
+
271
+ "UserData": {"Fn::Base64": {"Fn::Join": ["", [
272
+ "#!/bin/bash -e\n",
273
+ "export AWS_WAIT_HANDLE='", {"Ref": "InstanceBootstrapWaitHandle"}, "'\n",
274
+ "export BACKEND_ENDPOINT='", {"Fn::GetAtt": ["BackendEndpoint", "DNSName"]}, "'\n",
275
+ <%= ja 8, userdata['frontend'] %>
276
+ ]]}}
277
+ }},
278
+
279
+ "FrontendSecurityGroup": {"Type": "AWS::EC2::SecurityGroup", "Properties": {
280
+ "GroupDescription": "Enable SSH access via port 22 and HTTP via 80",
281
+ "VpcId": {"Ref": "VPC"},
282
+
283
+ "SecurityGroupIngress": [
284
+ {"IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": <%= j external_ssh_cidr %>},
285
+ {"IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": <%= j bastion_ssh_cidr %>},
286
+ {"IpProtocol": "tcp", "FromPort": "80", "ToPort": "80", "CidrIp": "10.100.0.0/24"}
287
+ ],
288
+ "SecurityGroupEgress": [{"IpProtocol": "-1", "CidrIp": "0.0.0.0/0"}]
289
+ }},
290
+
291
+ "FrontendEIP": {"Type": "AWS::EC2::EIP", "Properties": {
292
+ "Domain": "VPC"
293
+ }},
294
+
295
+ "FrontendEIPAssociation": {"Type": "AWS::EC2::EIPAssociation", "Properties": {
296
+ "AllocationId": {"Fn::GetAtt": ["FrontendEIP", "AllocationId"]},
297
+ "InstanceId": {"Ref": "Frontend"}
298
+ }},
299
+
300
+ "FrontendEndpoint": {"Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": {
301
+ "Instances": [{"Ref": "Frontend"}],
302
+ "Subnets": [{"Ref": "PublicSubnet"}],
303
+ "SecurityGroups": [{"Ref": "FrontendEndpointSecurityGroup"}],
304
+
305
+ "HealthCheck": {
306
+ "HealthyThreshold": "5",
307
+ "Interval": "30",
308
+ "Target": "HTTP:80/v1/info",
309
+ "Timeout": "5",
310
+ "UnhealthyThreshold": "2"
311
+ },
312
+ "Listeners": [{
313
+ "LoadBalancerPort": "443",
314
+ "InstancePort": "80",
315
+ "Protocol": "SSL",
316
+ "InstanceProtocol": "TCP",
317
+ "SSLCertificateId": {"Fn::Join": ["", [
318
+ "arn:aws:iam::", {"Ref": "AWS::AccountId"}, ":server-certificate/",
319
+ <%= j frontend_cert_path %>, ".pem"
320
+ ]]}
321
+ }]
322
+ }},
323
+
324
+ "FrontendEndpointDNSRecord": {"Type": "AWS::Route53::RecordSet", "Properties": {
325
+ "HostedZoneId": <%= j hosted_zone %>,
326
+ "Type": "CNAME", "TTL": "300",
327
+ "Name": <%= j "api.#{domain}." %>,
328
+ "ResourceRecords": [{"Fn::GetAtt": ["FrontendEndpoint", "DNSName"]}]
329
+ }},
330
+
331
+ "FrontendEndpointSecurityGroup": {"Type": "AWS::EC2::SecurityGroup", "Properties": {
332
+ "GroupDescription": "Frontend ELB security group",
333
+ "VpcId": {"Ref": "VPC"},
334
+
335
+ "SecurityGroupIngress": [
336
+ {"IpProtocol": "tcp", "FromPort": "443", "ToPort": "443", "CidrIp": "0.0.0.0/0"}
337
+ ],
338
+ "SecurityGroupEgress": [
339
+ {"IpProtocol": "tcp", "FromPort": "80", "ToPort": "80", "CidrIp": "0.0.0.0/0"}
340
+ ]
341
+ }},
342
+
343
+
344
+
345
+
346
+ "Backend": {"Type": "AWS::EC2::Instance", "Properties": {
347
+ "InstanceType": "m3.medium",
348
+ "ImageId": <%= j ubuntu_daily_ami %>,
349
+
350
+ "Tags": [
351
+ { "Key": "Name", "Value": "app01" },
352
+ { "Key": "Environment", "Value": <%= j environment %> }
353
+ ],
354
+
355
+ "KeyName": <%= j @stack.iam_keypair_name %>,
356
+
357
+ "BlockDeviceMappings": [
358
+ {"DeviceName": "/dev/xvdc", "Ebs": {
359
+ "SnapshotId": <%= j docker_library_snapshot %>,
360
+ "VolumeSize": "50"
361
+ }},
362
+
363
+ {"DeviceName": "/dev/xvdd", "Ebs": {
364
+ "VolumeSize": "300"
365
+ }}
366
+ ],
367
+
368
+ "NetworkInterfaces": [{
369
+ "Description": "Primary network interface",
370
+ "DeviceIndex": 0,
371
+ "DeleteOnTermination": true,
372
+
373
+ "SubnetId": {"Ref": "PrivateSubnet"},
374
+ "GroupSet": [{"Ref": "BackendSecurityGroup"}]
375
+ }],
376
+
377
+ "UserData": {"Fn::Base64": {"Fn::Join": ["", [
378
+ "#!/bin/bash -e\n",
379
+ "export AWS_WAIT_HANDLE='", {"Ref": "InstanceBootstrapWaitHandle"}, "'\n",
380
+ <%= ja 8, userdata['backend'] %>
381
+ ]]}}
382
+ }},
383
+
384
+ "BackendSecurityGroup": {"Type": "AWS::EC2::SecurityGroup", "Properties": {
385
+ "GroupDescription": "Enable SSH access via port 22",
386
+ "VpcId": {"Ref": "VPC"},
387
+
388
+ "SecurityGroupIngress": [
389
+ {"IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": <%= j external_ssh_cidr %>},
390
+ {"IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": <%= j bastion_ssh_cidr %>},
391
+ {"IpProtocol": "tcp", "FromPort": "51607", "ToPort": "51607", "CidrIp": "10.100.0.0/24"}
392
+ ],
393
+ "SecurityGroupEgress": [
394
+ {"IpProtocol": "-1", "CidrIp": "0.0.0.0/0"}
395
+ ]
396
+ }
397
+ },
398
+
399
+ "BackendEIP": {"Type": "AWS::EC2::EIP", "Properties": {
400
+ "Domain": "VPC"
401
+ }},
402
+ "BackendEIPAssociation": {"Type": "AWS::EC2::EIPAssociation", "Properties": {
403
+ "AllocationId": {"Fn::GetAtt": ["BackendEIP", "AllocationId"]},
404
+ "InstanceId": {"Ref": "Backend"}
405
+ }},
406
+
407
+ "BackendEndpoint": {"Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": {
408
+ "Instances": [{"Ref": "Backend"}],
409
+ "Subnets": [{"Ref": "PrivateSubnet"}],
410
+ "SecurityGroups": [{"Ref": "BackendEndpointSecurityGroup"}],
411
+ "Scheme": "internal",
412
+
413
+ "HealthCheck": {
414
+ "HealthyThreshold": "5",
415
+ "Interval": "30",
416
+ "Target": "HTTP:80/v1/info",
417
+ "Timeout": "5",
418
+ "UnhealthyThreshold": "2"
419
+ },
420
+
421
+ "Listeners": [{
422
+ "LoadBalancerPort": "443",
423
+ "InstancePort": "80",
424
+ "Protocol": "SSL",
425
+ "InstanceProtocol": "TCP",
426
+ "SSLCertificateId": {"Fn::Join": ["", [
427
+ "arn:aws:iam::", {"Ref": "AWS::AccountId"}, ":server-certificate/",
428
+ <%= j backend_cert_path %>, ".pem"
429
+ ]]}
430
+ }]
431
+ }},
432
+
433
+ "BackendEndpointDNSRecord": {"Type": "AWS::Route53::RecordSet", "Properties": {
434
+ "HostedZoneId": <%= j hosted_zone %>,
435
+ "Type": "CNAME", "TTL": "300",
436
+ "Name": <%= j "api.admin.#{domain}." %>,
437
+ "ResourceRecords": [{"Fn::GetAtt": ["BackendEndpoint", "DNSName"]}]
438
+ }},
439
+
440
+ "BackendEndpointSecurityGroup": {"Type": "AWS::EC2::SecurityGroup", "Properties": {
441
+ "GroupDescription": "Backend ELB security group",
442
+ "VpcId": {"Ref": "VPC"},
443
+
444
+ "SecurityGroupIngress": [
445
+ {"IpProtocol": "tcp", "FromPort": "443", "ToPort": "443", "CidrIp": "10.100.0.0/24"}
446
+ ],
447
+ "SecurityGroupEgress": [
448
+ {"IpProtocol": "tcp", "FromPort": "80", "ToPort": "80", "CidrIp": "0.0.0.0/0"}
449
+ ]
450
+ }},
451
+
452
+ "BackendIngress": {"Type": "AWS::EC2::SecurityGroupIngress", "Properties": {
453
+ "GroupId": {"Ref": "BackendSecurityGroup"},
454
+ "SourceSecurityGroupId": {"Ref": "BackendEndpointSecurityGroup"},
455
+
456
+ "IpProtocol": "tcp", "FromPort": "80", "ToPort": "80"
457
+ }},
458
+
459
+
460
+
461
+
462
+
463
+
464
+ "OpenVPN": {"Type": "AWS::EC2::Instance", "Properties": {
465
+ "InstanceType": "m1.small",
466
+ "ImageId": <%= j ubuntu_daily_ami %>,
467
+ "AvailabilityZone": {"Fn::GetAtt": ["PublicSubnet", "AvailabilityZone"]},
468
+
469
+ "Tags": [
470
+ { "Key": "Name", "Value": "vpn01" },
471
+ { "Key": "Environment", "Value": <%= j environment %> }
472
+ ],
473
+
474
+ "KeyName": <%= j @stack.iam_keypair_name %>,
475
+
476
+ "NetworkInterfaces": [
477
+ {
478
+ "NetworkInterfaceId": {"Ref": "OpenVPNPublicInterface"},
479
+ "DeviceIndex": "0"
480
+ },
481
+ {
482
+ "Description": "Private network interface",
483
+ "DeviceIndex": "1",
484
+ "DeleteOnTermination": true,
485
+
486
+ "SubnetId": {"Ref": "PrivateSubnet"},
487
+ "GroupSet": [{"Ref": "OpenVPNSecurityGroup"}]
488
+ }
489
+ ],
490
+
491
+ "UserData": {"Fn::Base64": {"Fn::Join": ["", [
492
+ "#!/bin/bash -e\n",
493
+ "export AWS_WAIT_HANDLE='", {"Ref": "InstanceBootstrapWaitHandle"}, "'\n",
494
+ <%= ja 8, userdata['openvpn'] %>
495
+ ]]}}
496
+ }},
497
+
498
+ "OpenVPNPublicInterface": {"Type": "AWS::EC2::NetworkInterface", "Properties": {
499
+ "Description": "Public network interface",
500
+
501
+ "SubnetId": {"Ref": "PublicSubnet"},
502
+ "GroupSet": [{"Ref": "OpenVPNSecurityGroup"}]
503
+ }},
504
+
505
+ "OpenVPNEIP": {"Type": "AWS::EC2::EIP", "Properties": {
506
+ "Domain": "VPC"
507
+ }},
508
+
509
+ "OpenVPNEIPAssociation": {"Type": "AWS::EC2::EIPAssociation", "Properties": {
510
+ "AllocationId": {"Fn::GetAtt": ["OpenVPNEIP", "AllocationId"]},
511
+ "NetworkInterfaceId": {"Ref": "OpenVPNPublicInterface"}
512
+ }},
513
+
514
+ "OpenVPNDNSRecord": {"Type": "AWS::Route53::RecordSet", "DependsOn": "OpenVPNEIPAssociation", "Properties": {
515
+ "HostedZoneId": <%= j hosted_zone %>,
516
+ "Type": "CNAME", "TTL": "300",
517
+ "Name": <%= j "vpn.#{domain}." %>,
518
+ "ResourceRecords": [{"Fn::GetAtt": ["OpenVPN", "PublicDnsName"]}]
519
+ }},
520
+
521
+ "OpenVPNSecurityGroup": {"Type": "AWS::EC2::SecurityGroup", "Properties": {
522
+ "GroupDescription": "Enable everything",
523
+ "VpcId": {"Ref": "VPC"},
524
+
525
+ "SecurityGroupIngress": [
526
+ {"IpProtocol": "tcp", "FromPort": "443", "ToPort": "443", "CidrIp": "0.0.0.0/0"},
527
+ {"IpProtocol": "udp", "FromPort": "1192", "ToPort": "1194", "CidrIp": "0.0.0.0/0"},
528
+ {"IpProtocol": "tcp", "FromPort": "943", "ToPort": "943", "CidrIp": "0.0.0.0/0"},
529
+ {"IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": "0.0.0.0/0"}
530
+ ]
531
+ }}
532
+
533
+ }
534
+ }