terrafying-components 1.4.3 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c445377d251318c7c321d2482081a0fea5d79e47fb09534a584e0560569495d8
4
- data.tar.gz: 156972b6c25200b5b0bfc9721e7fe179230a8e61745c39ca0f9c70ced7b879c5
3
+ metadata.gz: 3577f779cfb8aaaefa37ed0ad43635a37ae154cb34dbc0a6442177dd2abc1786
4
+ data.tar.gz: 1ed1adf2f61d82697438d1338b99276405d04c6688f84047a297a6ae4bdf8a5e
5
5
  SHA512:
6
- metadata.gz: 9802e7383383368c37b2df829ee2e79bc34470caab1eabbd447a48a8473d2b8306d9b2d577b39e1559e3fae9bb7a479d144b68a11739de6e50c9323a23292458
7
- data.tar.gz: 3866dc90d8e9a0cdf6e5fba8633e76710dd356efd14e4c2a6b50ca8cf3cc57eb57aeab453c0d9d40b3afd3035c74ec02d3c8453bd937012c1facd0619bb1cfae
6
+ metadata.gz: 9b23eba0da42b8a9bfa34251c545699f8468bb14d16392ae271f032fec6d01399995a8aeef66c52ae58a3f84a2e080e67d2ad46dd38c22445631539681d21bcc
7
+ data.tar.gz: 3715ab338a9947a5c0697a41011a74b3f91335da4b68148498fd9a0a118457c8d1f15290b4cffbe6285191ebb0f2b4a73f3b88dbc85377eba4173cf10a1740d2
@@ -0,0 +1,7 @@
1
+ class ::Hash
2
+ def merge_with_arrays_merged(newhash)
3
+ merge(newhash) do |_key, oldval, newval|
4
+ oldval.is_a?(Array) ? oldval | Array(newval) : newval
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+
2
+ require 'terrafying/components/endpoint'
3
+ require 'terrafying/components/endpointservice'
4
+ require 'terrafying/components/selfsignedca'
5
+ require 'terrafying/components/letsencrypt'
6
+ require 'terrafying/components/service'
7
+ require 'terrafying/components/subnet'
8
+ require 'terrafying/components/vpc'
9
+ require 'terrafying/components/vpn'
10
+ require 'terrafying/components/zone'
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Terrafying
4
+ module Components
5
+ class Auditd
6
+ def self.fluentd_conf(role, tags = [])
7
+ new.fluentd_conf(role, tags)
8
+ end
9
+
10
+ def fluentd_conf(role, tags)
11
+ tags = default_tags.merge(
12
+ custom_tags(tags)
13
+ )
14
+
15
+ {
16
+ files: [
17
+ systemd_input,
18
+ ec2_filter(tags),
19
+ s3_output(role)
20
+ ],
21
+ iam_policy_statements: [
22
+ allow_describe_instances,
23
+ allow_assume(role)
24
+ ]
25
+ }
26
+ end
27
+
28
+ def custom_tags(tags)
29
+ tags.map { |t| [t, wrap_tag(t)] }.to_h
30
+ end
31
+
32
+ def wrap_tag(t)
33
+ t = "tagset_#{t}" unless t.start_with? 'tagset_'
34
+ t.downcase
35
+ end
36
+
37
+ def default_tags
38
+ {
39
+ name: 'tagset_name',
40
+ instance_id: 'instance_id',
41
+ instance_type: 'instance_type',
42
+ private_ip: 'private_ip',
43
+ az: 'availability_zone',
44
+ vpc_id: 'vpc_id',
45
+ ami_id: 'image_id',
46
+ account_id: 'account_id'
47
+ }
48
+ end
49
+
50
+ def allow_describe_instances
51
+ {
52
+ Effect: 'Allow',
53
+ Action: %w[ec2:DescribeInstances ec2:DescribeTags ec2:DescribeRouteTables],
54
+ Resource: ['*']
55
+ }
56
+ end
57
+
58
+ def allow_assume(role)
59
+ {
60
+ Effect: 'Allow',
61
+ Action: ['sts:AssumeRole'],
62
+ Resource: [role]
63
+ }
64
+ end
65
+
66
+ def file_of(name, content)
67
+ {
68
+ path: "/etc/fluentd/conf.d/#{name}.conf",
69
+ mode: 0o644,
70
+ contents: content
71
+ }
72
+ end
73
+
74
+ def systemd_input
75
+ file_of(
76
+ '10_auditd_input_systemd',
77
+ <<~'SYSTEMD_INPUT'
78
+ <source>
79
+ @type systemd
80
+ tag auditd
81
+ filters [{ "_TRANSPORT": "audit" }, { "_COMM": "sshd" }]
82
+ path /fluentd/log/journal
83
+ read_from_head false
84
+ <storage>
85
+ @type local
86
+ persistent false
87
+ path /fluentd/var/audit.pos
88
+ </storage>
89
+ <entry>
90
+ field_map {
91
+ "MESSAGE": "log",
92
+ "_PID": ["process", "pid"],
93
+ "_CMDLINE": "process",
94
+ "_COMM": "cmd",
95
+ "_AUDIT_SESSION": "audit_session",
96
+ "_AUDIT_LOGINUID": "audit_loginuid"
97
+ }
98
+ fields_strip_underscores true
99
+ fields_lowercase true
100
+ </entry>
101
+ </source>
102
+ SYSTEMD_INPUT
103
+ )
104
+ end
105
+
106
+ def ec2_filter(tags)
107
+ file_of(
108
+ '20_auditd_filter_ec2',
109
+ <<~EC2_FILTER
110
+ <filter auditd>
111
+ @type ec2_metadata
112
+ metadata_refresh_seconds 300
113
+ <record>
114
+ #{map_tags(tags)}
115
+ </record>
116
+ </filter>
117
+ EC2_FILTER
118
+ )
119
+ end
120
+
121
+ def map_tags(tags)
122
+ tags.map { |k, v| "#{k} ${#{v}}" }
123
+ .reduce { |out, e| +out << "\n #{e}" }
124
+ end
125
+
126
+ def s3_output(audit_role)
127
+ file_of(
128
+ '30_auditd_output_s3',
129
+ <<~S3_OUTPUT
130
+ <match auditd>
131
+ @type s3
132
+ <assume_role_credentials>
133
+ role_arn #{audit_role}
134
+ role_session_name "auditd-logging-\#{Socket.gethostname}"
135
+ </assume_role_credentials>
136
+ auto_create_bucket false
137
+ s3_bucket uswitch-auditd-logs
138
+ s3_region eu-west-1
139
+ acl bucket-owner-full-control
140
+ path auditd/%Y/%m/%d/
141
+ s3_object_key_format "\%{path}\%{time_slice}_\#{Socket.gethostname}.\%{file_extension}"
142
+ <buffer time>
143
+ @type file
144
+ path /fluent/var/s3
145
+ timekey 300 # 5 minute partitions
146
+ timekey_wait 0s
147
+ timekey_use_utc true
148
+ </buffer>
149
+ <format>
150
+ @type json
151
+ </format>
152
+ </match>
153
+ S3_OUTPUT
154
+ )
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,55 @@
1
+
2
+ module Terrafying
3
+
4
+ module Components
5
+
6
+ module CA
7
+
8
+ def create_keypair(name, options={})
9
+ create_keypair_in(self, name, options)
10
+ end
11
+
12
+ def reference_keypair(ctx, name)
13
+ key_ident = "#{@name}-#{tf_safe(name)}"
14
+
15
+ ref = {
16
+ name: name,
17
+ ca: self,
18
+ source: {
19
+ cert: File.join("s3://", @bucket, @prefix, @name, name, "cert"),
20
+ key: File.join("s3://", @bucket, @prefix, @name, name, "key"),
21
+ },
22
+ resources: [
23
+ "aws_s3_bucket_object.#{key_ident}-key",
24
+ "aws_s3_bucket_object.#{key_ident}-cert"
25
+ ],
26
+ iam_statement: {
27
+ Effect: "Allow",
28
+ Action: [
29
+ "s3:GetObjectAcl",
30
+ "s3:GetObject",
31
+ ],
32
+ Resource: [
33
+ "arn:aws:s3:::#{File.join(@bucket, @prefix, @name, "ca.cert")}",
34
+ "arn:aws:s3:::#{File.join(@bucket, @prefix, @name, name, "cert")}",
35
+ "arn:aws:s3:::#{File.join(@bucket, @prefix, @name, name, "key")}",
36
+ ]
37
+ }
38
+ }
39
+
40
+ if self == ctx
41
+ ref[:resources] << "aws_s3_bucket_object.#{@name}-cert"
42
+ end
43
+
44
+ ref
45
+ end
46
+
47
+ def <=>(other)
48
+ @name <=> other.name
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,229 @@
1
+
2
+ require 'terrafying/components/usable'
3
+
4
+ require_relative './ports'
5
+
6
+ module Terrafying
7
+
8
+ module Components
9
+
10
+ class DynamicSet < Terrafying::Context
11
+
12
+ attr_reader :name, :asg
13
+
14
+ include Usable
15
+
16
+ def self.create_in(vpc, name, options={})
17
+ DynamicSet.new.create_in vpc, name, options
18
+ end
19
+
20
+ def self.find_in(vpc, name)
21
+ DynamicSet.new.find_in vpc, name
22
+ end
23
+
24
+ def initialize()
25
+ super
26
+ end
27
+
28
+ def find_in(vpc, name)
29
+ @name = "#{vpc.name}-#{name}"
30
+
31
+ self
32
+ end
33
+
34
+ def create_in(vpc, name, options={})
35
+ options = {
36
+ public: false,
37
+ ami: aws.ami("base-image-59a5b709", owners=["136393635417"]),
38
+ instance_type: "t2.micro",
39
+ instances: { min: 1, max: 1, desired: 1, tags: {} },
40
+ ports: [],
41
+ instance_profile: nil,
42
+ security_groups: [],
43
+ tags: {},
44
+ ssh_group: vpc.ssh_group,
45
+ subnets: vpc.subnets.fetch(:private, []),
46
+ depends_on: [],
47
+ rolling_update: :simple,
48
+ }.merge(options)
49
+
50
+ ident = "#{tf_safe(vpc.name)}-#{name}"
51
+
52
+ @name = ident
53
+ @ports = enrich_ports(options[:ports])
54
+
55
+ @security_group = resource :aws_security_group, ident, {
56
+ name: "dynamicset-#{ident}",
57
+ description: "Describe the ingress and egress of the service #{ident}",
58
+ tags: options[:tags],
59
+ vpc_id: vpc.id,
60
+ egress: [
61
+ {
62
+ from_port: 0,
63
+ to_port: 0,
64
+ protocol: -1,
65
+ cidr_blocks: ["0.0.0.0/0"],
66
+ }
67
+ ],
68
+ }
69
+
70
+ path_mtu_setup!
71
+
72
+ launch_config = resource :aws_launch_configuration, ident, {
73
+ name_prefix: "#{ident}-",
74
+ image_id: options[:ami],
75
+ instance_type: options[:instance_type],
76
+ user_data: options[:user_data],
77
+ iam_instance_profile: options[:instance_profile] && options[:instance_profile].id,
78
+ associate_public_ip_address: options[:public],
79
+ root_block_device: {
80
+ volume_type: 'gp2',
81
+ volume_size: 32,
82
+ },
83
+ security_groups: [
84
+ vpc.internal_ssh_security_group,
85
+ @security_group,
86
+ ].push(*options[:security_groups]),
87
+ lifecycle: {
88
+ create_before_destroy: true,
89
+ },
90
+ depends_on: options[:instance_profile] ? options[:instance_profile].resource_names : [],
91
+ }
92
+
93
+ if options[:instances][:track]
94
+ instances = instances_by_tags(Name: ident)
95
+ if instances
96
+ options[:instances] = options[:instances].merge(instances)
97
+ end
98
+ end
99
+
100
+ if options.has_key?(:health_check)
101
+ raise 'Health check needs a type and grace_period' if ! options[:health_check].has_key?(:type) and ! options[:health_check].has_key?(:grace_period)
102
+ else
103
+ options = {
104
+ health_check: {
105
+ type: "EC2",
106
+ grace_period: 0
107
+ },
108
+ }.merge(options)
109
+ end
110
+ tags = { Name: ident, service_name: name,}.merge(options[:tags]).merge(options[:instances][:tags]).map { |k,v| { Key: k, Value: v, PropagateAtLaunch: true }}
111
+
112
+ asg = resource :aws_cloudformation_stack, ident, {
113
+ name: ident,
114
+ disable_rollback: true,
115
+ template_body: generate_template(
116
+ options[:health_check], options[:instances], launch_config,
117
+ options[:subnets].map(&:id), tags, options[:rolling_update]
118
+ ),
119
+ }
120
+
121
+ @asg = output_of(:aws_cloudformation_stack, ident, 'outputs["AsgName"]')
122
+
123
+ self
124
+ end
125
+
126
+ def attach_load_balancer(load_balancer)
127
+ load_balancer.target_groups.each.with_index { |target_group, i|
128
+ resource :aws_autoscaling_attachment, "#{load_balancer.name}-#{@name}-#{i}", {
129
+ autoscaling_group_name: @asg,
130
+ alb_target_group_arn: target_group
131
+ }
132
+ }
133
+
134
+ self.used_by(load_balancer) if load_balancer.type == "application"
135
+ end
136
+
137
+ def generate_template(health_check, instances, launch_config, subnets,tags, rolling_update)
138
+ template = {
139
+ Resources: {
140
+ AutoScalingGroup: {
141
+ Type: "AWS::AutoScaling::AutoScalingGroup",
142
+ Properties: {
143
+ Cooldown: "300",
144
+ HealthCheckType: "#{health_check[:type]}",
145
+ HealthCheckGracePeriod: health_check[:grace_period],
146
+ LaunchConfigurationName: "#{launch_config}",
147
+ MaxSize: "#{instances[:max]}",
148
+ MetricsCollection: [
149
+ {
150
+ Granularity: "1Minute",
151
+ Metrics: [
152
+ "GroupMinSize",
153
+ "GroupMaxSize",
154
+ "GroupDesiredCapacity",
155
+ "GroupInServiceInstances",
156
+ "GroupPendingInstances",
157
+ "GroupStandbyInstances",
158
+ "GroupTerminatingInstances",
159
+ "GroupTotalInstances"
160
+ ]
161
+ },
162
+ ],
163
+ MinSize: "#{instances[:min]}",
164
+ DesiredCapacity: "#{instances[:desired]}",
165
+ Tags: tags,
166
+ TerminationPolicies: [
167
+ "Default"
168
+ ],
169
+ VPCZoneIdentifier: subnets
170
+ }
171
+ }
172
+ },
173
+ Outputs: {
174
+ AsgName: {
175
+ Description: "The name of the auto scaling group",
176
+ Value: {
177
+ Ref: "AutoScalingGroup",
178
+ },
179
+ },
180
+ },
181
+ }
182
+
183
+ if rolling_update == :signal
184
+ template[:Resources][:AutoScalingGroup][:UpdatePolicy] = {
185
+ AutoScalingRollingUpdate: {
186
+ MinInstancesInService: "#{instances[:desired]}",
187
+ MaxBatchSize: "#{instances[:desired]}",
188
+ PauseTime: "PT10M",
189
+ WaitOnResourceSignals: true,
190
+ }
191
+ }
192
+ elsif rolling_update
193
+ template[:Resources][:AutoScalingGroup][:UpdatePolicy] = {
194
+ AutoScalingRollingUpdate: {
195
+ MinInstancesInService: "#{instances[:min]}",
196
+ MaxBatchSize: "1",
197
+ PauseTime: "PT0S"
198
+ }
199
+ }
200
+ end
201
+
202
+ JSON.pretty_generate(template)
203
+ end
204
+
205
+ def instances_by_tags(tags = {})
206
+ begin
207
+ asgs = aws.asgs_by_tags(tags)
208
+
209
+ if asgs.count != 1
210
+ raise "Didn't find only one ASG :("
211
+ end
212
+
213
+ instances = {
214
+ min: asgs[0].min_size,
215
+ max: asgs[0].max_size,
216
+ desired: asgs[0].desired_capacity,
217
+ }
218
+ rescue RuntimeError => err
219
+ $stderr.puts("instances_by_tags: #{err}")
220
+ instances = nil
221
+ end
222
+
223
+ instances
224
+ end
225
+ end
226
+
227
+ end
228
+
229
+ end